¿Cómo se pasa de un programa en desarrollo a un lanzamiento?

67

En algún momento se está desarrollando un programa. Las características se agregan o eliminan o cambian todo el tiempo. Cada versión no es más que un prototipo. Entonces no pierdo mucho tiempo escribiendo código súper limpio en ese punto porque nunca sé cuánto dura algo. Por supuesto, trato de mantener la calidad del código a ciertos estándares, pero el tiempo siempre es un problema.

Luego llega el punto en el que finaliza el programa y los tomadores de decisiones dicen "eso es todo". Tengo un prototipo que funciona en este momento, pero el código interno es un poco desordenado de un lado a otro durante la fase de desarrollo. Se espera que comience a probar / depuración final, pero mi instinto dice que ahora debería de alguna manera limpiar y reescribir cosas para darle una arquitectura adecuada que facilite el mantenimiento, etc.

Una vez que las cosas han sido probadas y aprobadas, no tiene sentido volver a escribirlas. De manera regular, estoy parado allí con un prototipo 'terminado' que funciona y recibo un error durante las pruebas y veo que es el resultado de una codificación no inteligente que es el resultado de todo el proceso de desarrollo. Estoy en medio de las pruebas y la corrección de errores sería una reescritura ... ¡es un desastre!

Hay mejores formas de libros de texto, estoy seguro. Pero tengo que trabajar en un entorno de trabajo real donde no todo es un libro de texto.

Entonces, ¿cómo paso mi prototipo de trabajo a una versión de lanzamiento con una base de código estable? Tal vez no debería considerar el desarrollo terminado una vez que lo hago y realmente verlo como la fase de limpieza ... No sé, necesito ayuda aquí.

EDITAR

Quiero aclarar algunas cosas.

  • Estoy 100% en el lado de hacerlo justo antes y no después, código limpio y legible. Pero también tengo que hacer las cosas y no puedo soñar con la belleza del código, todo limpio y brillante. Tengo que encontrar un compromiso.

  • a menudo, una nueva característica es realmente algo que queremos probar y ver si tiene sentido implementar algo como esto. (especialmente en aplicaciones móviles, para obtener una apariencia real en un dispositivo real). Por lo tanto, es algo pequeño que (en mi humilde opinión) no justifica demasiado trabajo en una primera iteración de "veamos". Sin embargo, a veces surge la pregunta ¿CUÁNDO pago esta deuda técnica? De eso se trata esta pregunta.

Si sé que la mitad de las funciones se eliminarán un día más tarde (suficiente experiencia en nuestra empresa por ahora), realmente me cuesta creer que la mejor manera de abordar mi problema es sin embargo invertir tiempo extra para escribir todo limpio, incluso si la mayor parte se eliminará poco después. Me parece que ahorraré tiempo si hago una gran limpieza una vez que la cosa sea sólida, de ahí mi pregunta.

