Últimamente he refactorizado algunos códigos en el trabajo y pensé que hice un buen trabajo. Bajé 980 líneas de código a 450 y reduje a la mitad el número de clases.
Al mostrar esto a mis colegas, algunos no estuvieron de acuerdo en que esto fuera una mejora.
Dijeron: "menos líneas de código no es necesariamente mejor"
Puedo ver que podría haber casos extremos en los que la gente escribe líneas realmente largas y / o pone todo en un solo método para guardar algunas líneas, pero eso no fue lo que hice. En mi opinión, el código está bien estructurado y es más fácil de comprender / mantener debido a que es la mitad del tamaño.
Me cuesta ver por qué alguien querría trabajar con el doble del código que se requiere para hacer un trabajo, y me pregunto si alguien siente lo mismo que mis colegas y puede presentar algunos buenos argumentos para tener más código en menos ?
fuente
Respuestas:
Una persona delgada no es necesariamente más saludable que una persona con sobrepeso.
Una historia infantil de 980 líneas es más fácil de leer que una tesis de física de 450 líneas.
Hay muchos atributos que determinan la calidad de su código. Algunos simplemente se calculan, como la complejidad ciclomática y la complejidad de Halstead . Otros se definen más libremente, como cohesión , legibilidad, comprensibilidad, extensibilidad, robustez, corrección, autodocumentación, limpieza, comprobabilidad y muchos más.
Podría ser, por ejemplo, que si bien redujo la longitud total del código, introdujo una complejidad injustificada adicional e hizo que el código fuera más críptico.
Dividir un código largo en pequeños métodos podría ser tan dañino como beneficioso .
Pídale a sus colegas que le brinden comentarios específicos sobre por qué creen que sus esfuerzos de refactorización produjeron un resultado indeseable.
fuente
Curiosamente, un colega y yo estamos actualmente en medio de un refactorizador que aumentará el número de clases y funciones en un poco menos del doble, aunque las líneas de código permanecerán casi iguales. Así que tengo un buen ejemplo.
En nuestro caso, teníamos una capa de abstracción que realmente debería haber sido dos. Todo estaba repleto en la capa de interfaz de usuario. Al dividirlo en dos capas, todo se vuelve más cohesivo, y probar y mantener las piezas individuales se vuelve mucho más simple.
No es el tamaño del código lo que molesta a tus colegas, es otra cosa. Si no pueden articularlo, intente mirar el código usted mismo como si nunca hubiera visto la implementación anterior, y evaluarlo por sus propios méritos en lugar de solo en comparación. A veces, cuando hago una refactorización larga, pierdo de vista el objetivo original y llevo las cosas demasiado lejos. Tome una mirada crítica de "panorama general" y vuelva a encaminarla, tal vez con la ayuda de un programador de pares cuyo consejo valore.
fuente
Me viene a la mente una cita, a menudo atribuida a Albert Einstein:
Cuando se va por la borda recortando cosas, puede hacer que el código sea más difícil de leer. Como "fácil / difícil de leer" puede ser un término muy subjetivo, explicaré exactamente lo que quiero decir con esto: una medida del grado de dificultad que tendrá un desarrollador experto para determinar "¿qué hace este código?" con solo mirar la fuente, sin la ayuda de herramientas especializadas.
Lenguajes como Java y Pascal son infames por su verbosidad. Las personas a menudo señalan ciertos elementos sintácticos y dicen burlonamente que "están ahí para facilitar el trabajo del compilador". Esto es más o menos cierto, excepto por la parte "justa". Cuanta más información explícita haya, más fácil será leer y comprender el código, no solo por un compilador sino también por un ser humano.
Si digo
var x = 2 + 2;
, es inmediatamente obvio quex
se supone que es un número entero. Pero si digovar foo = value.Response;
, está mucho menos claro quéfoo
representa o cuáles son sus propiedades y capacidades. Incluso si el compilador puede inferirlo fácilmente, pone mucho más esfuerzo cognitivo en una persona.Recuerde que los programas deben estar escritos para que la gente los lea, y solo de manera incidental para que las máquinas los ejecuten. (Irónicamente, ¡esta cita proviene de un libro de texto dedicado a un lenguaje infame por ser extremadamente difícil de leer!) Es una buena idea eliminar cosas que son redundantes, pero no elimine el código que hace que sea más fácil para sus seres humanos averiguar qué está pasando, incluso si no es estrictamente necesario para el programa que se está escribiendo.
fuente
var
ejemplo no es particularmente bueno de simplificación porque la mayoría de las veces leer y comprender el código implica descubrir el comportamiento en un cierto nivel de abstracción, por lo que conocer los tipos reales de variables específicas generalmente no cambia nada (solo te ayuda a entender las abstracciones más bajas). Un mejor ejemplo sería múltiples líneas de código simple agrupadas en una sola declaración enrevesada, por ejemplo,if ((x = Foo()) != (y = Bar()) && CheckResult(x, y))
toma tiempo para asimilar, y conocer los tiposx
oy
no ayuda en lo más mínimo.Un código más largo puede ser más fácil de leer. Por lo general, es lo contrario, pero hay muchas excepciones, algunas de ellas descritas en otras respuestas.
Pero veamos desde un ángulo diferente. Asumimos que el nuevo código será visto como superior por los programadores más hábiles que ven las 2 piezas de código sin tener un conocimiento adicional de la cultura, la base del código o la hoja de ruta de la compañía. Incluso entonces, hay muchas razones para objetar el nuevo código. Por brevedad llamaré a "Personas que critican el nuevo código" Pecritenc :
fuente
Qué tipo de código es mejor puede depender de la experiencia de los programadores y también de las herramientas que utilizan. Por ejemplo, aquí es por qué lo que normalmente se consideraría código mal escrito puede ser más efectivo en algunas situaciones que el código orientado a objetos bien escrito que hace uso completo de la herencia:
(1) Algunos programadores simplemente no tienen una comprensión intuitiva de la programación orientada a objetos. Si su metáfora para un proyecto de software es un circuito eléctrico, entonces esperará mucha duplicación de código. Le gustará ver más o menos los mismos métodos en muchas clases. Te harán sentir como en casa. Y un proyecto en el que tiene que buscar métodos en las clases para padres o incluso en las clases de abuelos para ver qué está pasando puede parecer hostil. No desea comprender cómo funciona la clase principal y luego comprender cómo difiere la clase actual. Desea comprender directamente cómo funciona la clase actual, y encuentra confuso el hecho de que la información se extiende sobre varios archivos.
Además, cuando solo desea solucionar un problema específico en una clase específica, es posible que no le guste tener que pensar si solucionar el problema directamente en la clase base o sobrescribir el método en su clase de interés actual. (Sin herencia no tendría que tomar una decisión consciente. El valor predeterminado es simplemente ignorar problemas similares en clases similares hasta que se informen como errores). Este último aspecto no es realmente un argumento válido, aunque podría explicar algunas de las oposición.
(2) Algunos programadores usan mucho el depurador. Aunque en general estoy firmemente del lado de la herencia de código y evito la duplicación, comparto algo de la frustración que describí en (1) al depurar código orientado a objetos. Cuando sigue la ejecución del código, a veces sigue saltando entre clases (ancestro) aunque permanezca en el mismo objeto. Además, al establecer un punto de interrupción en un código bien escrito, es más probable que se active cuando no sea útil, por lo que es posible que tenga que hacer un esfuerzo para hacerlo condicional (cuando sea práctico) o incluso continuar manualmente muchas veces antes del activador relevante.
fuente
Depende totalmente. He estado trabajando en un proyecto que no permite variables booleanas como parámetros de función, sino que requiere un dedicado
enum
para cada opción.Entonces,
es mucho más detallado que
Sin embargo,
es mucho más legible que
El compilador debe generar el mismo código para ambos, por lo que no se gana nada utilizando el formulario más corto.
fuente
Yo diría que la cohesión podría ser un problema.
Por ejemplo, en una aplicación web, digamos que tiene una página de administración en la que indexa todos los productos, que es esencialmente el mismo código (índice) que usaría en una situación de página de inicio, para ... simplemente indexar los productos.
Si decide parcializar todo para que pueda mantenerse SECO y elegante, tendría que agregar muchas condiciones con respecto a si el usuario que navega es un administrador o no y desordenar el código con cosas innecesarias que lo harán altamente ilegible, digamos ¡Un diseñador!
Entonces, en una situación como esta, incluso si el código es más o menos el mismo, solo porque podría escalar a otra cosa y los casos de uso podrían cambiar ligeramente, sería malo ir tras cada uno de ellos agregando condiciones e ifs. Por lo tanto, una buena estrategia sería deshacerse del concepto DRY y romper el código en partes que se puedan mantener.
fuente
Cuando menos código es menos mantenible / extensible que más código. Refactorizar la concisión del código a menudo elimina las construcciones de código "innecesarias" en interés de LoC. El problema es que esas construcciones de código, como las declaraciones de interfaz paralela, los métodos / subclases extraídos, etc. son necesarios si este código alguna vez necesita hacer más de lo que hace actualmente, o hacerlo de manera diferente. En el extremo, ciertas soluciones personalizadas para el problema específico pueden no funcionar si la definición del problema cambia solo un poco.
Un ejemplo; Tienes una lista de enteros. Cada uno de estos enteros tiene un valor duplicado en la lista, excepto uno. Su algoritmo debe encontrar ese valor no emparejado. La solución de caso general es comparar cada número con cualquier otro número hasta que encuentre un número que no tenga engaño en la lista, que es una operación N ^ 2 veces. También podría construir un histograma usando una tabla hash, pero eso es muy poco eficiente en cuanto al espacio. Sin embargo, puede hacerlo de tiempo lineal y espacio constante utilizando una operación XOR a nivel de bits; XOR cada entero contra un "total" en ejecución (comenzando con cero), y al final, la suma de ejecución será el valor de su entero sin emparejar. Muy elegante. Hasta que los requisitos cambien, y más de un número en la lista no pueda ser emparejado, o los enteros incluyan cero. Ahora su programa devuelve basura o resultados ambiguos (si devuelve cero, ¿eso significa que todos los elementos están emparejados o que el elemento no emparejado es cero?). Tal es el problema de las implementaciones "inteligentes" en la programación del mundo real.
fuente
El código de computadora necesita hacer varias cosas. Un código "minimalista" que no hace estas cosas no es un buen código.
Por ejemplo, un programa de computadora debe cubrir todos los casos posibles (o como mínimo, todos los casos probables). Si un código cubre solo un "caso base" e ignora otros, no es un buen código, incluso si es breve.
El código de la computadora debe ser "escalable". Un código críptico puede funcionar solo para una aplicación especializada, mientras que un programa más largo pero más abierto puede facilitar la adición de nuevas aplicaciones.
El código de la computadora debe ser claro. Como demostró otro respondedor, es posible que un codificador de núcleo duro produzca una función de tipo "algorítmico" de una línea que haga el trabajo. Pero la frase tenía que dividirse en cinco "oraciones" diferentes antes de que fuera claro para el programador promedio.
fuente
Rendimiento computacional. Al optimizar el revestimiento de tuberías o ejecutar partes de su código en paralelo, puede ser beneficioso, por ejemplo, no realizar un bucle de 1 a 400, sino de 1 a 50 y colocar 8 instancias de código similar en cada bucle. No estoy asumiendo que este fuera el caso en su situación, pero es un ejemplo en el que más líneas son mejores (en términos de rendimiento).
fuente