¿Cómo manejas el código feo que escribiste? [cerrado]

88

Entonces su cliente le pide que escriba un código, y usted lo hace. Luego cambia las especificaciones sobre usted, como se esperaba, e implementa diligentemente sus nuevas características como un buen muchacho. Excepto ... las nuevas características entran en conflicto con las características antiguas, por lo que ahora su código es un desastre. Usted realmente quiere volver atrás y corregir, pero él le sigue pidiendo cosas nuevas y cada vez que haya terminado de limpiar algo, vientos de hasta un lío de nuevo.

¿Qué haces? ¿Dejar de ser un maníaco del TOC y simplemente aceptar que su código va a terminar siendo un desastre sin importar lo que haga, y simplemente seguir agregando características a esta monstruosidad? ¿Guardar la limpieza para la versión 2?

Mark
fuente
15
Esa es una gran pregunta.
Walter
3
Creo que este es un buen lugar para aplicar la regla 80/20 .
Mark C
umm..no escribir código feo en primer lugar ?!
Roopesh Shenoy
8
@Roopesh: No es feo en primer lugar, es cuando sigues agregando cosas que se vuelve feo. Con las características adicionales, te das cuenta de que la estructura central podría haber sido diseñada de manera diferente para soportar mejor esas características. Y en ese punto, puede retroceder y volver a escribir grandes pedazos de base, o simplemente agregar la función. Por lo general, no hay tiempo suficiente para retroceder y volver a escribir la mitad de su programa.
mpen
Entonces "diseña teniendo en cuenta el cambio", dices. Claro, es fácil de decir, pero cuando algunas cosas fundamentales cambian porque su cliente realmente no sabe lo que quiere y solo le da media especificación por adelantado, es un poco difícil.
mpen

Respuestas:

41

Consigue otro trabajo y deja que otras personas se encarguen de ello. Muahahahhahahaa.

.....

Solo bromeaba. :)

Pero con toda seriedad: el relleno de estimación es tu amigo. Generalmente hago una estimación realista decente, luego la doblo. Esto puede sonar excesivo, y a veces lo es, pero es mejor sobrestimar un poco e incluso parecer un poco lento a veces, que dejar malas impresiones al generar un código defectuoso y siempre soplar sus estimaciones. Y, por supuesto, incurres en una deuda técnica al permitir que la base de código se vuelva hacky.

Otro consejo (relacionado): siempre calcule las tareas aparentemente pequeñas y sin complicaciones para un bloque de tamaño decente. Digamos, por ejemplo, un elemento del que está casi seguro que será un simple cambio de 30 segundos en una línea: dele 1 hora (o tal vez el bloque de tiempo más bajo en su hoja de horas o sistema CR, por ejemplo, 15 minutos / 0.25 horas) . Y dé bloques de medio día o 1 día para los artículos un poco más grandes pero aún relativamente triviales.

La razón de esto es principalmente psicológica: descubro que si tienes el hábito de hackear rápidamente pequeños cambios, el trabajo se siente apresurado, y nunca terminas sentado, haciendo balance y refactorizando cosas que necesitan ser refactorizadas. Además, en un nivel práctico: a veces se producen cambios pequeños pero no triviales, y no desea sentirse constantemente como si estuviera retrasado y apagando incendios de insectos. Es parte integrante de por qué las bases de código se vuelven hacky con el tiempo.

Finalmente, recuerde siempre que las personas no tienen que saber que está rellenando un poco sus estimaciones. Mientras sea un desarrollador competente y esté trabajando a un ritmo decente, este relleno no se notará. es decir, no le digas al PHB "Mi estimación inicial es que tomará dos horas, pero dame medio día". Solo dígale "Creo que tomará aproximadamente medio día". y déjalo ahí.