NikkyD
fuente
68
Su pregunta es "Me metí en un agujero; ¿cómo salgo?" La respuesta estándar es, por supuesto, el primer paso, DETENER LA EXCAVACIÓN MÁS PROFUNDA. Su proceso de desarrollo se puede resumir como "generar enormes cantidades de deuda técnica y luego ignorarlo cuando venza". Si esto es un problema, cambie sus procesos de desarrollo. Solo verifique el código limpio, funcional, depurado y cuidadosamente revisado que cumpla con sus especificaciones escritas cuidadosamente. No se endeude y no tendrá que salir de la deuda.
Eric Lippert
11
@NikkyD Si no se le da el tiempo para una implementación adecuada, debe conversar con su gerente sobre el impacto en la calidad del software. Comprenda lo que todos aquí le están diciendo: no invertir el tiempo por adelantado está dañando su capacidad de trabajar eficientemente más adelante. Otro problema que desea plantearles: si abandonara la empresa (o "lo atropellara un autobús"), sería extremadamente costoso para los nuevos desarrolladores familiarizarse con el código. El dinero que creen que están ahorrando ahora les costará más tarde.
jpmc26
32
Si está haciendo una pequeña rama de características para simular una interfaz de usuario propuesta para una característica, eso es genial. Hazlo tan rápido y sucio como quieras, muéstralo al cliente y luego elimina esa rama . Cuando los fabricantes de automóviles fabrican automóviles con arcilla y papel para simular un nuevo diseño, no intentan poner un motor en el modelo de arcilla. El proceso para determinar si vale la pena hacer la función debería ser barato. Una vez que haya decidido hacer la función, asegúrese de comenzar desde un código limpio y siempre producir código limpio, porque ese código ahora es código de producción .
Eric Lippert
10
"No puedo soñar con la belleza del código, todo limpio y brillante" Este es un malentendido fundamental de lo que significa "código limpio". El código limpio no significa que pases una tarde haciendo que tus pestañas se alineen para que puedas imprimir el código y enmarcarlo. El código limpio es un buen código y un buen código es un código limpio. El código limpio es un código que funciona correctamente, se puede depurar y se puede entender. Si no tiene tiempo para escribir código limpio desde el principio, definitivamente no tiene tiempo para escribir código desordenado y luego también arreglarlo más tarde. Eso es lo que dura la tarea.
GrandOpener
8
"También tengo que hacer las cosas y no puedo soñar con la belleza del código, todo limpio y brillante. Tengo que encontrar un compromiso". Un compromiso significa un término medio que es "suficientemente bueno" para ambas partes. Si su código es desordenado, particularmente si es lo suficientemente desordenado como para pensar que tendrá problemas para mantenerlo, entonces eso no es "lo suficientemente bueno" y necesita encontrar un mejor compromiso.
anaximander

Respuestas:

98

Entonces no pierdo mucho tiempo escribiendo código súper limpio en ese punto porque nunca sé cuánto dura algo.

No saber cuánto dura algo nunca debería ser una excusa para descuidar, todo lo contrario. El código más limpio es en mi humilde opinión el que no se interpone en tu camino cuando tienes que cambiar algo. Entonces, mi recomendación es: siempre trate de escribir el código más limpio que pueda, especialmente al codificar un prototipo. Porque será mucho más fácil adaptarlo cuando haya que cambiar algo (lo que seguramente sucederá).

No me malinterpreten: mi comprensión del "código más limpio" no tiene nada que ver con hacer que el código sea hermoso por el bien de la belleza. Eso es de hecho algo que puede ralentizarlo. En mi punto de vista, el código limpio es un código que se explica principalmente por sí mismo (no es necesario escribir tantos documentos, provoca una aceleración), fácil de entender (menos errores, por lo que se necesita menos depuración, aceleración, menos tiempo necesario para encontrar el correcto lugar para alterar - acelerar), resuelve el problema dado con la menor cantidad de código necesario (menos código para depurar - aceleración obvia), es SECO (solo un lugar para cambiar cuando algo tiene que cambiar - acelerar - y menos riesgo de introducir nuevos errores al olvidarse de cambiar un segundo lugar), sigue los estándares de codificación (cosas menos engorrosas en las que pensar: acelerar), usa pequeños,

Se espera que comience la prueba / depuración final, pero mi instinto dice que ahora debería de alguna manera limpiar y reescribir cosas para darle una arquitectura adecuada que facilite el mantenimiento, etc.

Hacer "limpieza" después nunca funciona. Considere su limpieza antes de implementar una nueva característica, o cuando comience a implementarla, pero no después. Por ejemplo, cada vez que comience a tocar un método para una función, y observe que tiene más de 10 líneas, considere refactorizarlo en métodos más pequeños, inmediatamente , antes de completar la función. Siempre que detecte una variable existente o nombre de función que no sabe exactamente lo que significa, averigüe para qué sirve y cambie el nombre de la cosa antes de hacer cualquier otra cosa. Si hace esto regularmente, mantiene su código al menos en un estado "suficientemente limpio". Y comienza a ahorrar tiempo , porque necesita mucho menos tiempo para la depuración.

Estoy en medio de las pruebas y la corrección del error sería una reescritura

... que es la prueba real de lo que escribí anteriormente: estar "sucio" te persigue inmediatamente cuando comienzas a depurar tu código y te hará más lento.

Puede evitar esto casi por completo si realiza la limpieza de inmediato. Luego, las correcciones de errores significarán principalmente pequeños cambios en el código, pero nunca un cambio arquitectónico importante. Si realmente detecta evidencia de una mejora arquitectónica durante las pruebas, retrasarla, incluirla en su sistema de seguimiento de problemas e implementarla la próxima vez que tenga que implementar una función que se beneficie de ese cambio ( antes de comenzar con esa función).

