Uno de los principios más básicos y ampliamente aceptados del desarrollo de software es DRY (no se repita). También está claro que la mayoría de los proyectos de software requieren algún tipo de gestión.
¿Cuáles son las tareas que son fáciles de administrar (estimar, programar, controlar)? Tareas correctas y repetitivas, exactamente las tareas que deben evitarse según DRY.
Por lo tanto, desde la perspectiva de la gestión de proyectos, es excelente resolver una tarea copiando un código existente 100 veces y hacer algunas adaptaciones menores a cada copia, según sea necesario. En todo momento, usted sabe exactamente cuánto trabajo ha realizado y cuánto le queda. Todos los gerentes te amarán.
Si, en cambio, aplica el principio DRY e intenta encontrar una abstracción que elimine más o menos el código duplicado, las cosas son diferentes. Por lo general, hay muchas posibilidades, tienes que tomar decisiones, investigar, ser creativo. Puede encontrar una mejor solución en menos tiempo, pero también puede fallar. La mayoría de las veces, realmente no se puede decir cuánto trabajo queda. Eres la peor pesadilla de un gerente de proyecto.
Por supuesto que estoy exagerando, pero obviamente hay un dilema. Mis preguntas son: ¿Cuáles son los criterios para decidir si un desarrollador está exagerando DRY? ¿Cómo podemos encontrar un buen compromiso? ¿O hay una manera de superar completamente este dilema, no solo encontrando un compromiso?
Nota: Esta pregunta se basa en la misma idea que la anterior, Cantidad de trabajo de rutina en el desarrollo de software y su efecto en la estimación , pero creo que aclara mi punto, perdón por repetirme :).
fuente
Respuestas:
Parece asumir que el objetivo principal de la gestión de proyectos es producir estimaciones exactas. Este no es el caso. El objetivo principal de la gestión de proyectos es el mismo que para los desarrolladores: entregar valor para el propietario del producto.
En teoría, un producto que utiliza muchos procesos manuales lentos en lugar de automatización podría ser más fácil de estimar (aunque lo dudo), pero no proporciona una buena relación calidad-precio para el cliente, por lo que es simplemente una mala gestión del proyecto. No hay dilema
Es bien sabido que la estimación de proyectos de software es difícil, y se han escrito numerosos libros y se han desarrollado varios procesos para gestionarlo.
Si el único objetivo del PM fuera producir estimaciones exactas, entonces sería fácil. Simplemente aumente las estimaciones a 10X y deje que los desarrolladores jueguen juegos por el resto si terminan antes. En realidad, esto sería mejor que su sugerencia de utilizar el trabajo ocupado de copiar y pegar para rellenar el tiempo, ya que jugar juegos no reducirá la capacidad de mantenimiento del producto.
Pero en realidad, el propietario del producto quiere estimaciones útiles y un producto de calidad entregado de la manera más rápida y económica posible. Estas son las limitaciones reales que un PM tendrá que navegar.
En cualquier caso, cuestiono su suposición de que el trabajo manual repetitivo es más predecible que automatizado. Toda la experiencia muestra que el trabajo manual repetitivo es más propenso a errores. ¿Y qué pasa si se descubre un error en el código copiado? De repente, el costo de corregir un error se multiplica por la cantidad de repetición, lo que hace que la incertidumbre explote.
fuente
Tiene razón: copiar y pegar funciona muy bien, y DRY no tiene sentido cuando su tarea es producir un programa para el cual la plantilla copiada o la copia no tendrán que mantenerse o evolucionar en el futuro. Cuando esos dos componentes de software tienen un ciclo de vida completamente diferente, acoplarlos juntos refactorizando un código común en una biblioteca común que está en desarrollo puede tener efectos impredecibles para el esfuerzo. Por otro lado, al copiar secciones de código dentro de un programa o sistema de programas, todas estas partes generalmente tendrán el mismo ciclo de vida. A continuación ilustraré lo que esto significa para DRY y la gestión de proyectos.
En serio, existen muchos programas de este tipo: por ejemplo, la industria de los juegos de computadora produce muchos programas que deben mantenerse durante un período corto de algunos meses o un año como máximo, y cuando ese tiempo termina, copie y pegue el código antiguo de un juego anterior donde se excede el período de mantenimiento, en la base de código de un juego nuevo está perfectamente bien y podría acelerar las cosas.
Desafortunadamente, el ciclo de vida de la mayoría de los programas con los que tuve que lidiar en los últimos años es muy diferente. El 98% de los requisitos o solicitudes de corrección de errores que me llegaron fueron solicitudes de cambiopara programas existentes. Y cada vez que necesite cambiar algo en una pieza de software existente, la "gestión de proyectos" o la planificación funcionan mejor cuando sus esfuerzos de prueba y depuración son bastante bajos, lo que no será el caso si cambia algo en un lugar, pero debido a la copia lógica empresarial pegada, olvida fácilmente que también necesita cambiar una docena de otros lugares en la base del código. E incluso si logra encontrar todos esos lugares, el tiempo para cambiarlos todos (y probar los cambios) es probablemente mucho mayor, como si solo tuviera un lugar para cambiar. Entonces, incluso podría hacer una estimación precisa del cambio, ya que los costos una docena de veces más altos de lo necesario pueden colisionar fácilmente con el presupuesto del proyecto.
TLDR: siempre que desarrolle un programa en el que no sea necesaria ni responsable la corrección de errores y el mantenimiento del original o la copia, no dude en copiar. Pero si usted, su equipo o su empresa son o podrían ser responsables, aplique DRY siempre que pueda.
Ejemplo
Como anexo, permítanme explicar qué significa "corrección de errores y mantenimiento", y cómo esto conduce a la imprevisibilidad en la planificación, especialmente dentro de un producto, por un ejemplo del mundo real. De hecho, he visto que este tipo de cosas suceden en realidad, probablemente no con 100 instancias, pero los problemas incluso pueden comenzar cuando solo tienes una instancia duplicada.
La tarea: crear 100 informes diferentes para una aplicación, cada informe se ve muy similar, algunas diferencias de requisitos entre los informes, alguna lógica diferente, pero en general, no hay muchas diferencias.
El desarrollador que obtiene esta tarea crea la primera (digamos que toma 3 días), después de algunos cambios o correcciones de errores menores debido al control de calidad y la inspección del cliente está terminada, parece funcionar bien. Luego comenzó a crear el siguiente informe copiando y modificando todo, luego el siguiente, y para cada nuevo informe necesita ~ 1 día en promedio. Muy predecible, a primera vista ...
Ahora, después de que los 100 informes estén "listos", el programa pasa a producción real y ocurren algunos problemas que se pasaron por alto durante el control de calidad. Tal vez haya problemas de rendimiento, tal vez los informes se bloqueen de forma regular, tal vez otras cosas no funcionen según lo previsto. Ahora, cuando se aplicó el principio DRY, el 90% de esos problemas podrían resolverse cambiando la base del código en un solo lugar. Pero debido al enfoque de copiar y pegar, el problema debe resolverse 100 veces en lugar de una vez. Y debido a los cambios ya aplicados de un informe a otro, el desarrollador no puede copiar y pegar rápidamente la corrección para el primer informe en el otro 99. Tiene que buscar en los 100 informes, leerlos, traducir el cambio al modificado informe, pruébelo y quizás depure cada uno individualmente. Para la tarde, esto comienza a ponerse realmente difícil: por supuesto, puede tomarse el tiempo para una corrección de errores "regular" (digamos, 3 horas) y multiplicar esto por 100, pero en realidad, esta es probablemente una estimación incorrecta, algunas de las soluciones podrían ser más fácil de hacer que otros, otros podrían ser más difíciles. E incluso si esta estimación es correcta, hacer que la depuración cueste 100 veces más de lo necesario, le costará mucho dinero a la empresa.
Lo mismo sucederá la próxima vez cuando el cliente solicite cambiar el color del emblema de su empresa en todos esos informes, para hacer que el tamaño de página sea configurable o por algún otro requisito nuevo que afecte a todos los informes de manera similar. Entonces, si eso sucede, puede hacer una estimación de los costos y facturar al cliente 100 veces el precio que tendría que pagar cuando el código hubiera estado SECO. Sin embargo, intente esto varias veces y luego el cliente cancelará el proyecto porque probablemente no estará dispuesto a pagar sus costos de evolución exorbitantes. Y quizás en ese momento alguien haga la pregunta de por qué sucedió esto y señale con el dedo a la persona que tomó la decisión de esta programación de copiar y pegar.
Mi punto es: cuando produce software para otros, siempre tiene al menos durante un corto período de tiempo la responsabilidad de hacer que funcione, corregir errores, adaptar el programa a los requisitos cambiantes, etc. Incluso en un proyecto de campo verde, estos las piezas pueden sumar rápidamente mucho más que el esfuerzo de desarrollo inicialmente planificado. Y especialmente cuando todo su código copiado está dentro de un producto, el período de responsabilidad es para todas las partes iguales, lo cual es bastante diferente de la situación en la que copió un código antiguo de un proyecto muerto que ya no es bajo mantenimiento activo.
fuente
Su afirmación base es incorrecta.
Lo que hace que el software sea diferente de otras profesiones es que estás haciendo algo nuevo todos los días. Después de todo, ningún cliente va a pagar usted para construir algo que alguien ya lo ha hecho. A los gerentes de proyecto les puede gustar la previsibilidad, pero a sus jefes les gusta el valor . Si solo está copiando código con ligeras variaciones, no está proporcionando mucho valor a la empresa.
Eventualmente, la compañía se dará cuenta de que pueden hacer el mismo trabajo en una fracción del tiempo contratando a un buen programador. Y si no lo hacen, sus competidores lo harán.
fuente
La programación de cortar y pegar finalmente conduce a un software abandonado. Fui contratista de un sistema para ordenar servicios de telefonía fija de una compañía telefónica muy grande. El sistema fue cortado y pegado ad nauseum porque todas las pruebas fueron manuales y no querían cambiar ningún código de trabajo. La mejora más pequeña podría resultar en una nueva copia de cientos de líneas de código. Originalmente, la aplicación fue escrita para manejar cuentas de hasta doce líneas físicas. Por supuesto, esta limitación se realizó en cientos de ubicaciones en el código. Después de aproximadamente cuatro años, el negocio preguntó al equipo qué se necesitaría para manejar cuentas más grandes. Estimaron alrededor de $ 18 millones. En ese momento, el proyecto fue entregado a un equipo offshore para un mantenimiento mínimo. El equipo existente fue despedido.
Las organizaciones que piensan de esta manera están siendo aplastadas por compañías con mejor tecnología.
fuente
Una máxima a menudo olvidada que se aplica aquí es la regla de 3 . Esto indica que está bien copiar el código una vez, pero más allá de eso debe ser reemplazado por un código genérico.
3 puede parecer un número arbitrario, pero un escenario común es donde los datos y la lógica se duplican en una aplicación y base de datos. Un ejemplo a menudo citado es cuando hay una tabla de búsqueda en la base de datos y un lado del cliente de enumeración. La diferencia en los paradigmas no permite que esto se almacene fácilmente en un solo lugar, por lo que la información a menudo aparece en ambos lugares.
Si bien es bueno tener código DRY, puede haber ocasiones en que la lógica de negocios dicte una excepción, por lo que debe crear dos o más bits de código de origen que antes era genérico.
¿Entonces lo que hay que hacer? Código para el status quo (después de todo, YAGNI ). Si bien el código debe escribirse para facilitar la modificación, escribir una serie completa de campanas y silbatos para algo que podría no ser necesario es simplemente incendiar dinero.
fuente
En su pregunta, solo enumera tres funciones de gestión de proyectos: estimación, programación y control. La gestión de proyectos se trata de lograr objetivos dentro de las limitaciones del proyecto. Los métodos utilizados para lograr los objetivos dentro de las limitaciones de un proyecto son diferentes para proyectos de software que muchos otros tipos de proyectos. Por ejemplo, desea que los procesos de fabricación sean altamente repetibles y bien entendidos. Sin embargo, el desarrollo de software es principalmente trabajo de conocimiento- no es de rutina y requiere pensar en lugar de seguir instrucciones y procedimientos rígidos. Las técnicas utilizadas para iniciar, planificar, ejecutar, monitorear y controlar, y cerrar un proyecto de software deberán dar cuenta del tipo de trabajo que se debe realizar en un proyecto de software, específicamente, trabajo no rutinario que no se puede hacer a instrucciones y procedimientos específicos.
Creo que el otro problema es que está tomando DRY, un concepto que se relaciona con la repetición de información, y está tratando de aplicarlo a la gestión de tareas. DRY simplemente dice que solo debe tener una representación autorizada de la información. Los gerentes de proyecto deberían estar adoptando esto, ya que significa que todos sabrán a dónde ir para obtener la información, la comunicación de los cambios será fácil y los cambios pueden controlarse y administrarse bien. DRY, a través de piezas reutilizables, ayuda a mantener bajos los costos a largo plazo, ayuda a mantener cronogramas a largo plazo y a mejorar la calidad: tres piezas para el Triángulo de Gestión de Proyectos . Es necesario invertir algo de tiempo y dinero para hacer que las cosas se sequen de manera efectiva, pero el trabajo del gerente del proyecto es hacer concesiones de tiempo, costo, cronograma y calidad.
fuente
Escribir un nuevo código es solo una pequeña parte de la tarea
Su sugerencia facilitaría la estimación de la parte de escribir inicialmente un nuevo código. Sin embargo, para traer algo nuevo (no importa si se trata de un sistema nuevo, una adición de características o un cambio de funcionalidad), hacer esto no es suficiente y es solo una minoría de trabajo: las estimaciones observadas en la literatura indican que en la práctica esto parte es algo así como 20% -40% del trabajo total.
Por lo tanto, la mayoría del trabajo (que incluye adaptar su desarrollo inicial a lo que realmente se necesitaba, integración, prueba, reescritura, reevaluación) no es más fácil de estimar; al revés, evitando intencionalmente DRY acaba de hacer que esa parte sea mucho más grande, más difícil y con estimaciones más variables: ese error o necesidad de cambio que requiere cambiar todas las partes clonadas puede no ocurrir, pero si lo hace, entonces sus estimaciones van a estar totalmente equivocados
No obtiene mejores estimaciones al mejorar la calidad de su estimación de una pequeña parte del trabajo pero empeorarla en una gran parte del trabajo; por lo que no es realmente una compensación, sino una situación de perder-perder donde se obtiene una peor productividad pero también peores estimaciones.
fuente
DRY es útil pero también está sobrevalorado. Algunas personas pueden llevarlo demasiado lejos. De lo que muchos desarrolladores no se dan cuenta es que cada vez que implementa DRY para usar el mismo método para dos propósitos (ligeramente) diferentes, está introduciendo una especie de acoplamiento muy estrecho entre los diferentes usos. Ahora, cada vez que cambie el código para el primer caso de uso, también debe verificar si regresa el segundo caso de uso. Si estos son casos de uso ampliamente independientes, es muy cuestionable si deberían estar estrechamente acoplados, probablemente no deberían estarlo.
El uso excesivo de DRY también puede conducir a métodos de Dios que explotan en complejidad para manejar todos los diferentes casos de uso a los que se someten, cuando los métodos atómicos más pequeños que replican algún código serían mucho más fáciles de mantener.
Sin embargo, sugeriría que la pregunta no es realmente relevante a nivel de gestión de proyectos. Un gerente de proyecto realmente no querrá preocuparse por este nivel de detalle de implementación. Si lo son, probablemente sea microgestión. Realmente ... cómo se implementan las cosas es más responsabilidad del desarrollador y líder técnico. La gestión de proyectos está más preocupada por lo que se hace y cuándo .
EDITAR: por comentario, estoy de acuerdo, sin embargo, en la medida en que facilita la estimación del tiempo de desarrollo, evitar DRY a veces puede reducir la cantidad de incertidumbre. Pero creo que este es un tema insignificante en relación con las preguntas más apremiantes de (1) cuánto tiempo hasta que se cumplan los requisitos comerciales, (2) qué deuda técnica se asume en el proceso, y (3) riesgos para el costo total de la propiedad de las elecciones arquitectónicas realizadas, ya sea que se seque o no en muchos casos, es una elección de diseño que debería basarse más en el riesgo / recompensa de esos factores, que en si hace que sea un poco más fácil proporcionar a los gerentes de proyecto información más precisa .
fuente
Creo que estás malentendido DRY.
Usemos un ejemplo:
vs.
Al reemplazar la clase B con C, hemos seguido el principio DRY y hemos reducido la duplicación de código. Pero no hemos aumentado las incógnitas o el riesgo para el proyecto (a menos que nunca haya hecho una herencia antes).
Creo que lo que quieres decir cuando hablas de DRY es algo más como una tarea de diseño. Es decir:
!!!¡Nuevo requerimiento! ¡Algunos clientes necesitan poder multiplicar dobles!
vs.
Aquí (suponiendo que funcione) hemos diseñado una solución que puede abordar tanto el requisito antiguo como el nuevo, esencialmente tratando de crear un modelo matemático del problema de la vida real o las reglas comerciales. En la vida real, el sistema que estamos modelando obviamente será mucho más complicado, nuestro modelo no se ajustará exactamente y los casos extremos y los resultados inesperados tomarán tiempo para encontrarlos y corregirlos.
Entonces, ¿deberíamos tomar B o A versión 2 en este caso?
B será más específico para el cambio solicitado real con menos efectos secundarios y será más fácil de estimar y más rápido de hacer.
Una versión 2 dará como resultado menos código general en el futuro y será la solución más elegante
Una vez más, voy a decir que se reduce a la calidad de las especificaciones y requisitos.
Si tenemos especificaciones muy claras que cubren los casos límite y la compatibilidad con versiones anteriores, entonces podemos estar seguros de que entendemos el sistema lo suficientemente bien como para refactorizar el modelo sin producir errores.
Si tenemos una solicitud de emergencia para un solo cliente donde el único requisito es que el comportamiento cambie para ese cliente sin tener en cuenta el sistema general; entonces 'mejorar' el modelo refactorizando A conlleva un riesgo sustancial. Tanto para romper otros clientes como para sobrepasar la fecha límite debido al tiempo extra desconocido necesario para diseñar y probar la solución.
fuente
Párrafo por párrafo
Correcto.
Las tareas repetitivas deben ser automatizadas, obligatorias . Son aburridos, propensos a errores, cuando se hacen a mano.
Creo que puede cambiar la palabra "adaptación" con "configuración". Considere que tiene un error en este código que se supone que debe copiarse. Un error que aparece bajo condiciones específicas. Si no se repara en la fuente original, y se copia, habrá muchos lugares para arreglar. Esto puede ser malo, pero alguien tiene que:
Eliminar las duplicaciones conduce a un solo punto de falla. Si algo falla, puede estar bastante seguro de dónde sucede. SOLID y Design Patterns están ahí para ayudar a solucionar exactamente ese problema. Los plazos demasiado cortos tienden a provocar una "codificación" de estilo procesal. Más tiempo invertido en un proyecto para crear algo reutilizable significa que debe haber una cantidad mínima de tiempo invertido en el próximo proyecto cuando la función se reutilizará, pero debe ser configurable en primer lugar.
Mucha gente señaló que no hay dilema aquí. Si y no.
Si tiene algo altamente experimental que nunca antes se había hecho, no hay dilema. De lo contrario, si tiene que volver a hacer algo, como un nuevo sistema de reservas, ya tiene abstracciones, solo depende de lo que necesite.
Creo que el dilema es: si implementamos algo en una característica, si es poco probable que se solicite. Implemente algo cuando se le solicite. Nadie necesita una gran infraestructura que no se utilizará.
fuente
Absolutamente se trata de diseño. Tal vez no se reutilice per se, pero no obstante, diseñe.
Experiencia y su entorno / situación existente. Para un problema dado, obtendrá un fuerte sentido del Principio de Prado al intentar mayores grados de SECADO. Entonces, de repente, entran en juego consideraciones de gestión. El tiempo, los objetivos, el cliente, la gestión del código a largo plazo (alguien dijo que la deuda técnica ), etc. informarán su plan de ataque.
Uh ... ¿diseño? Refactorizar es diseño, bueno, se supone que debe ser. El alcance de DRYing puede expandirse fácilmente como una supernova desde el bucle, el método y las clases. He estado allí, hecho eso. Pero realmente no puede saber hasta que estudie el problema: esto es diseño.
¿Cómo puede no ser un problema de diseño? Debe considerar el problema más ampliamente que el código duplicado inmediato a la mano. Esta es una actividad de diseño, ya sea código existente o una hoja en blanco; ya sea "método de extracción" o creando nuevas clases y módulos.
Epílogo
Gestión típica, ignorando el tiempo de diseño. Idealmente, habríamos diseñado la repetitividad superfluamente redundante antes de la codificación. En cambio, la gerencia piensa que el desarrollo (y la corrección de errores) es un evento olímpico único, la codificación, cuando en realidad es un decatlón. Y miden 1/1000 de segundo porque piensan que todo es analógico.
Tuve esta experiencia: "Pasé dos días escribiendo esta fila (de un formulario GUI) y dos horas escribiendo el resto del formulario". Quiero decir que me tomé el tiempo para identificar las clases reutilizables, DRY es un efecto secundario natural, la fila de formulario GUI y w / in que algunos otros. Una vez depurados, estos se usaron, individualmente y en composición, en todo el formulario, que ahora se codificó muy rápido y las pruebas fueron excepcionalmente rápidas a pesar de la complejidad de la construcción. Y también pasó por pruebas formales con una tasa de errores sorprendentemente baja.
Yo tampoco lo sabía, pero tenía fe en que el esfuerzo inicial de diseño valía la pena. Todos decimos esto, pero la administración en particular no confía en ello. La gerencia hubiera pensado que estaba jodiendo. "¡Dos días y aún no tienes el 2% codificado!"
En un caso, nos apegamos a nuestras armas cuando la gerencia dijo "estás pasando demasiado tiempo en el diseño, ponte en marcha". Y compañeros de trabajo diciendo "son demasiadas clases". Bueno, se suponía que un subproyecto mucho menos complejo tomaría alrededor de 1 mes (pensé que estaba bien adivinar) pero tardó 5 meses. 3 meses de eso fue en pruebas / arreglos porque era un punto de venta. "¡Pero no tuvimos tiempo de diseñar!". En realidad dijeron eso.
Muestre a la gerencia cómo funciona. Captura algunos datos. Compare con otro trabajo, especialmente el de sus compañeros de trabajo que hacen el trabajo apresurado. Ese montón de fallas siempre parece perder la carrera, quedando atascado en la prueba y luego, después del lanzamiento, volvió una y otra vez para corregir más errores.
fuente