2010-05-29 14 views
10

Como una persona que le gusta seguir las mejores prácticas,Visual Studio Código Métrica y el índice de mantenibilidad de la caja del interruptor

Si corro métricas de código (clic derecho sobre el nombre del proyecto en el explorador de soluciones y seleccione "Código de calcular métricas" - 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

(por supuesto, esto es insignificante si tiene sólo esto, pero si se utiliza una utilidad como philos whos clase Ophy está haciendo cosas así, su clase de utilidad tendrá el índice de mantenimiento mucho peor ...)

¿Cuál es la solución para esto?

Respuesta

26

En primer lugar: 61 se considera código de mantenimiento. 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 = moderada para mantener
  • 20-100 = bueno para mantener

El Índice de Capacidad de mantenimiento se basa en tres métricas de código: A saber Halstead el Volumen, la complejidad ciclomática y líneas de código y en base a la following formula:

MAX (0, (171 - los 5.2 * ln (Halstead Volumen) - 0,23 * (Ciclomática Complejidad) - 16,2 * ln (Líneas de Código)) * 100/171)

De hecho, en su ejemplo la causa raíz para el bajo valor del Índice de Capacidad de mantenimiento 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-diciembre). Este código será muy legible y mantenible, pero dará lugar a una enorme Complejidad Cyclomatic y, por lo tanto, en un Índice de Mantenibilidad muy bajo en Visual Studio 2010.

Este es un hecho bien conocido sobre la métrica y debe considerarse si se juzga el código basado en las figuras. 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. P.ej. si el Índice de Mantenibilidad estaba siempre en 100 y de repente bajó a 10, debería inspeccionar el cambio que causó esto.

+0

Nota: El índice se basa en _average_ HV, CC y LOC. Para un análisis más detallado del Índice de Mantenibilidad, los coeficientes, los umbrales y su historial, vea mi publicación en el blog "[Piénselo dos veces antes de usar el Índice de Mantenibilidad] (http://avandeursen.com/2014/08/29/think- dos veces antes de usar el índice de mantenimiento /) ". – avandeursen

2

Dos cosas vienen a la mente:

Usar una enumeración para casarse con la descripción y el valor

public enum FormFactor 
{ 
    Other = 1, 
    SIP = 2, 
    etc. 
} 

utilizar 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 
    } 
} 
+0

hmm, estoy en dificultades para comprender su solución. ¿Podrías por favor ser un poco más específico? Un ejemplo más detallado? Saludos – pee2002

0

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]; 
} 
+0

Sí, es una solución, pero no muy elegante: P estaba pensando en una forma estructural de hacer esto. ¿Algunas ideas? – pee2002

2

lo haría de esta manera y olvidar el índice de mantenimiento:

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(); 
} 

mi humilde opinión, fácil de leer y fácil de cambiar.

+0

Eso es lo que hice ...Pero realmente quiero saber si hay otra solución – pee2002

+0

Creo que los métodos array y enum mencionados a continuación son menos legibles y menos fáciles de mantener. –

0

Es evidente que para mí el métodoEnum es el más fácil de mantener, ya que no se trata de cadenas codificadas de forma rígida por lo tanto no hay problema error tipográfico y en tiempo de compilación comprobación de sintaxis. Las únicas restricciones son las reglas de denominación.

5

El índice de mantenimiento podría ser mayor debido a la falta de capacidad de ampliación en el método que elija para su solución.

La solución correcta (Mark Simpson mencionado anteriormente) es la que se puede ampliar 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 OO ha sido olvidado y siempre debe verse como un mal olor de código.

Personalmente, me gustaría poner en práctica ...

interface IFormFactor 
{ 
    // some methods 
} 

class SipFormFactor : IFormFactor... 

class DipFormFactor : IFormFactor... 

Etc. 

... y tienen los métodos de la interfaz de proporcionar la funcionalidad deseada - se puede pensar en él [supongo] como algo similar a GoF Comando Patrón.

De esta manera sus métodos de nivel superior sólo puede ser ...

MyMethod(IFormFactor factor) 
{ 
    // some logic... 

    factor.DoSomething(); 

    // some more logic... 
} 

... y usted puede venir en una fecha posterior e introducir un nuevo factor de forma sin tener que cambiar el 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.

3

Sé que esta respuesta es muy tarde, pero me interesaba 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 del 74 - ligeramente inferior a la solución de matriz debido acoplamiento clase a un diccionario, pero creo que es más general, ya que funciona para cualquier número 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 general, utilizar un enfoque basado en datos puede ayudar a que su código sea más claro, porque separa las piezas importantes (en este caso, una condición y un resultado) del cruft (en este caso, el switch-case)

Cuestiones relacionadas