Mesas Bobby
fuente
12
+1 Por ser malvado. ;)for(printf("MUHU"); 1; printf("HA"));
Mateen Ulhaq
1
@muntoo: Me tomó un segundo darme cuenta de lo que hizo ... no vi el for. Cute;)
mpen
44
Estoy seguro de que esto depende del gerente, pero no necesariamente necesita mentir. El CTO y yo tenemos un entendimiento; él sabe que puedo dar una estimación razonable pero solo con un 50% de confianza; Si pongo un factor de falsificación, puedo dar la misma estimación con un nivel de confianza del 90%. Y resulta que, durante un largo período de tiempo, la mayoría de las personas prefieren estimaciones confiables a ingenuamente optimistas, incluso si no lo admiten o se dan cuenta, por lo que le da la estimación pesimista a su jefe a menos que sea una emergencia.
Aaronaught
2
El punto de que absolutamente nada lleva menos de media hora está muy bien hecho. Incluso si un solo cambio en el código toma 5 minutos, hay una gran cantidad de sobrecarga que acompaña.
Murph el
2
@Murph - en el clavo. Rechazo cualquier estimación comercial de menos de medio día. Para el momento en que el desarrollador haya tomado el código correcto, haya realizado el cambio, ejecute las pruebas unitarias, haya pasado la compilación para probar y la prueba lo haya comprobado, NADA toma 5 minutos.
Jon Hopkins el
66

Sobreestime deliberadamente el tiempo necesario para sus próximas funciones. Usa ese tiempo extra para limpiar.

Nunca podrá justificar el mantenimiento, y el cliente lo necesita independientemente, así que dele el medicamento amargo (costos ligeramente mayores para las siguientes funciones) para que puedan mejorar.

Frank Shearar
fuente
+1 por esto. Estimación de relleno FTW. Y realmente, el mismo consejo se aplica para justificar cuánto tiempo lleva la reparación de errores y el mantenimiento (internamente de todos modos: justificando al PHB, no a los clientes, como usted dice que a los clientes no les importa).
Bobby Tables
55
Creo que también es una forma razonable de manejar el problema. El dolor que someten a los desarrolladores debe ser devuelto como un costo adicional. La gerencia y la fuerza de ventas también tienen que aceptar esa filosofía, de lo contrario, los desarrolladores obtendrán el eje y estarán sujetos a un empeoramiento de las bases de código.
The Tin Man
1
Ah, además: absolutamente, el ideal es la comunicación abierta y honesta. Solo sugiero un mecanismo de afrontamiento cuando eso no se puede lograr perfectamente. Es la medicina a largo plazo como un engaño.
Frank Shearar el
3
¿Es este relleno de estimación? Parece que es hora de implementar una nueva característica y mantener la calidad del código para mí.
David Thornley el
2
Creo que este es principalmente el enfoque correcto, pero lo caracterizaría de manera diferente. Lo están contratando para desarrollar un código de calidad profesional. Eso significa que debe incorporar el tiempo estimado para "hacerlo bien". No haga estimaciones basadas en el tiempo que le tomaría si se quedara despierto toda la noche pirateando y declarara "completo" tan pronto como se ejecutara correctamente la primera vez. Esto puede significar que, en una situación competitiva, a veces estará infravalorado. Está bien. Desarrollarás una reputación de ofrecer calidad y consistencia y finalmente ganarás. Juega el juego largo.
Brandon DuRette
11

Intente hacer un rediseño adecuado mientras integra nuevas características. No hay despues. Sin el rediseño, agrega constantemente más y más fricción para más cambios y nuevas características.

En algún momento, se detendrá casi por completo, donde todo parece llevar años. La mayoría de las compañías probablemente opten por la gran reescritura en este punto, la versión 2. Tiene una economía bastante pobre y es un buen momento para que su cliente pruebe una fiesta de desarrollo diferente si se siente inclinado.

El rediseño / refactorización adecuado puede proteger la inversión de sus clientes y mantener las cosas sostenibles. Necesita incorporar esto. Optimice para el cambio, viaje ligero.

Joppe
fuente
6