Esto requiere algo de disciplina y algo de experiencia en codificación, por supuesto. Es una idea similar a la idea detrás del "desarrollo impulsado por pruebas", hacer estas cosas de antemano en lugar de hacerlo después (TDD también puede ayudar, pero lo que escribí funciona incluso cuando no usa TDD). Cuando haga esto en consecuencia, no necesitará ninguna "fase de limpieza" especial antes de la liberación.

Doc Brown
fuente
40
@NikkyD Las sugerencias hechas por Doc Brown son hábitos que en realidad disminuyen el tiempo necesario y son muy realistas a largo plazo. Piense cuánto tiempo ahorra si no necesita examinar su código para descubrir cómo no romperlo cada vez que necesita cambiarlo . Las ganancias son similares a cambiar de mecanografiar "cazar y picotear" a aprender a teclear. Inicialmente, puede llevar más tiempo, ya que está aprendiendo, pero una vez que el hábito está ahí, es indudablemente mejor y lo beneficiará por el resto de su carrera. Si elige no intentarlo, nunca llegará allí.
Daniel
44
@NikkyD: No aumenta el plazo. El plazo ya estaba hinchado; simplemente no tuvo en cuenta la hinchazón cuando escribió el software y se endeudó técnicamente para lo que no había presupuestado.
Eric Lippert
77
@NikkyD: Te presento el ídolo con pies de arcilla y el concepto de deuda técnica . Lo primero significa que puede construir software de sonido sobre bases inestables, lo último es sobre el "interés" (costo agregado) experimentado por las características que intenta agregar cuando la estructura no es sólida.
Matthieu M.
10
@NikkyD: no, sugiero escribir su código de forma similar a cómo un experto en billar juega sus bolas: cada disparo parece simple para el extraño, ya que después del disparo las bolas se detienen en posición para un nuevo "disparo simple". Y en billar o codificación, esto lleva algunos años de práctica ;-)
Doc Brown
16
@NikkyD: según mi experiencia, cuando "agregar una pequeña característica requiere mucha refactorización", el código ya es un desastre, y la necesidad de "mucha refactorización" proviene del hecho de que necesita cambiar una función o clase que hizo No mantener lo suficientemente limpio en el pasado. No dejes que las cosas lleguen tan lejos. Pero si estás en esa situación, busca un compromiso. Al menos siga "la regla de boyscout" y deje el código en un mejor estado que antes de agregar la función. Entonces, incluso si la función se eliminó la próxima semana, el código debería estar en mejor forma que antes.
Doc Brown
22

Tiene dos problemas separados, ambos con el mismo síntoma (código descuidado):

Problema n. ° 1: Control de requisitos insuficiente No quiero decir que sus partes interesadas cambien sus requisitos con demasiada frecuencia, quiero decir que está permitiendo cambios de requisitos durante un ciclo de corrección de errores / prueba. Incluso las metodologías ágiles no son compatibles con eso; construyes, pruebas, entregas, inyectas nuevos requisitos.

Problema n. ° 2: Usted cree que lo que está escribiendo es "solo por ahora" En el desarrollo de software "solo por ahora" el código es realmente extremadamente raro. Te has dado cuenta de que una vez que cumples con los requisitos de un usuario, los rigores de la oferta y la demanda hacen que sea muy difícil justificar el regreso y volver a implementar una función "listo". Entonces, ¿qué hacer al respecto? Siempre escriba el código de producción. Funcionalmente para usted, eso significa que sus estimaciones para sus grupos de interés deben ser sustancialmente mayores para que tenga algo de tiempo para hacerlo correctamente.

Además, comprenda que está trabajando en la posición más difícil como desarrollador: lea la versión de Joel Spolsky sobre la vida de un desarrollador interno . Por lo tanto, debe estar extra vigilante si quiere lograr que su cordura esté intacta.

Gus
fuente
21

Es un problema común, especialmente cuando se crea lo que es esencialmente un globo de prueba de software , por así decirlo .

