Reduciendo la complejidad ciclomática en PHP
Recientemente he estado rescatando cosas y leyendo cosas nuevas de PHP y poniéndome al día. PHP es un lenguaje que ya ha superado su lastre de ser un lenguaje confuso y «de pobres» y exclusivamente para crear webs cutrecillas. Por mencionar dos proyectazos que dan soporte a un enorme porcentaje de sitios: WordPress y Drupal.
Un excelente comienzo si te quieres modernizar y empezar a aplicar las mejores prácticas de PHP es https://phptherightway.com/. Se trata de un libro en constante evolución que puedes leer de forma gratuita y también puedes comprar al autor en formato eBook.
He estado retomando mi proyecto (framework Slim 3) para la web https://puestosdetrabajofuncionarios.nom.es/ para ver si podía ponerlo al día con las mejores prácticas y en concreto me ha parecido muy interesante el uso de PHP Mess Detector https://phpmd.org/. Le damos caña:
Nos fijamos en el primer resultado.
La complejidad ciclomática de McCabe es una métrica de la calidad del software. Es una técnica de análisis estático que orienta sobre la dificultad de crear pruebas automatizadas del mismo. Se trata de averiguar el número de caminos independientes dentro del código y por tanto dar una cota superior del número de pruebas que se deberían realizar para asegurar que cada línea se ejecuta al menos una vez. Definido en PHPMd: https://phpmd.org/rules/codesize.html#cyclomaticcomplexity.
Que la CC sea alta no significa, ni mucho menos, que el código no sea correcto. Solo indica que es costoso de probar exhaustivamente y por tanto costoso de mantener. Lo ideal es tener menos caminos independientes de ejecución. Veamos al culpable:
Este código estima los salarios en función del grupo. Los grupos de funcionarios pueden ser A1, A2, C1, C2, E, o una combinación de ellos (ej. A1A2). Por tanto cuando son grupos compuestos tengo que sacar los dos (el del A1 y el del A2).
A veces se deja funcionando un código correcto que no es el más óptimo. A veces sabes que no es el más óptimo (y por limitaciones de tiempo, lo dejas para hacer otra cosa) pero otras veces ni lo sabes, y ahí es donde entran en juego las herramientas de análisis estático de código.
Me dice que la complejidad ciclomática es 10, que está justo en el umbral permitido. Si lo repensamos un poco podemos llegar a la siguiente versión:
Este código es funcionalmente equivalente al anterior pero mucho más sencillo y fácil de probar. En la versión anterior había cometido el error de usar el valor para el grupo tal y como viene, de ahí la excesiva repetición de código (por ejemplo estoy calculando el salario de C1 en más de un sitio). Lo que debo hacer es extraer conocimiento del valor de $grupo
y actuar en consecuencia: «Si es A1A2, es A1 y también es A2», por tanto entrará por los condicionales primero y segundo. Veamos que nos dice PHP Mess Detector:
Efectivamente el problema que estábamos tratando ha desaparecido y me quedan dos. Ahora tengo un método más sencillo de comprender y modificar, más fácil de probar y más eficiente de paso.
Los conjuntos de reglas cleancode
y codesize
son solo dos de los posibles con esta herramienta:
Código limpio | cleancode | Limpieza de código en general |
Tamaño de código | codesize | Busca fragmentos de código largos o complejos |
Controvertidos | controversial | Comprueba buenas y malas prácticas donde pueda haber controversia o diferencias de opinión |
Diseño | design | Ayuda a encontrar problemas de diseño |
Nombrado | naming | Evita nombres demasiado cortos o demasiado largos |
Código sin uso | unusedcode | Detecta código sin uso que se puede borrar |
Estas herramientas de análisis estático están muy bien para irlas aplicando sin obsesionarse, aumentando poco a poco el conjunto de reglas. Te ayudarán a tener un proyecto más limpio, eficiente y fácil de mantener. A veces creemos que lo vemos todo, pero hay problemas que son anti-intuitivos que nos cuesta ver.
A veces se trata de hacer algo tan sencillo como dividir métodos monstruosos en partes más pequeñas. Aunque así parezca que estamos tratando de eludir nuestra responsabilidad con el único objetivo de engañar al sistema de análisis, en realidad es justo lo que tenemos que hacer: tener módulos/funciones/métodos más pequeños y fáciles de probar por separado y con una responsabilidad muy delimitada. Volvamos a la primera captura y centrémonos en ValidatorBuscarPuesto
. Para el método validate
se queda de complejidad ciclomática alta y de complejidad Npath (https://phpmd.org/rules/codesize.html#npathcomplexity). El método validate
es demasiado grande:
… y unas 40 líneas más del mismo rollo. Pero cada validación de cada campo es una unidad independiente, este método se puede quedar así:
Y se definen aparte los procedimientos para validar cada campo. Ahora no tienes la misión de probar un gran monolito, tienes la misión de probar unidades más manejables y, si son correctas, el método compuesto debería ser correcto también. Veamos el resultado:
¡Misión cumplida! Por el momento…
Perpetrado el 11 de diciembre de 2022 por una IN (Inteligencia Natural), la mia, con cierto esfuerzo.
Archivado en categoría(s) PHP, Programación
Es genial ver cómo este lenguaje ha evolucionado y se ha alejado de su antiguo estereotipo, convirtiéndose en una herramienta poderosa y versátil para todo tipo de proyectos. Gracias por compartir tus recomendaciones y experiencia, definitivamente seguiré explorando y aplicando todo lo aprendido para seguir mejorando en mi propio trabajo con PHP. ¡Saludos!