visual-studio - tutorial - visual studio code extensions
Métricas de código de Visual Studio y el índice de Mantenibilidad de la caja del conmutador (7)
Dos cosas me vienen a la mente:
Usa una enumeración para unir la descripción y el valor
public enum FormFactor
{
Other = 1,
SIP = 2,
etc.
}
Usa una clase o estructura para representar cada factor de forma
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
}
}
Como una persona que ama seguir las mejores prácticas,
Si ejecuto métricas de código (haga clic con el botón derecho en el nombre del proyecto en el explorador de soluciones y seleccione "Calcular métricas de código" - Visual Studio 2010) en:
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;
}
Me da un índice de Mantenibilidad de 61
(por supuesto, esto es insignificante si solo tienes esto, pero si usas una utilidad como clase, cuya filosofía está haciendo cosas como esa, tu clase de utilidad tendrá el índice de mantenimiento mucho peor ...)
¿Cuál es la solución para esto?
Lo haría de esta manera y olvidaría el índice de Mantenibilidad:
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();
}
En mi humilde opinión, fácil de leer y fácil de cambiar.
No sé cuánto importa, pero el siguiente obtiene un 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];
}
Primero que nada: 61 se considera código mantenible. Para el Índice de Mantenibilidad, 100 es muy fácil de mantener el código, mientras que 0 es difícil de mantener.
- 0-9 = difícil de mantener
- 10-19 = moderado para mantener
- 20-100 = bueno para mantener
El Índice de Mantenibilidad se basa en tres métricas de código: a saber, Halstead Volumen, Cyclomatic Complexity y Lines of Code y basadas en la siguiente fórmula :
MAX (0, (171 - 5.2 * ln (Halstead Volume) - 0.23 * (Complejidad ciclomática) - 16.2 * ln (Líneas de código)) * 100/171)
De hecho, en su ejemplo, la causa raíz del bajo valor del Índice de Mantenibilidad es la Complejidad ciclomática. Esta métrica se calcula en función de las diversas rutas de ejecución en el código. Desafortunadamente, la métrica no se alinea necesariamente con la "legibilidad humana" del código.
Ejemplos como el resultado de su código en valores de índice muy bajos (recuerde, más bajo significa más difícil de mantener) pero de hecho son muy fáciles de leer. Esto es común al usar Cyclomatic Complexity para evaluar el código.
Imagine el código que tiene un bloque de interruptores por días (lunes a domingo) más un bloque de interruptores por meses (enero a diciembre). Este código será muy legible y mantenible, pero dará como resultado una enorme Complejidad Ciclomática y, por lo tanto, un Índice de Mantenibilidad muy bajo en Visual Studio 2010.
Este es un hecho bien conocido sobre la métrica y debe considerarse si el código se juzga en función de las cifras. En lugar de mirar el número absoluto, las cifras deben ser monitoreadas a lo largo del tiempo para entenderlas como un indicador del cambio del código. Por ejemplo, si el Índice de Mantenibilidad fue siempre de 100 y de repente bajó a 10, debe inspeccionar el cambio que causó esto.
El índice de mantenimiento podría ser mayor debido a la falta de capacidad de expansión en el método que elija para su solución.
La solución correcta (Mark Simpson mencionado anteriormente) es la que se puede expandir para usar un nuevo factor de forma sin reconstruir el código: las instrucciones de cambio / caso en el código son siempre una señal de que el diseño de OO ha sido olvidado y siempre debe verse como un mal código huele
Personalmente, implementaría ...
interface IFormFactor
{
// some methods
}
class SipFormFactor : IFormFactor...
class DipFormFactor : IFormFactor...
Etc.
... y que los métodos en la interfaz proporcionen la funcionalidad deseada; puedes pensar que [supongo] es similar en GoF Command Pattern.
De esta forma tus métodos de nivel superior pueden ser ...
MyMethod(IFormFactor factor)
{
// some logic...
factor.DoSomething();
// some more logic...
}
... y puede aparecer en una fecha posterior e introducir un nuevo factor de forma sin tener que cambiar este código como lo haría con la cláusula de cambio codificada. También encontrará que este enfoque también se presta fácilmente a TDD (debe terminar con esto si está haciendo TDD correctamente), ya que es fácil burlarse.
Claramente, para mí, el método Enum es el más fácil de mantener, ya que no involucra cadenas codificadas, por lo tanto, no hay problema de tipeo y verificación de sintaxis en tiempo de compilación. Solo las restricciones son reglas de denominación.
Sé que esta respuesta es muy tarde, pero me interesó que nadie pusiera la solución del diccionario todavía. Descubrí que cuando se trata de grandes declaraciones de conmutación que están orientadas a datos como esta, a menudo es más legible colapsar el conmutador en un diccionario.
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;
}
Esto le da un índice de Mantenibilidad de 74, un poco más bajo que la solución de matriz debido al acoplamiento de clase a un diccionario, pero creo que es más general porque funciona para cualquier cantidad de tipos que normalmente se enciende. Al igual que la solución de matriz, se escala muy bien y elimina una gran cantidad de código repetitivo.
En términos generales, el uso de un enfoque basado en datos puede ayudar a que su código sea más claro, ya que separa las piezas importantes (en este caso, una condición y un resultado) del cruft (en este caso, el switch-case).