Escuché una expresión tal que para convertirte en programador, debes ser flojo. Pero a veces la pereza en la programación conduce a una terrible deuda técnica. En mi artículo sobre SRP, mencioné que violar este principio puede conducir a un aumento de la complejidad o incluso a la multiplicación de este. Uno de mis colegas produjo un ejemplo interesante, y con mi ayuda decidí demostrar cómo se ve.

Decidamos cuál es esta complejidad excesiva. Pero primero, hablemos de su opuesto, de la complejidad de los requisitos. Por ejemplo, hay requisitos para calcular el salario del empleado a partir de la tarifa por hora y las horas trabajadas. Y si un empleado ha estado trabajando en la empresa durante más de cinco años, acumule un bono. Este "si" proviene de los requisitos, y no se puede evitar. De una forma u otra, se convertirá en un elemento de complejidad en el código de la aplicación, muy probablemente en la forma de un operador condicional "si". Pero a veces la complejidad no procede de los requisitos, sino que se deriva del enfoque del desarrollador para resolver el problema.
El operador "si", los patrones como "estrategia", los métodos polimórficos no son una lista completa de las técnicas de programación que pueden contener esta complejidad excesiva. Personalmente, yo, por cierto, siempre estoy en contra del uso de patrones por parte de los desarrolladores simplemente porque pueden hacerlo y no para resolver un problema específico.
Aquí hay un ejemplo simple. Puede parecer ficticio, pero no lo es. Ni siquiera está simplificado, fue de esta forma que lo conocí durante una revisión de código hace un par de años. En dos lugares del código hubo llamadas a la misma función pero con un parámetro booleano diferente:
Los diseños similares siempre parecen sospechosos y esta función no me decepcionó. Este parámetro se pasó con el único propósito de ser verificado dentro de esta función:
doSomething(flag: boolean): void { if(flag) {
Esta verificación se puede describir como "si me llamaron desde el lugar A, hacemos una cosa; de lo contrario, me llamaron desde el lugar B, hacemos otra cosa". Esta bandera, este "si" es de lo que trata toda esta nota. La complejidad no proviene de los requisitos comerciales. Naturalmente, recomendé cambiar el código de la siguiente manera:
Eso es todo, no hay más complejidad. Aquí es donde el desarrollador no debe ser demasiado vago y escribir otra firma de función.
Aquí puede exclamar: "Pero este es solo un 'si'", o: "Esta violación es obvia, ¿quién escribe el código así?" Y aquí viene el segundo ejemplo. Muestra que puede ser notablemente más difícil ver la violación, y también que el costo de esta violación puede ser más que un simple "si". Como en el primer ejemplo, la función se usa en dos lugares:
El método, como se deduce de su nombre, verifica la validez del objeto. Sin embargo, no era obvio que también pudiera verificar la validez de una matriz de objetos. Modifiqué los nombres de las variables para enfatizar esta violación. El método se ve así:
checkValidity(parm: MyType | MyType[]): void { if(Array.isArray(parm)) { parm.forEach(p => checkValidity(p)); } else {
Aqui esta Uno si se convierte en muchos ifs. Si la matriz contiene 100 objetos, entonces este "si" se ejecutará 101 veces. Y en datos reales, podríamos tener 30 mil objetos allí, y esto ya es una pérdida de rendimiento impresionante.
Obviamente, siguiendo el principio de responsabilidad exclusiva, este método debe ser refactorizado para que se obtengan 2 métodos:
checkItemsValidity(parms: MyType[]): void { parms.forEach(p => checkItemValidity(p)); } checkItemValidity(parm: MyType): void {
En consecuencia, también debe ajustar los puntos de llamada.
Es interesante que los ejemplos que di en el artículo sobre SRP condujeron a un aumento en SLOC, los mismos ejemplos, por el contrario, condujeron a una ligera disminución, junto con la mejora esperada en la calidad del código.
Eso es todo Solo un par de ejemplos simples para demostrar el principio más importante del buen código.