Hay varios enfoques que pueden ayudar. En primer lugar, el enfoque TDD puede ayudar a reducir la base del código a lo estrictamente necesario. Si sus pruebas van de la mano con su código, entonces al menos puede tener cierta confianza en que su código se comportará como debería.

Tómese el tiempo para refactorizar a medida que avanza. Una vez que tiene un prototipo y el cliente está muy ansioso por tenerlo en sus manos, es difícil decir que necesita tiempo para pulir qué (para ellos) está completo. Me gusta registrarme diariamente seguido de un registro de refactorización pero YMMV.

Los desarrolladores que escriben código rápidamente a menudo tienen demanda: tuvimos un desarrollador de este tipo en mi último departamento. Todos los equipos lo querían porque trabajaba muy rápido. Sin embargo, una vez que llegó el momento de probar y liberar su código, las ruedas se soltaron rápidamente. Cosas codificadas, trucos y atajos por todas partes. Su stock pronto cayó, masivamente.

Cortar el código de producción desde el principio puede parecer una molestia, pero dependiendo de su entorno, hay muchas herramientas que pueden ser difíciles de desarrollar, como Ghostdoc y Stylecop .

Vale la pena tener una mentalidad de desarrollo correcta desde el principio. Se sorprendería de la cantidad de sistemas de paquetes que se suponía que eran solo soluciones intermedias que se convierten en aplicaciones fundamentales.

Robbie Dee
fuente
Te refieres a todas las soluciones stop gap jamás escritas, ¿verdad?
RubberDuck
44
Un gran punto sobre la justificación para el cliente. Tengo mucha experiencia con clientes que piensan que cuando la GUI parece completa, la aplicación también está lista. Aprendí a hacer que la GUI pareciera incompleta mientras el código en segundo plano aún no está listo y, en consecuencia, solo hago que lo que el cliente ve parezca pulido cuando el código (y la lógica comercial) lo está. Es muy difícil explicar que lo que parece terminado para el cliente aún tardará un mes o dos en entregarse.
Luaan
11

Continuamente

La velocidad de desarrollo es la razón principal para escribir código limpio, legible y comprobable; No se hace por belleza, ni por otros valores abstractos. ¿Por qué me lo negaría a mí mismo y solo lo haría después para algún futuro programador?

Claro que puede haber cambios que son principalmente cosméticos y, por lo tanto, no esenciales; Yo diría que es mucho más útil tener un código moderadamente bueno en este momento, durante el desarrollo, que tener un desorden en este momento y esperar hacerlo perfecto más tarde (lo cual, admitámoslo, nunca va a suceder, incluso si tuvieras el tiempo).

Thanos Tintinidis
fuente
66
+1 y desde un punto de vista personal, me resultaba demasiado difícil cambiar los engranajes de hackear proyectos personales en casa y escribir código de producción en mi trabajo diario. Escribir código profesional en mis proyectos de pasatiempo pagaba dividendos inmediatos: el código era más fácil de leer y había muchos menos errores.
Robbie Dee
Una razón por la que nunca va a suceder es que usted (mejor) mejora en lo que hace con el tiempo. Por lo tanto, si espera medio año para "limpiar" algo, no solo olvidará todos los minutos necesarios para hacer la limpieza de forma segura, sino que también será un mejor programador que antes y es probable que se sienta tentado simplemente tirar todo y comenzar de nuevo. Y dado que es mucho trabajo (y a menudo es una mala idea de todos modos), probablemente solo omita la limpieza nuevamente.
Luaan
"¿Por qué me lo negaría a mí mismo y solo lo haría después para algún futuro programador?" ¡Revelación! ¿Y adivina qué? A veces (y a veces, a menudo) eres ese futuro programador.
radarbob
@RobbieDee, observación superlativa! En una entrevista, Malcom Gladwell, el tipo que trajo la "regla de las 10.000 horas" a la conciencia popular (en el libro Outliers ), dijo que debe ser una "práctica deliberada" o simplemente está perdiendo el tiempo. Significa centrarse en la mejora, practicar detalles específicos con la intención de mejorar ese aspecto específico de una habilidad, etc.
radarbob
@ThanosTintinidis, luego está el problema de "ninguna buena acción queda sin castigo". Habiendo escrito un código tan limpio, inevitablemente alguien lo arruinará. Asegúrese de ser el revisor del código cuando alguien más toque su código limpio. Un método simple agregado sopló la encapsulación y la coherencia que incluso se documentó en línea . Estuve furioso por una semana; y un año después, cada vez que veo ese código.
radarbob
4

