Subido por Roy Carrington

Presentación 9. Medición de producto sofware

Anuncio
Clase 9:
Medición de
productos
software
Calidad de Software
Por: Ing. Belén Bonilla
Medición del producto
La medición del producto está centrada en
evaluar la calidad de los entregables.
Los productos del software son las salidas
del proceso de producción del software
que incluye todos los artefactos
entregados o documentos que son
producidos durante el ciclo de vida de
software.
Líneas de código (LOC): Es la métrica más popular a nivel de
código de programa. Es la suma de las líneas de código, sin
incluir las líneas que son comentarios o líneas en blanco.
Métricas a
nivel de
código
Para poder emplearla efectivamente, hay que determinar lo
que implica una línea de código en la evaluación.
En SonarQube: Número de líneas físicas que contienen al
menos un carácter que no es un espacio en blanco ni una
tabulación ni parte de un comentario.
Métricas a
nivel de
código
Líneas de código (LOC): De forma típica, los softwares con
más líneas de código poseen una complejidad más alta y son
más difíciles de mantener que aquellos con menos líneas de
código.
Líneas de comentario (CLOC): Número de líneas que
contienen comentarios o código comentado.
En SonarQube: Las líneas de comentario no significativas
(líneas de comentario vacías, líneas de comentario que
contienen sólo caracteres especiales, etc.) no aumentan el
número de líneas de comentario.
Métricas a
nivel de
código
Densidad de comentarios: Nos da idea de hasta cuánto está
documentado el código.
Métricas a
nivel de
código
𝐶𝐿𝑂𝐶
𝐷𝑒𝑛𝑠𝑖𝑑𝑎𝑑 𝑑𝑒 𝑐𝑜𝑚𝑒𝑛𝑡𝑎𝑟𝑖𝑜𝑠 =
×100%
𝐿𝑂𝐶 + 𝐶𝐿𝑂𝐶
• 50% significa que el número de líneas de código es igual al
número de líneas de comentarios.
• 100% significa que el archivo solo contiene líneas de
comentarios
Métricas a
nivel de
código
Complejidad ciclomática: Es una métrica cuantitativa que refleja
la complejidad del software. Una de las técnicas más reconocidas
para el cálculo de la complejidad ciclomática es la propuesta por
Thomas J. McCabe, y que se le conoce como “Complejidad
ciclomática de McCabe”.
Según McCabe, una complejidad ciclomática superior a 10 por lo
general indica que un algoritmo es complejo y con más
probabilidades de errores y más difícil de mantener y probar.
Por tanto la correlación es positiva: A mayor valor de la
complejidad ciclomática, mayor complejidad, mayor densidad de
errores, mayor esfuerzo de mantenimiento y pruebas.
Complejidad ciclomática en SonarQube: Es una medida del
número mínimo de caminos posibles a través del código y, por lo
tanto, el número de pruebas requeridas, ¡no se trata de la calidad
del código!
Métricas a
nivel de
código
La complejidad ciclomática es igual al número de puntos de
decisión + 1. Algunos puntos de decisión: if, while, do, for,?:,
catch, enunciados case y operadores && y ||…Se debe revisar
los criterios específicos por lenguaje para tener una lista
completa, según el caso.
Ver: https://docs.sonarqube.org/latest/user-guide/metricdefinitions/
Ejemplo…
Métricas a
nivel de
código
Complejidad ciclomática en SonarQube: Según la teoría pura,
el nivel 1-4 se considera fácil de probar, 5-7 OK, 8-10 considere
refactorizar para facilitar las pruebas y 11+ refactorice ahora, ya
que las pruebas serán tediosas.
Cuando se trata de la medición de la calidad del código mediante
esta métrica (no aconsejable, preferir complejidad cognitiva), el
nivel 10 es un nivel muy bueno como objetivo final. Se puede
tener un nivel de complejidad 15 o incluso superior, pero
manténgalo por debajo de 20 para detectar automáticamente el
código realmente mal diseñado.
Complejidad cognitiva de SonarQube: Es una medida que nos
permite aproximar qué tan difícil es entender el flujo de control del
código.
Métricas a
nivel de
código
La complejidad cognitiva se evalúa de acuerdo con tres reglas
básicas:
1. Ignorar las estructuras que permiten que varios enunciados
sean legibles abreviados en uno.
2. Incrementar (agregar uno) por cada ruptura en el flujo lineal del
código.
3. Incrementar cuando las estructuras que rompen el flujo están
anidadas.
Complejidad cognitiva de SonarQube
Se evalúan incrementos para:
Estructuras de bucle: for, foreach, while, do while
Métricas a
nivel de
código
Estructuras condicionales: operadores ternarios, if
Ambos tipos se evalúan con un incremento (+1) por la propia
estructura, más un incremento (+1) por cada nivel de anidación en el
que estén.
Para else if, else se evalúa +1 por la propia estructura. No se
evalúa ningún incremento de anidación para estas estructuras porque
el costo mental ya se “pagó” al leer el if.
Switch y todos sus case representan en total un incremento.
Complejidad cognitiva de SonarQube
Se evalúan incrementos para:
Métricas a
nivel de
código
Secuencia de operadores lógicos: la complejidad cognitiva no se
incrementa para cada operador lógico binario sino que evalúa un
incremento para cada secuencia de operadores lógicos binarios. Debido
a que las expresiones booleanas se vuelven más difíciles de entender
con operadores mixtos, la complejidad cognitiva aumenta para cada
nueva secuencia de operadores similares.
Ejemplo: if(a && b && c || d || e && f)
if (a
// +1 por el if
&& b && c
// +1
|| d || e
// +1
&& f)
// +1
Complejidad cognitiva de SonarQube
Se evalúan incrementos para:
Métricas a
nivel de
código
Catch: Un catch representa una especie de rama en el flujo de control
tanto como un if. Por lo tanto, cada cláusula de catch da como
resultado un incremento estructural de la complejidad cognitiva. Un
catch solo agrega un punto a la puntuación de complejidad cognitiva,
sin importar cuántos tipos de excepciones se detecten. Los bloques de
try y finally se ignoran por completo.
Saltos a labels: goto agrega un incremento a la complejidad cognitiva,
así como break o continue a un label (o número en algunos
lenguajes) (goto label, break label, continue label,
break number, continue number)
Entre otras reglas más que se pueden ampliar en:
https://www.sonarsource.com/docs/CognitiveComplexity.pdf
Métricas clásicas
a nivel de código
Complejidad cognitiva de SonarQube
Resumen de reglas
Hay un incremento por cada una de
estas estructuras:
Las siguientes estructuras
incrementan el nivel de
anidación
Las siguientes estructuras reciben un
incremento de anidación acorde con su
profundidad anidada dentro de las
estructuras indicadas en la segunda
columna
if, else if, else, operador
ternario, switch, for,
foreach, while, do while
catch, goto LABEL, break
LABEL, continue LABEL,
break NUMBER, continue
NUMBER, secuencias de operadores
lógicos, cada método en un ciclo de
recursión.
if, else if, else,
operador ternario,
switch, for,
foreach, while, do
while, catch
if, operador ternario, switch,
for, foreach, while, do
while, catch
Otras métricas de mantenibilidad
Cantidad de code smells:
Métricas a
nivel de
código
Los code smells son síntomas en el código que indican que tal
vez no se están haciendo las cosas de una forma del todo
correcta, lo que puede llevar a que haya algún problema a futuro
y un problema de trasfondo.
Un problema relacionado con la mantenibilidad en el código.
Dejarlo como está significa que, en el mejor de los casos, los
mantenedores tendrán más dificultades de lo que deberían para
realizar cambios en el código. En el peor de los casos, estarán
tan confundidos por el estado del código que introducirán errores
adicionales a medida que realicen cambios.
Otras métricas de mantenibilidad
Cantidad de code smells:
Son ejemplos de code smells:
Métricas a
nivel de
código
• Código duplicado
• Operador switch complejo o demasiadas sentencias if
• Métodos muy largos (más de 10 líneas de código)
• Muchos parámetros para un método (más de 3 ó 4)
• Demasiados comentarios
• Entre otros (Para más información, revisar:
https://refactoring.guru/es/refactoring/smells )
Otras métricas de mantenibilidad
Deuda técnica:
Métricas a
nivel de
código
Esfuerzo para corregir todos los code smells. En el caso de
SonarQube, la medida se almacena en minutos en la base de
datos y se asume un día de 8 horas cuando los valores se
muestran en días. Cada issue (un tipo de issue son los code
smells) tiene asociado un “remediation cost” (tiempo estimado
para reparar un issue, tiempo de reparación); esto podría ser 1 m,
5 m, 30 m, etc. La suma de todos estos costos de reparación
para los code smells (issues de mantenibilidad) para un proyecto,
es la deuda técnica.
Otras métricas de mantenibilidad
Proporción de deuda técnica:
Métricas a
nivel de
código
Relación entre el costo de desarrollar el software y el costo de
repararlo. La fórmula es:
𝐶𝑜𝑠𝑡𝑜 𝑑𝑒 𝑟𝑒𝑝𝑎𝑟𝑎𝑐𝑖ó𝑛
𝑃𝑟𝑜𝑝𝑜𝑟𝑐𝑖ó𝑛 𝑑𝑒 𝑑𝑒𝑢𝑑𝑎 𝑡é𝑐𝑛𝑖𝑐𝑎 =
𝐶𝑜𝑠𝑡𝑜 𝑑𝑒 𝑑𝑒𝑠𝑎𝑟𝑟𝑜𝑙𝑙𝑜
Que se puede reformular como:
𝑃𝑟𝑜𝑝𝑜𝑟𝑐𝑖ó𝑛 𝑑𝑒 𝑑𝑒𝑢𝑑𝑎 𝑡é𝑐𝑛𝑖𝑐𝑎 =
𝐶𝑜𝑠𝑡𝑜 𝑑𝑒 𝑟𝑒𝑝𝑎𝑟𝑎𝑐𝑖ó𝑛
𝐶𝑜𝑠𝑡𝑜 𝑑𝑒 𝑑𝑒𝑠𝑎𝑟𝑟𝑜𝑙𝑙𝑎𝑟 𝑢𝑛𝑎 𝑙í𝑛𝑒𝑎 𝑑𝑒 𝑐ó𝑑𝑖𝑔𝑜 ×𝑛ú𝑚𝑒𝑟𝑜 𝑑𝑒 𝑙í𝑛𝑒𝑎𝑠 𝑑𝑒 𝑐ó𝑑𝑖𝑔𝑜
El valor del costo para desarrollar una línea de código es de 0.06
días.
Paréntesis obligatorio
Métricas a
nivel de
código
Refactorización: El objetivo principal de la refactorización es
combatir la deuda técnica. Transforma un desorden en código
limpio y diseño simple.
Para cada code smell existe una o más técnicas de
refactorización que permitirán eliminarlo. Por ejemplo, los code
smells “Long method” y “Duplicate code” pueden eliminarse
empleando la técnica de refactorización “Extract method” en
conjunto con otras técnicas.
(Para más información:
https://refactoring.guru/es/refactoring/techniques )
Métricas a
nivel de
código
Algunas métricas de fiabilidad:
Número de bugs: Un bug es un error de codificación que
romperá el código y debe corregirse de inmediato.
En SonarQube es uno de los tres tipos de issues (en conjunto
con los code smells y las vulnerabilidades).
Métricas a
nivel de
código
Algunas métricas de fiabilidad:
Esfuerzo de reparación de fiabilidad: Esfuerzo para solucionar
todos los errores (bugs).
En SonarQube, la medida se almacena en minutos en la base de
datos. Se asume un día de 8 horas cuando los valores se
muestran en días.
Métricas
orientadas
a objetos a
nivel de
diseño
Existen varias propuestas como:
• Métricas MOOSE (las más utilizadas)
• Métricas MOOD
• Métricas de Lorenz y Kidd
Métricas
orientadas
a objetos a
nivel de
diseño
Métodos ponderados por clase (WMC, Weighted
Methods per Class): Considere una clase C1, con
métodos M1, M2, …, Mn que son definidos en la clase. Con
c1, c2, …,cn como la complejidad de los métodos, entonces:
?
𝑊𝑀𝐶 = % 𝑐<
<=>
Métodos ponderados por clase (WMC, Weighted
Methods per Class):
Métricas
orientadas
a objetos a
nivel de
diseño
• Es un predictor de cuánto tiempo y esfuerzo se requiere
para desarrollar y mantener una clase.
• Clases con un largo número de métodos pertenecen, con
mayor probabilidad, a aplicaciones específicas, limitando
la posibilidad de reutilización.
• A mayor cantidad de métodos en una clase, mayor el
impacto potencial en las clases hijas.
• A mayor complejidad entre todos los métodos de una
clase, mayor dificultad para la mantenibilidad.
La complejidad de los métodos se puede determinar con la
complejidad cognitiva.
Métricas
orientadas
a objetos a
nivel de
diseño
Profundidad del árbol de herencia de una clase (DIT,
Depth of Inheritance Tree): Mide el nivel máximo de
herencia a través de la longitud entre un nodo y el nodo
raíz en una jerarquía de clases. Es decir, es una medida de
cuántas clases ancestras pueden potencialmente afectar* a
una clase (la que está siendo evaluada).
En casos que involucran herencia múltiple, DIT será la
longitud máxima desde el nodo (clase evaluada) hasta el
nodo raíz.
* Debido a que cuanto mayor sea el nivel de profundidad de herencia de
una clase, mayor es el número de métodos y atributos que hereda de
otras clases.
Métricas
orientadas
a objetos a
nivel de
diseño
Ejemplo 1: La clase C hereda de la clase B, la cual hereda
de la clase A. Entonces:
DIT(A) = 0
DIT(B) = 1
DIT(C) = 2
Métricas
orientadas
a objetos a
nivel de
diseño
Ejemplo 2:
DIT(A) = 0
DIT(B) = DIT(C) = 1
DIT(D) = DIT(E) = 2
Métricas
orientadas
a objetos a
nivel de
diseño
Interpretación:
• Cuanto más profunda es una clase en la jerarquía de
clases, mayor el grado de herencia de métodos, haciendo
más complicado predecir su comportamiento (el de la clase
evaluada)
• Árboles más profundos constituyen mayor complejidad de
diseño, ya que más métodos y clases están involucrados.
• Cuanto más profunda es una clase en la jerarquía de
clases, mayor el potencial de reutilización de métodos
heredados.
Métricas
orientadas
a objetos a
nivel de
diseño
Interpretación: Es decir, un valor alto para la métrica DIT
indica que el nivel de complejidad es alto para esa clase. Esto
también significa que hay un alto número de atributos y
métodos que son heredados, lo cual indica que hay
reutilización de código a través de la herencia pero puede ser
más difícil entonces de predecir el comportamiento de la
clase.
Un valor menor para DIT indica menos complejidad pero
también significa que hay menos reutilización de código por
herencia.
La herencia es un concepto poderoso de la POO y los diseños
deben esforzarse por la reutilización de código. Por lo tanto,
debe alcanzarse un balance entre la reutilización de código y
la complejidad.
Métricas
orientadas
a objetos a
nivel de
diseño
Recomendación: Los valores ideales por convención son
entre 2 y 3.
Si para la mayoría de las clases, la métrica DIT está por
debajo de 2, esto nos indica una pobre explotación de las
ventajas del diseño orientado a objetos y la herencia.
Métricas
orientadas
a objetos a
nivel de
diseño
Número de hijos (NOC, Number of Children): Es el
número de clases inmediatas subordinadas a una clase en
la jerarquía, es decir, la cantidad de subclases que
pertenecen a una clase. NOC es una medida de cuántas
subclases van a heredar los métodos de una clase padre.
Interpretación:
Métricas
orientadas
a objetos a
nivel de
diseño
• A mayor número de hijos, mayor la reutilización, ya que
la herencia es una forma de reutilización.
• A mayor el número de hijos, mayor es la probabilidad de
una abstracción inapropiada de la clase padre. Si una
clase tiene muchos hijos, puede ser un caso de mal uso
de las subclases.
• El número de hijos da una idea de la influencia potencial
que tiene una clase en el diseño. Si una clase tiene un
muchos hijos, puede requerir más pruebas de los
métodos en esa clase (porque el impacto de un defecto
en el padre trascendería a los hijos).
Métricas
orientadas
a objetos a
nivel de
diseño
Interpretación: Entonces, NOC es un indicador de:
• El nivel de reutilización
• La posibilidad de haber creado abstracciones erróneas
• El nivel de pruebas requerido
Métricas
orientadas
a objetos a
nivel de
diseño
Recomendación:
Los valores ideales por lo regular, son entre 2 y 3 ya que se
suele aconsejar que se seleccionen los mismos valores
ideales (y también los límites) que en DIT.
Métricas
orientadas
a objetos a
nivel de
diseño
Ejemplo:
NOC(A) = NOC(B) = 2
NOC(C) = 1
NOC(D) = NOC(E) = 0
Métricas
orientadas
a objetos a
nivel de
diseño
Acoplamiento entre objetos (CBO, Coupling Between
Objects): CBO para una clase es el número total de otras
clases con las cuales se encuentra acoplada.
Recordemos que dos clases están acopladas cuando
métodos declarados en una clase usan métodos o instancian
(o acceden a) variables definidas por la otra clase.
Si una clase A usa una clase B, se dice que A depende de B.
Esto es, A no puede realizar su trabajo sin B, por lo tanto,
existe acoplamiento entre las clases A y B.
Interpretación:
Métricas
orientadas
a objetos a
nivel de
diseño
• Acoplamiento excesivo entre clases perjudica el diseño
modular y previene la reutilización. Entre más independiente
una clase es, más fácil será reutilizarla en otra aplicación.
• Con miras a incrementar la modularidad y promover la
encapsulación, el acoplamiento entre clases debe
mantenerse al mínimo. A mayor número de acoplamiento,
más sensitivo será realizar cambios en otras partes del
diseño, y por lo tanto el mantenimiento es más difícil.
• Una medida del acoplamiento es útil para determinar cuán
complejo probablemente será realizar las pruebas a varias
partes del diseño. A mayor acoplamiento entre clases, más
rigurosas deben ser las pruebas y más serían más difíciles
de realizar.
Entonces es una métrica útil para predecir esfuerzo necesario
en mantenimiento y pruebas.
Métricas
orientadas
a objetos a
nivel de
diseño
Recomendación:
Un valor de 0 indica que una clase no tiene relación con
ninguna otra clase en el sistema y, por lo tanto, no debe ser
parte del diseño.
Un valor entre 1 y 4 es bueno, ya que indica que la clase está
débilmente acoplada.
Un número más alto que esto puede indicar que la clase está
demasiado acoplada con otras clases en el diseño, lo que
complicaría las pruebas y modificaciones, y limitaría las
posibilidades de reutilización.
Métricas
orientadas
a objetos a
nivel de
diseño
Ejemplo 1:
CBO(Cuenta) = 0
CBO(Cliente) = 2
CBO(TarjetaCredito) = 2
CBO(AutorizacionTarjeta) = 0
Enfoque de Abreu y Melo, 1996
Métricas
orientadas
a objetos a
nivel de
diseño
Ejemplo 2:
CBO(A) = 2
CBO(B) = 2
CBO(C) = 0
CBO(D) = 1
CBO(E) = 0
Enfoque de Abreu y Melo, 1996
Métricas orientadas
a objetos a nivel de
diseño
CBO(Professor) = 2
Proporción de acomplamiento entre clases (CF):
Métricas
orientadas
a objetos a
nivel de
diseño
CF se define como la proporción entre el máximo número
posible de acoplamientos en el sistema y el número real de
acoplamientos no imputables a herencia.
𝑪𝑭 =
𝑻𝑪
∑𝑻𝑪
∑
𝒊"𝟏 𝒋"𝟏 𝒆𝒔_𝒄𝒍𝒊𝒆𝒏𝒕𝒆(𝒄𝒊 , 𝒄𝒋 )
𝑻𝑪𝟐 − 𝑻𝑪
Donde:
TC = número de clases
La relación cliente-proveedor (𝐶! ⇒ 𝐶" ) representa que la clase
cliente (𝐶! ) contiene al menos una referencia no heredada de
la clase proveedor (𝐶" ).
Descargar