Estoy escribiendo código Ruby para un simple ejercicio de encriptación y con frecuencia me he encontrado con este dilema (el ejercicio es un cifrado solitario si debe saberlo). Se trata de si debo rellenar mi lógica con variables descriptivas y declaraciones de un solo paso que hacen que la función sea legible en lugar de declaraciones concisas, incluso densas, que eliminen la repetición y / o minimicen las oportunidades de errores.
Mi ejemplo más reciente: mi programa recibe información y, debido a las pautas de formato rígido, puede determinar fácilmente si la información debe cifrarse o descifrarse. Para simplificar, una vez que la clave de cifrado y el mensaje se convierten / generan para ser compatibles, se trata de restar la clave del mensaje cifrado o agregar la clave a un mensaje no cifrado, para obtener la salida deseada (piense en la clave como cifrado, mensaje + cifrado = código; código - cifrado = mensaje). La posición DRY me dice que debo convertir mi mensaje cifrado de manera diferente a mi mensaje no cifrado para que la función que toma la clave de cifrado y la aplica al mensaje nunca necesite distinguir. Descubrí que esto significa que necesito algunas instrucciones anidadas if en la función, pero la lógica parece ser sólida. Sin embargo, este código no es fácil de leer.
Por otro lado, podría escribir dos funciones diferentes que se invocan en función de un indicador que se establece cuando la aplicación determina el cifrado o descifrado. Esto sería más fácil de leer, pero duplicaría la función de alto nivel de aplicar la clave de cifrado a un mensaje (lo que hace que se cifre o descifre).
¿Debo inclinarme hacia un código legible o un código conciso? ¿O he perdido otra forma de obtener esta funcionalidad y satisfacer ambos principios? ¿Es una posición a lo largo de una escala en la que uno debe considerar el propósito del proyecto y tomar las mejores decisiones para cumplir ese propósito?
Hasta ahora, tiendo a enfatizar el código conciso y SECO sobre el código legible.
Respuestas:
DRY es una guía, no una religión. Aquellos que lo llevan al punto de SECO por encima de todo lo demás, lo han llevado demasiado lejos.
En primer lugar, el código utilizable es primordial. Si el código no es útil y utilizable, no lo es ... y no tiene sentido escribirlo en primer lugar.
En segundo lugar, algún día, alguien tendrá que mantener su código. Si su código no se puede mantener, romperán su diseño "hermoso" denso, conciso y SECO mientras maldicen su nombre. No hagas esto. He sido esa persona y cada vez que veo un cierto nombre en la anotación del código, me estremezco.
Hacer código denso que carece de "variables descriptivas" y pegar todo en expresiones ternarias anidadas con lambdas sin ninguna documentación es inteligente. Es bueno saber que puedes hacerlo, pero no lo hagas. El código inteligente es muy difícil de depurar. Evite escribir código inteligente .
La mayor parte del tiempo dedicado al software se dedica al mantenimiento del software, no a escribirlo la primera vez. Escriba el código para que usted (u otra persona) pueda corregir rápida y fácilmente los errores y agregar funciones según sea necesario con tan pocos cambios de diseño ideales.
fuente
No estoy seguro según la pregunta que entiendes DRY. El código DRY no es lo mismo que conciso. Muy a menudo es lo contrario.
Aquí, no estoy seguro de cuál es el gran problema para este ejemplo. Haga una función para cifrar, una función para descifrar, ayudantes para la funcionalidad común (bytes de mezcla) y un front-end simple para tomar entradas y determinar cifrar / descifrar ... No se repita.
Sin embargo, en general, tanto DRY como legibilidad existen para ayudar a mantener y extender el código. No todos los escenarios son iguales, un gran golpe de legibilidad para eliminar una pequeña repetición no es bueno, y tampoco lo es un montón de duplicación para agregar un poco de legibilidad.
Si se presiona, preferiría la legibilidad. El código duplicado todavía se puede probar: el código ilegible hace que usted haga (y pruebe) lo incorrecto.
fuente
No estoy familiarizado con su caso específico, pero puedo dar algunas pautas generales.
El propósito de la legibilidad y DRY es la mantenibilidad .
La capacidad de mantenimiento es importante en la mayoría de las situaciones. Pasará más tiempo manteniendo el código que escribiendo. Esto es especialmente cierto si considera que escribir código es un tipo especial de mantenimiento.
Desafortunadamente, DRY a menudo es mal entendido. Esto se debe en parte a que parece muy simple, pero como muchas cosas simples puede ser, bueno ... complicado.
La intención de DRY es que cada unidad de funcionalidad exista en un solo lugar. Si se sigue el principio, el responsable del código que tiene la tarea de cambiar o verificar esa funcionalidad puede manejar el código de una vez. Si no se sigue SECO, existe un peligro muy real de que alguna copia de la funcionalidad no se mantenga correctamente.
La violación más obvia de DRY es la codificación de copiar y pegar, donde bloques enteros de código se repiten textualmente en la base del código. Esto es sorprendentemente común en mi experiencia, y de ninguna manera se agrega a la legibilidad. Por lo tanto, refactorizar el código para introducir un método común aumenta invariablemente la conformidad y legibilidad de DRY.
La segunda violación más evidente es "copiar y pegar y cambiar un poco". Nuevamente, refactorizar para introducir un método común con parámetros, o dividir una función en pasos y abstraer los elementos comunes casi siempre aumenta la legibilidad.
Luego están las violaciones más sutiles, donde la funcionalidad se duplica pero el código es diferente. Esto no siempre es fácil de detectar, pero cuando lo ve y refactoriza para extraer el código común en un solo método / clase / función, entonces el código es usualmente más legible de lo que era antes.
Finalmente, están los casos de repetición de diseño. Por ejemplo, podría haber utilizado el patrón de estado varias veces en su base de código, y está considerando refactorizar para eliminar esta repetición. En este caso, proceda con precaución. Es posible que esté reduciendo la legibilidad al introducir más niveles de abstracción. Al mismo tiempo, en realidad no se trata de duplicar la funcionalidad sino de duplicar la abstracción. A veces vale la pena ... pero a menudo no lo es. Su principio rector será preguntar, "cuál de estos es más fácil de mantener".
Cada vez que hago estos juicios, trato de considerar la cantidad de tiempo que las personas pasarán manteniendo el código. Si el código es la funcionalidad principal del negocio, entonces probablemente necesitará más mantenimiento. En esos casos, mi objetivo es hacer que el código se pueda mantener para las personas que están familiarizadas con la base del código y las abstracciones involucradas. Sería más feliz presentar un poco más de abstracción para reducir la repetición. Por el contrario, un guión que rara vez se usa y se mantiene con poca frecuencia podría ser menos fácil de entender para los encargados del mantenimiento si implica demasiada abstracción. En ese caso, me equivocaría del lado de la repetición.
También considero el nivel de experiencia de otros miembros de mi equipo. Evito abstracciones "elegantes" con desarrolladores sin experiencia, pero aprovecho los patrones de diseño reconocidos por la industria con grupos más maduros.
En concusión, la respuesta a su pregunta es hacer lo que haga que su código sea más fácil de mantener. Lo que eso significa en su escenario depende de usted decidir.
fuente
Si sus funciones se vuelven más complicadas y más largas (por lo tanto, menos legibles) cuando intenta hacerlas SECAS, entonces lo está haciendo mal. Está tratando de poner demasiada funcionalidad en una función porque cree que esta es la única forma de evitar repetir los mismos códigos en una segunda función.
Hacer que el código DRY casi siempre signifique refactorizar la funcionalidad común a funciones más pequeñas. Cada una de esas funciones debería ser más simple (y, por lo tanto, más legible) que la original. Para mantener todo en la función original en el mismo nivel de abstracción, esto también puede significar refactorizar partes adicionales que no se usan en otros lugares. Su función original se convierte en una "función de alto nivel", llamando a las más pequeñas, y también se hace más pequeña y simple.
Hacer esto, en consecuencia, conduce principalmente a diferentes niveles de abstracciones en su código, y algunas personas creen que este tipo de código es menos legible. Según mi experiencia, esto es una falacia. El punto clave aquí es dar buenos nombres a las funciones más pequeñas, introducir tipos de datos bien nombrados y abstracciones que puedan ser fácilmente captados por una segunda persona. De esa manera, "SECO" y "legibilidad" solo deberían entrar en conflicto muy, muy raramente.
fuente
Si bien no estoy seguro de qué es exactamente lo que está causando el problema aquí, mi experiencia es que cuando te encuentras con DRY y la legibilidad en conflicto, eso dice que es hora de refactorizar algo.
fuente
Elegiría legible (= mantenible) en lugar de SECO cualquier día de la semana. En realidad, ambos a menudo se alinean, alguien que obtiene el concepto de DRY generalmente produciría (en su mayoría) código legible.
fuente
Muy, muy, muy, muy pocas veces en mi carrera he encontrado un caso legítimo que enfrenta la legibilidad contra DRY. Hazlo legible primero. Nombra bien las cosas. Copie y pegue si es necesario.
Ahora retroceda y mire la totalidad que ha creado, como un artista que retrocede para mirar su pintura. Ahora puedes identificar adecuadamente la repetición.
El código repetido debe ser refactorizado en su propio método, o extraído en su propia clase.
La repetición de código debería ser el último recurso. Primero legible Y SECO, si no es legible si limita el alcance del código repetido.
fuente