Para ello, diferencie entre el código "Solo intento hacer esto para ver cómo funciona" y el código "esto se dirige al producto". Hay varias formas de hacerlo.

Una es la ramificación o la palabra que se encuentre en su sistema de control de fuente. Crea una rama para el nuevo informe o el nuevo diseño de importación o lo que sea. Si a la gente le gusta, el trabajo de regresarlo a la rama principal es un trabajo separado y rastreable. Puede asignarse a alguien e informarse y no se espera que ocurra mágicamente el día en que la administración (o las ventas) acuerdan que la característica pertenece al producto.

Otro son los picos. No haces ese cambio en el producto. Entras en una aplicación separada, súper simple, que existe solo para que tengas un lugar para poner el código. Puedes ser tan desordenado como quieras porque solo estás explorando la nueva API o lo que sea. Y nuevamente, si regresa e informa "sí, podemos hacer eso, he descubierto cómo" hay una tarea rastreable, reportable y asignable de escribir código listo para el producto en el producto para hacer lo que desea.

En ambos casos, listo para el producto significa legible, ordenado, siguiendo los estándares de nomenclatura, con pruebas y cumpliendo con su estilo de código y objetivos de rendimiento. En ambos casos, haces que el trabajo sea visible. Estoy de acuerdo en que no desea hacer todo ese trabajo cada vez que es muy probable que alguien retire la función del producto. Pero tampoco quieres dejar que ese trabajo se vuelva invisible. Trabajar en copias separadas del producto o en un producto no relacionado que es apenas más que un arnés de prueba le permite sacar a la superficie el trabajo para crear un código listo para el producto una vez que alguien decide que quiere algo.

La desventaja es que no pueden decidir que quieren algo y enviarlo (es decir, la versión a medias, desordenada, no probada, indocumentada y posiblemente lenta que ha implementado como prueba de concepto) mañana. La primera vez que obtiene retroceso en ese frente, simplemente pregunte si debe hacerlo de la manera larga (más costosa) cada vez por si acaso, ralentizando el camino hacia las características rechazadas. Si pregunta correctamente, obtendrá un "no".

Kate Gregory
fuente
1

Realmente creo que ya entiendes el problema. El problema es que su estilo de codificación requiere que realice demasiadas modificaciones. La razón por la que necesita demasiada revisión es porque (a) se combina con una previsión y planificación insuficientes y (b) los parches incrementales a corto plazo que se colocan regularmente durante el desarrollo aumentan de manera combinatoria la complejidad de cualquier revisión requerida.

La respuesta por lo tanto, es

(a) cambie su estilo de desarrollo un poco más hacia la cascada y un poco menos ágil. Sin embargo, no vayas hasta el final, porque la cascada clásica tiene sus propias trampas. Hay un equilibrio saludable para tener. Sé que puede ser preocupante solo pensar en cosas durante unos días a veces, como si no se hiciera ningún desarrollo, pero tienes que confiar en el proceso. En ingeniería no puedes simplemente unir las cosas y luego clavarlas en la parte superior y esperar obtener una solución elegante. Si no hay nadie haciendo arquitectura y diseño técnico de alto nivel, eso significa que es su trabajo. Has estado pagando el precio de descuidar ese trabajo.

(b) trate de evitar parchear las cosas. No piense a largo plazo solo cuando llegue el momento de realizar el control de calidad. Realmente deberías probar cada pequeña pieza que construyes, todo el tiempo, y cubrir todos los casos de entrada, aquellos que no están en el camino feliz también. Un parche / pirateo es casi por definición una solución a corto plazo, que bien puede tener un costo a largo plazo, afecta al costo total de propiedad del cliente en el sistema. Una vez más, la presión está por sacar el código, por lo que tiene que haber equilibrio. Pero trate de no implementar soluciones a corto plazo, especialmente. aquellos que acoplan firmemente componentes que realmente deberían estar acoplados sin apretar. Habrá un nuevo trabajo, así que hágalo TEMPRANO para hacerlo mucho más fácil, para evitar los hacks y parches que se acumularán con el tiempo y se volverán inmanejables.