Con todos los comentarios sobre la sobreestimación, creo que se pierde una cantidad modesta de puntos (buena oportunidad).

No se trata de estimar el tiempo necesario para realizar el cambio (solo) y luego agregar algunos, se trata de estimar el tiempo requerido para modificar el código (¡refactorizar!) Para llevarlo a un punto donde el cambio se pueda realizar de forma segura y luego realizar el cambio cambio (probablemente algo unidas). Ok, esto equivale a lo mismo ... pero no se trata de forzar o estirar o sobreestimar, es solo una cuestión de decir que para hacer esto primero necesito hacer eso y esto es cuánto tiempo tomará en total. La clave aquí es que trabajas en aquellas partes del sistema de las que depende el cambio y no más: si hay un código horrible en otra parte ... difícil, tómalo cuando estés allí.

Volviendo un poco a la pregunta original: después de muchos años, todo se reduce a esto para mí, cuando implementas algo a menos que sepas (no creas, no esperes (¿sospechas?), No pienses pero sabes ) que cosas adicionales son también se requiere, entonces debe hacer lo que necesita para implementar ese requisito y no más de la manera más ordenada y elegante que pueda.

Cuando venga a implementar lo siguiente, un poco más tarde, tomará los pasos necesarios para llevar la base de código (y la base de datos y lo que sea) al estado necesario para implementar esa funcionalidad de la manera más ordenada y elegante posible. Esta refactorización es donde lidias con el desorden que surge naturalmente a medida que evoluciona un proyecto, y con suerte evitas crear más desorden (o al menos mantener el nivel constante).

Una de las áreas de discusión aquí es "Deuda técnica": es como un sobregiro, tiene que pagarlo y cuanto más tiempo lo deje, más intereses (en este caso, tiempo necesario para corregir) se acumularán, lo que le da un buen argumento para gastar parte de su tiempo minimizando la deuda técnica.

Aquí también es donde comienzan las pruebas unitarias y otras pruebas automatizadas (si pudiera hacerlo tan bien como digo, ¡estoy bastante seguro de que sería una persona más feliz!) Combinado con un servidor de compilación adecuado (que puede ejecutar al menos algunos de tus pruebas). Combinados con esos, pero de valor en sí mismos, hay patrones como inyección de dependencia e inversión de control (nunca estoy seguro de cuánto son "iguales" esos dos) porque hacen que sea más fácil cambiar la tubería y, por lo tanto, lidiar con los cambios en aislamiento.

Por último, recuerde, si no está roto, no lo arregle. Poner en orden su código solo por el hecho de ordenarlo puede ser satisfactorio, pero también es una oportunidad para introducir errores, por lo que puede ser doloroso si no necesita cambiarlo y no lo está construyendo, puede ser mejor dejar algunos grumos solo: ¡la oportunidad de arreglar o reemplazar llegará eventualmente!

Murph
fuente
4

1) El control de cambio adecuado es tu amigo

Si el cliente cambia la especificación que está bien, es su derecho, sin embargo, es un cambio y es necesario cobrarlo (o costarlo de cualquier manera que sea apropiada para la estructura / relación del proyecto).

La estimación de ese cambio debe incluir el costo de la refactorización necesaria . El cliente puede criticar lo que parece ser un alto costo, pero en ese momento debe explicarle que debido a que el código ya está medio escrito, hay elementos que deben reescribirse para garantizar que sea robusto y compatible en el futuro y que Si no se hace, es probable que tenga problemas en el futuro con el soporte futuro o que los cambios se vuelvan aún más caros.

2) La refactorización debe hacerse de tal manera que brinde un beneficio genuino a largo plazo para el cliente

Al considerar la refactorización, siempre debe tener en cuenta lo que realmente se necesita y lo que es importante, y asegurarse de que el trabajo de refactorización proporcione un valor genuino a largo plazo para el dinero.

