Visual Studio代码指标和开关案例的可维护性索引
-
05-10-2019 - |
题
作为一个喜欢遵循最佳实践的人
如果我运行代码指标(右键单击解决方案资源管理器中的项目名称,然后选择“计算代码指标” - Visual Studio 2010)on:
public static string GetFormFactor(int number)
{
string formFactor = string.Empty;
switch (number)
{
case 1:
formFactor = "Other";
break;
case 2:
formFactor = "SIP";
break;
case 3:
formFactor = "DIP";
break;
case 4:
formFactor = "ZIP";
break;
case 5:
formFactor = "SOJ";
break;
}
return formFactor;
}
它给了我一个可维护性索引 61
(当然,如果您只有此功能,这是微不足道的,但是如果您使用像班级哲学这样的实用程序正在做类似的事情,那么您的公用事业课程将具有最差的可维护性索引。)
这是什么解决方案?
解决方案
首先:61被认为是可维护的代码。对于可维护性索引,100非常容易维护代码,而0很难维护。
- 0-9 =难以维护
- 10-19 =中度维护
- 20-100 =维护好
可维护性索引基于三个代码指标:即Halstead量,循环复杂性和代码线,并基于 以下公式:
max(0,(171-5.2 * ln(halstead卷)-0.23 *(循环复杂性)-16.2 * ln(代码行)) * 100/171)
实际上,在您的示例中,可维护性指数低值的根本原因是环形复杂性。该指标是根据代码中的各种执行路径计算的。不幸的是,该度量不一定与代码的“人类可读性”保持一致。
示例作为您的代码导致索引值非常低(请记住,较低意味着更难维护),但实际上它们很容易阅读。当使用循环复杂性评估代码时,这很常见。
想象一下代码,该代码在几天(周一)和几个月(Jan-dec)的开关块中有一个开关块。该代码将非常可读性和可维护性,但会导致巨大的循环复杂性,因此在Visual Studio 2010中的可维护性指数非常低。
这是关于指标的众所周知的事实,如果根据数字对代码进行判断,则应考虑。与其查看绝对数字,不如随着时间的推移监视这些数字作为更改代码的指标。例如,如果可维护性指数始终为100,并且突然下降到10,则应检查导致此的更改。
其他提示
由于您选择的解决方案的方法缺乏可扩展性,因此可维护性指数可能会更高。
正确的解决方案(Mark Simpson在上面涉及的Mark Simpson)是可以扩展的,以使用新的外形尺寸而不重建代码 - 代码中的Switch / Case语句始终表明OO设计已被遗忘,应始终看到作为不良的代码气味。
就个人而言,我将实施...
interface IFormFactor
{
// some methods
}
class SipFormFactor : IFormFactor...
class DipFormFactor : IFormFactor...
Etc.
...并且在接口上的方法提供了所需的功能 - 您可以认为[我想]与GOF命令模式相似。
这样,您的更高级别的方法就可以了...
MyMethod(IFormFactor factor)
{
// some logic...
factor.DoSomething();
// some more logic...
}
...您可以在以后出现,并引入一个新的外形,而无需像用硬编码的开关子句那样更改此代码。您还会发现这种方法还可以轻松地借给TDD(如果您正确地进行TDD,则应最终得到此方法),因为这很容易嘲笑。
我知道这个答案很晚,但是我很感兴趣,还没有人提出字典解决方案。我发现,在处理像这样的大型开关语句时,将开关案例折叠成词典通常更可读。
public static readonly IDictionary<int, string> Factors = new Dictionary<int, string> {
{ 1, "Other" },
{ 2, "SIP" },
{ 3, "DIP" },
{ 4, "ZIP" },
{ 5, "SOJ" }
};
public static string GetFormFactor2(int number)
{
string formFactor = string.Empty;
if (Factors.ContainsKey(number)) formFactor = Factors[number];
return formFactor;
}
由于类耦合到字典,这为您提供了比数组解决方案略低的74-可维护性索引,但我觉得它更一般,因为它适用于通常会打开的任何类型。像数组解决方案一样,它可以很好地缩放并删除了许多重复的代码。
一般而言,使用数据驱动的方法可以帮助您的代码更清晰,因为它将重要片段(在这种情况下为条件和结果)与Cruft(在这种情况下为Switch-case)分开。
脑子里有两件事:
使用枚举结婚的描述和价值
public enum FormFactor
{
Other = 1,
SIP = 2,
etc.
}
使用类或结构代表每个形式
public class FormFactor
{
public int Index { get; private set; }
public string Description { get; private set; }
public FormFactor(int index, string description)
{
// do validation and assign properties
}
}
我会这样做,而忘记了可维护性索引:
public static string GetFormFactor(int number)
{
switch (number)
{
case 1: return "Other";
case 2: return "SIP";
case 3: return "DIP";
case 4: return "ZIP";
case 5: return "SOJ";
}
return number.ToString();
}
以恕我直言,易于阅读,易于更改。
我不知道它有多少重要,但是以下是76:
private static string[] _formFactors = new[] { null, "Other","SIP","DIP", "ZIP", "SOJ"};
public static string GetFormFactor2(int number)
{
if (number < 1 || number > _formFactors.Length)
{
throw new ArgumentOutOfRangeException("number");
}
return _formFactors[number];
}
显然对我来说 枚举 方法是最可维护的,因为它不涉及硬编码字符串,因此没有错别字问题和编译时间语法检查。只有限制是命名规则。