Brad Thomas
fuente
2
Solo una nota: ágil no significa "cambios frecuentes sin pensar" o "menos diseño". De hecho, encuentro que ágil requiere mucho más diseño que lo que la gente llama comúnmente cascada. La falta de un buen diseño es una de las razones por las que la cascada no funciona bien en la práctica: si realmente invierte en el diseño correctamente, funciona bien; simplemente también se vuelve mucho más caro que ágil. Si omite la parte de diseño de forma ágil, solo está golpeando el código de una manera a otra, y eso no funcionará mejor que cualquier otra práctica que evite el diseño.
Luaan
El enfoque ágil en iteraciones cortas, sprints, etc., para obtener prototipos rápidamente, necesariamente ejerce más presión para descuidar el diseño suficiente por adelantado
Brad Thomas
No, se enfoca en diseñar piezas más pequeñas. Pero en general, debes diseñar mucho, de lo contrario solo vas a producir un producto horrible. La clave es hacer las cosas pequeñas y bien diseñadas, así como intercambiables. Si diseñas menos ágilmente, te estás perjudicando a ti mismo (y a tus clientes). Las iteraciones cortas son el beneficio de usar ágil, no el requisito previo o solo parte del proceso: una vez que obtienes todo lo suficientemente bueno, de repente puedes permitirte las iteraciones cortas, no al revés.
Luaan
Poner más énfasis en el diseño de piezas más pequeñas es un problema importante, cuando realmente la imagen más grande es comúnmente la causa más importante de reelaboración. He visto mucho más dinero desperdiciado en el negocio de repente diciendo "pero lo necesitamos para hacer esto", que requiere una revisión más amplia de lo que jamás haya visto en el cambio de un diseño de un pequeño componente suelto
Brad Thomas
Sí, pero en ese punto ya has perdido (e independientemente de si estabas intentando ágil o cascada). Cuando su "panorama general" se compone de muchas partes pequeñas que están relativamente aisladas, la única revisión amplia que obtiene es cuando necesita reemplazar casi todo. ¿Qué enfoque no te hace perder todo cuando necesitas comenzar desde cero? Incluso los niveles de diseño de la NASA conducen de vez en cuando a "necesitamos cambiar todo". Al mantenerse flexible y adaptable, obtiene más espacio de maniobra para acomodar los cambios, pequeños o grandes.
Luaan
0

Usted escribe:

Cada versión no es más que un prototipo. Entonces no pierdo mucho tiempo escribiendo código súper limpio en ese punto porque nunca sé cuánto dura algo. ...

Luego llega el punto en el que finaliza el programa y los tomadores de decisiones dicen "eso es todo". Tengo un prototipo que funciona en este momento, pero el código interno es un poco desordenado de un lado a otro durante la fase de desarrollo.

Una versión registrada puede ser un "prototipo" ya que pierde características o algunas características no se desarrollan, pero todo el código registrado debe ser un código de calidad de producción que no necesariamente necesita limpieza.

Creo que estás posponiendo tu "limpieza" demasiado.

Mi regla de oro es:

  • Comience con la función (sub)
  • siéntase libre de escribir cosas incompletas e incompletas, tal vez algunos c & p para tener una idea de lo que estoy implementando o si tengo que rascar las últimas horas de codificación (tenga en cuenta que esto puede ir de la mano con TDD / pruebas, es solo que todo se atenúa un poco para obtener una respuesta rápida del espacio de implementación que estoy explorando)
  • La subfunción "funciona" lo suficientemente bien por ahora
  • Ahora haga la limpieza: antes de una confirmación SCC .
    • Mira el código para ver qué es obvio
    • Haga una diferencia con el último compromiso para revisar los cambios y tal vez detecte algunos problemas
    • Arreglar cosas que anoté en mi bloc de notas
  • Ahora hago el commit: esta calidad de código está lista para enviarse

En este punto, el código comprometido aún puede contener algunas soluciones o "deudas técnicas" que sería bueno limpiar, y tal vez lo limpie cuando sea lo natural para una siguiente subfunción, pero estará bien si ese código se libera tal cual.

Martin Ba
fuente