Después de todo, debemos hacer estas cosas para que el código siga siendo extensible y compatible a mediano / largo plazo para garantizar que la inversión del cliente siga siendo válida en lugar de estar fuera de cualquier impulso para la perfección teórica. El trabajo de refactorización (y las estimaciones correspondientes) se debe hacer con esto como el alcance, y no solo porque ahora piensa que podría haber una forma ligeramente mejor de hacerlo.

Jon Hopkins
fuente
3

Algunos programadores sugieren que una forma de controlar ese problema con los clientes es hacer que el cliente firme y autorice la especificación inicial. ENTONCES, cuando solicitan un cambio de requisito que no está en la especificación inicial, usted les dice que necesita revisar el cronograma del contrato y del proyecto para calcular los costos adicionales y las demoras, luego haga un anexo al contrato. Aparentemente hace maravillas al evitar que los clientes insistan en nuevas características (no previstas).

Jas
fuente
2
+1; Puede funcionar, sin embargo, también corre el peligro de alienar a su cliente al ser demasiado inflexible. Hasta cierto punto, si puede hacer esto o no depende del tipo (tamaño) del proyecto y de las expectativas del cliente.
Ken Henderson el
3

Tengo el siguiente comentario en una base de código en el que estoy trabajando actualmente:

/*
 * Every time I see this function, I want to take a shower.
 */

Lo sé, muy bien la situación que estás describiendo. Lo que hago es tratar (lo mejor) de esperar hasta que las cosas se calmen y cualquier tipo de 'arrastramiento' haya 'arrastrado' todo lo que va a hacer. Para ese momento, es probable que haya lanzado algo utilizable, y puede tomarse un tiempo para limpiar las cosas e implementar cosas de manera un poco diferente.

No se puede correr limpiando muchos pequeños líos repetidamente. Eso simplemente triplica tu trabajo y tu frustración. Espere a que se convierta en uno más grande, pero apenas mueve el desorden y luego puede hacer algo al respecto.

Tim Post
fuente
2

Mi preferencia es evitar esta situación en primer lugar.

Todo depende de CÓMO leas las especificaciones. Es fácil pensar en ellas como tabletas de piedra, pero en realidad la mayoría de las especificaciones cambian. Cuando diseñe su código, vea la probabilidad de que cada parte de la especificación vaya a cambiar. Con el tiempo, se volverá bastante bueno para predecir esto.

Habiendo metido en el lío, la experiencia y el juicio son muy importantes. ¿Estás escribiendo nuevos errores debido a este código de espagueti? ¿Está tardando más en implementarse? estos apuntarían a hacer un refactor táctico.

para el futuro, parece que necesita trabajar en asociación con su cliente. Diciéndoles, "miren, este producto se está expandiendo significativamente más allá de la especificación original. Si bien el diseño original era bueno para ese nivel, expandirlo en la dirección X y las direcciones Y necesitan algo de reestructuración en el diseño" se manejó bien, e incluso obtendrá su cliente para pagarlo.

Michael Shaw
fuente
No sé si los consideraría "errores" o no. Estoy haciendo algunos grandes cambios, y naturalmente todo comienza a desmoronarse cuando comienzas a arrancar los cimientos. Sin embargo, todo se puede arreglar. Le recuerdo a mi cliente los costos de hacer cambios como este de manera regular, pero él quiere "estimaciones" inmediatas que simplemente no puedo dar. El estacionamiento de pelotas ni siquiera es posible hasta que realmente pienses en todos los cambios de diseño que necesitas hacer, pero él simplemente no entiende eso. De todos modos, está pagando, y no se queja demasiado.
mpen
2

Cobra por hora y si quiere cambios diga que está bien, pero incorpore el tiempo requerido para escribir un buen código en la ecuación. También recuerde que escribir código ordenado vale la pena a largo plazo cuando tiene que mantenerlo. Ahorrar tiempo ahora podría costarle más tarde.

Craig
fuente
Cobro por hora, pero la cuestión es que, incluso cuando me tomo el tiempo de escribir "buen código", se vuelve obsoleto tan rápido que me pregunto si hay algún punto. Creo que estoy agregando costos limpiando constantemente antes de que el proyecto se haya estabilizado.
mpen
1

Creo que escribir software debe ir de la mano con las necesidades del negocio. Si se trata de un proyecto descartable (como un prototipo que debe construirse en una semana, con nuevas entradas que llegan todos los días), entonces no hay necesidad de preocuparse por el mantenimiento del código y otras cosas: el tiempo es crucial y solo necesita empuje su código fuera de la puerta lo más rápido que pueda.

Pero si está escribiendo una aplicación a largo plazo, entonces tiene sentido considerar todo esto, porque hay un impacto considerable en el tiempo que lleva construir nuevas funciones, corregir errores existentes, integrarse en otras aplicaciones y otras cosas, y Esto se traduce en un impacto comercial (debido a que se requiere más tiempo más adelante y más costos).

Por lo tanto, es mejor sensibilizar al tomador de decisiones sobre los costos reales de no refactorizar el código siempre que sea necesario; en mi experiencia, si los costos y el impacto temporal de ambas opciones se explican en términos mensurables para el propietario de la decisión, entonces la decisión puede ser una decisión pan comido. No esperes que la gente te diga 'sí, adelante, escribe un código hermoso, a pesar de que toma el doble de tiempo y no me da ningún beneficio adicional'. Simplemente no funciona de esa manera.

Roopesh Shenoy
fuente
1

Hágalo parte de su proceso, lo llamo "refactorización extrema" y ¡será grande! ;) Simplemente haga las cosas rápidamente y cuando se hayan agregado suficientes características nuevas de tejido cicatricial, refactorícelo. Pregúntese continuamente "Ahora, si hubiera comenzado desde cero, ¿cómo lo habría hecho?"

Las personas que piensan que pueden diseñar y pensar en todo por adelantado se engañan a sí mismas, usted (y su cliente) siempre aprenden cosas a medida que avanzan. Usa esas lecciones.

Como eres un buen programador, podrás refactorizar bastante rápido y, a medida que lo hagas continuamente, el código comenzará a tomar su "forma adecuada", lo que significa que se volverá más flexible con menos dependencias.

Los clientes podrían sentirse molestos si supieran que está "perdiendo el tiempo" reelaborando cosas, por lo que ayuda a no preguntar / contar y ser realmente rápido al respecto.

El código desarrollado de esta manera le ahorrará mucho tiempo al final y facilitará cada vez más agregar nuevas funciones.

También diría que una de las principales razones del mal código es el miedo que algunos programadores tienen a hacer una refactorización estructural más grande, y cuanto más esperes, peor será.

rev konrad
fuente
1

Confíe en un poder superior

No me refiero a rezar. Quiero decir, asegúrese de que haya un hombre de negocios (es decir, gerente de proyecto o equivalente) que pueda colocar como relleno entre usted y el cliente. Si el cliente exige demasiado, deje que el hombre de negocios ponga el pie y esté listo para manejar "es factible, pero no estoy seguro de si eso se ajusta al alcance de la especificación, vea [hombre de negocios]".

En un flujo de proyecto normal, la especificación general debe congelarse antes de que tenga lugar un desarrollo serio.

Muchos clientes continuarán impulsando cambios / mejoras / mejoras siempre que lo permita. Muchos abusarán al máximo de esa capacidad porque les hace sentir que están aprovechando al máximo su dinero (incluso si sabotea su proyecto).

Haga que una persona se dedique a perfeccionar y congelar la especificación desde el principio y aplicarla más adelante.

No hay nada de malo en hacer un poco más por un poco de buen karma con el cliente, pero prepárate para diferir a un poder superior cuando se salga de control. Si la especificación requiere una cantidad ridícula de cambios, tal vez sea hora de volver al ciclo comercial y reevaluar el contrato y / o agregar adiciones al contrato (con una compensación monetaria justa).

El hecho de que tenga este problema tiene poco que ver con la forma en que codifica. Es una señal de que su gerente de proyecto está infrautilizado en el proyecto (ya sea por su culpa, por su culpa o por ambas).

Como otros han dicho en muchas respuestas, también es necesario agregar un búfer de tiempo para contingencias en cualquier proyecto, pero determinar eso debe decidirse a puerta cerrada antes de que la especificación sea congelada y entregada al cliente por el PM.

Evan Plaice
fuente
0

El diseño inicial adecuado no puede ayudar a evitar el problema. Y es casi imposible (o muy, muy difícil) considerar todos los requisitos futuros "quizás". Entonces, después de algún tiempo, llegará el Big Re-factoring. Y la mejor solución es reescribir todo.

En pocas palabras: en lugar de colocar una torreta en el Ferrari rojo, reconsidere los requisitos y construya un tanque.

duros
fuente
0

Mátalo con fuego.

También refactorice lo antes posible: por ejemplo, cuando el código feo proviene de apresurarse para una fecha límite, refactorizaría después de la fecha límite porque no puede (o no debería al menos) agregar más funciones hasta que el código existente sea mantenible, de lo contrario va a hacer que sea mucho más difícil depurar códigos futuros.

picos salvajes
fuente
0

Escriba pruebas unitarias para sus proyectos que prueben el estado actual y luego refactorice cuando tenga tiempo, de esta forma evitará romper su proyecto mientras intenta limpiarlo.

chiurox
fuente
0

La respuesta más simple. Dejaría de codificar de cualquier tipo, hasta que tenga una especificación final de exactamente lo que quiere a partir de ahora.

Luego, deben priorizar esa lista de características, etc., para confirmar qué elementos deben tener en este momento y cuáles se pueden hacer más adelante ...

Usando sus experiencias para determinar cuál es el tiempo / costo de cada función, y luego decirles, si lo desean, tomará x cantidad de tiempo y dinero.

Estás lidiando con el gran crimen del arrastre de alcance de funciones, y seguirán agregando funciones sin cesar, hasta que nunca se haga nada o se haga tan mal.

Dígales una vez que tenga una lista final, que hará modificaciones futuras, como prefieran, pero que deben centrarse en el 15/20 más importante que deben tener ahora.

Luego, según el tiempo de finalización, dígales que después de que se haya publicado esto, estará abierto a discutir / intercambiar ideas sobre la próxima versión.

Una vez que se ha tomado una decisión final sobre lo que se debe hacer para la versión actual, todas las discusiones / ideas / sugerencias deben detenerse al 100%.

Si tiene ideas infinitas, dígale que las escriba en su lista de características para la próxima versión, y que le permita concentrarse en ofrecer las características más importantes que desean en este momento.

Si continúan malgastando tu tiempo, cambia de opinión. Entonces simplemente dejaría de trabajar en el proyecto, y trabajaría en otros proyectos, hasta que hayan finalizado sus decisiones

Es difícil de hacer, pero el arrastre del alcance de la función es tan destructivo para el tiempo, la energía, la motivación y el pensamiento claro.

crosenblum
fuente
0

Desde una perspectiva completa del proyecto:

Aprenda del código con su equipo, vea qué se puede refactorizar y reutilizar la próxima vez, luego vaya a tomar una cerveza.

Desde una perspectiva en desarrollo:

Explique pacientemente por qué se detuvo el desarrollo y explique por qué no puede continuar hasta que todas las especificaciones estén sobre la mesa y se entiendan. Entonces, ve a tomar una cerveza.

Desde una perspectiva de planificación:

Solicite todas las especificaciones por adelantado y trabaje con todos para tener una comprensión clara de la ruta de desarrollo. Involucre al cliente / partes interesadas lo más cerca posible para asegurarse de que todos estén en la misma página. Más tarde esa noche, consiga cervezas para todos. Mañana comienza el proyecto.

Kevin
fuente