Seis días para cambiar una línea de código (2015)
(edw519.posthaven.com)- Cuando la utilización de la planta bajó un 10%, la empresa intentó acumular inventario antes de la temporada alta en vez de despedir personal, y para eso comenzó una solicitud para cambiar el límite de backlog de 3 meses a 4 meses
- El responsable de IT pensó que bastaba con cambiar un solo valor hardcodeado en una rutina crítica, pero primero hubo que crear el ticket, describir el impacto de negocio, obtener aprobaciones y ajustar la prioridad en la cola
- El programador cambió el valor
MonthsOfBacklogde"3"a"4"en la línea 1252 del módulo ORP572 y pasó las pruebas, pero en la revisión de código también le exigieron corregir violaciones previas de políticas - El alcance del cambio creció con procedimientos secundarios como convertirlo en un registro del archivo Parameters, quitar comandos de depuración, advertencias por variables no asignadas, un Employee ID hardcodeado, permisos de acceso, entorno de pruebas, plan de pruebas y firma del usuario
- Aunque el cambio necesario para el negocio era de 1 línea y 1 byte, el tiempo total transcurrido fue de 6 días, y los procedimientos internos y las políticas aumentaron mucho el lead time real de un cambio pequeño
Solicitud para cambiar el límite de 3 meses a 4 meses
- El presidente Philip dijo que la planta estaba con un 10% de inactividad y quería producir más backlog para acumular inventario antes de la temporada alta, en lugar de despedir personal
- Lee, gerente de operaciones, explicó que según la política de la empresa solo se podía generar backlog para 3 meses, así que si el límite subía a 4 meses habría trabajo suficiente
- David, responsable de IT, consideró que probablemente bastaba con cambiar una sola línea de código en una rutina crítica del software legado, y pidió que se enviara un ticket a IT Services
- Judy, gerente de IT, asignó la solicitud como
Ticket# 129281, pero dijo que hacía falta completar la sección Business Impact y obtener la aprobación de un Director- Cuando David mencionó la posibilidad de despidos, Judy llenó ella misma esa sección y la elevó para atención rápida
- Dos días después, la solicitud seguía en la Developer Queue como el primer Enhancement detrás de 14 Bug Reports
- David marcó la solicitud como urgente y ordenó que se la enviaran directamente a Ed
Cómo un cambio de una línea termina convirtiéndose en un cambio de proceso
- Ed cambió la variable hardcodeada
MonthsOfBacklogde"3"a"4"en la línea 1252 del módulo ORP572- Pasó la prueba unitaria y ejecutó 2 pruebas batch
- La cola de trabajo de Operations aumentó el 10% como se esperaba
- El cambio pasó a Code Review y a User Acceptance Testing con Homer
- Shirley, encargada de la revisión de código, exigió que la variable hardcodeada se convirtiera en un registro del archivo Parameters porque iba contra la política de la empresa
- También dijo que antes de pasar a producción había que corregir 2 comandos Debug existentes, una advertencia por variable no asignada y un Employee ID hardcodeado
- Su postura era que, como a Ed le habían asignado ORP572, también debía hacerse responsable de errores previos que violaban la nueva política de la empresa
- El entorno de pruebas también se volvió un factor de retraso
- Homer no estaba disponible por pruebas de control del cierre contable de fin de mes, así que hubo que usar a Marge
- Ed no tenía permisos de acceso a Marge, y Joe de IT Security dijo que no podía dárselos sin la firma de David
- El trabajo del registro en Parameters se amplió con requisitos adicionales
- Hacía falta un nombre mejor porque
MonthsOfDemandsería difícil de entender para programadores extranjeros - El nuevo registro de Parameter debía tener auditoría, pero esa política no estaba documentada y la actualización del wiki ya llevaba 3 meses de retraso
- Ed cambió el nombre a
SelectedMonthsOfBacklogDemandy agregó el módulo PAR634 para mantener ese registro y su auditoría
- Hacía falta un nombre mejor porque
- Tony, encargado de pruebas, señaló que
129281aparecía en Marge pero que no había Test Plan- Ed dijo que bastaba con ejecutar la versión anterior y la nueva y confirmar que aumentara el total del reporte
WorkOrdersHours, pero Tony exigió Test Cases seleccionados por el usuario, Expected Results, Test Runs documentados y sign-off del usuario porque afectaba a toda la planta - Dos días después, Philip le ordenó a David que hiciera que Tony pasara de inmediato a producción el programa de Ed
- Ed dijo que bastaba con ejecutar la versión anterior y la nueva y confirmar que aumentara el total del reporte
- El tiempo total transcurrido fue de 6 días, y el cambio en el código mission critical era de 1 línea y 1 byte
- Se consumieron 24 Excedrin
- En Hacker News se indica que el tiempo dedicado a escribir con frustración fue de 14 horas
1 comentarios
Opiniones de Hacker News
El punto central es que el revisor exigió: “para cambiar esto, también hay que arreglar otros problemas pendientes en el codebase”.
En esos casos hay que responder algo como: “Estoy de acuerdo con mejorar la calidad del código, pero cambiar Y requiere aprobaciones de X/Y/Z y agregará varios días. Voy a convertir lo que mencionas en un trabajo de deuda técnica y lo abordaremos en un PR posterior según prioridad y capacidad. Por ahora, enfoquémonos en qué hace falta para desplegar este PR localizado”.
Lo más importante que aprendí fue a hacer PR enfocados y a saber rebatir cuando un revisor intenta ampliar el alcance. En general, otros ingenieros lo aceptaban de forma pragmática. No tiene que ver con la cantidad de líneas. Podrías cambiar solo el formato de todo el código sin ningún cambio lógico, o cambiar apenas unas banderas de funcionalidad y aun así tener un gran impacto. Hay que hacer un solo cambio enfocado a la vez.
Si esto era de tan alta prioridad que, de no resolverse, la empresa tendría que despedir gente, esos 2 o 3 días antes de que alguien lo viera nunca debieron ocurrir. Pero en este proceso de desarrollo eso parece ser la “ruta rápida”.
Los últimos 2 días también parecen haber pasado sin que ocurriera nada porque el plan de pruebas se consideró insuficiente. “Para cambiar esto hay que arreglar otros problemas pendientes” ocupó apenas 2 horas aquí, y antes incluso de llegar a esa parte ya había al menos 2 o 3 cosas más que podían señalarse como problemas centrales de este proceso.
En vez de dejar FIXME o TODO, prefiero crear discretamente un issue para no olvidarlo. Esta parte de las revisiones está rota. Resolver deuda técnica debe planearse por separado, no ser una condición para terminar una tarea.
Cuando esas capas se acumulan, el código termina siendo moralmente equivalente a Atlanta, Georgia, famosa por tener demasiadas autopistas de circunvalación.
Cuando se agregue una regla nueva, la automatización debería añadir comentarios de excepción de regla en todos los puntos existentes que la incumplen, y hacerlos rastreables. Si un código que hay que desplegar con urgencia necesita incumplir una regla, se agrega un comentario de excepción y se pone el propio nombre como responsable de arreglarlo después.
Con el tiempo se puede construir una cultura de corregir estas infracciones de reglas separadamente del desarrollo de funcionalidades.
Es cierto. El proceso de revisión de código de la mayoría de las empresas está lleno de quisquillosidad y comentarios triviales.
Hace tiempo propuse eliminar ese tipo de comentarios y reemplazarlos con herramientas de análisis estático para acelerar el feedback, pero me respondieron que esas revisiones de código eran necesarias para todos. Porque ayudan a la gente a ascender, dan la sensación de haber evitado problemas en el código y hacen que las métricas de revisión se vean bien para los altos mandos cuando miran la cantidad de comentarios de los revisores.
La verdadera solución es aceptar que no todo el código tiene que parecer escrito por mí, y preguntarse: “¿Este comentario aborda un error objetivo en el código?”. En muchos casos la respuesta es “no”.
Si un nombre de variable es un poco verboso o el espaciado entre métodos no es uniforme, idealmente debería ser “feedback para tener en cuenta la próxima vez si se convierte en un patrón”. Pero desde el punto de vista del revisor, puede ver la cantidad de comentarios por PR como una métrica de cuánto guió a la persona, o preocuparse por una reacción del tipo “¿quién dejó que eso se mergeara?”, y termina dejando el comentario.
Quien recibe la revisión lo corrige por miedo a parecer poco receptivo al feedback si no atiende el comentario, o a que el revisor le dé una mala evaluación si lo rebate. Entonces hay que volver a aprobar la versión actualizada y el ciclo de demora vuelve a empezar.
Pero también hay problemas que algunos consideran señalamientos triviales y que en realidad no lo son en absoluto. Puede ser porque no ven el problema con sus propios ojos, no lo entienden, o les falta la capacidad de dejar de lado las emociones y repensar el código que escribieron.
Todos alguna vez nos hemos encariñado con nuestro código, e incluso pudimos haber pensado que era el código más elegante del mundo. Pero a veces hay que admitir que uno se equivocó, que es difícil de leer, que tiene defectos o que perjudica al codebase.
Una vez señalé una condición de carrera que podía ser un problema real en el código de alguien más senior que yo, y me dijeron que estaba siendo quisquilloso. Para mí, una condición de carrera es un problema fundamental del código escrito y debe corregirse; para esa persona, como todavía no había visto que se rompiera de forma natural, era un estado aceptable.
Me gustan mucho las revisiones entre pares, y normalmente me enfoco en: “este código no se comportará como se espera”, “esto bloqueará la implementación o la hará mucho más costosa”, “funciona, pero es difícil de entender y afectará el mantenimiento; considera otra forma o agregar una explicación”, “el código está bien, pero podría leerse o funcionar mejor; no voy a fallar la revisión por esto, pero vale la pena tenerlo en cuenta para el próximo código”.
“Julie: contacta a Joe del equipo de seguridad de IT. Te va a dar permisos. En 2 horas.” es totalmente irreal. No hay forma de que el equipo de seguridad responda tan rápido.
A veces pienso que el personal de helpdesk lo agarra apenas entra porque es un ticket que pueden cerrar rápido y así mejorar sus métricas personales.
Dicho como en el título, 6 días para cambiar una línea de código, suena terrible.
Pero el sistema mejoró de varias maneras. La configuración pasó de estar hardcodeada a poder configurarse en una tabla de parámetros, y también se agregó auditoría para rastrear ese cambio de configuración.
No intento defender la burocracia. Detesto sinceramente ese aspecto de las organizaciones grandes. Solo quiero señalar que, además del objetivo original, durante esos 6 días se generó valor adicional.
Por eso hay que incluir cierta cantidad de costos accesorios en las estimaciones, y si se asignan story points, también hay que considerar esos costos de proceso.
Al final, los dos logros fueron el “logro” de evitar el ritual adicional alrededor de los cambios de código, y el “logro” de recuperar la funcionalidad perdida por el primer “logro”, porque de ahora en adelante este cambio ya no estaría en el código.
Esto debió haberse manejado como: “Es urgente, por favor aprueben este PR de un solo carácter. Ya creé un ticket de seguimiento para las mejoras que pidieron. Primero resolvamos el problema de producción y luego vemos el resto”.
El revisor solo tenía que decir “LGTM!”. Si la mayoría de los ingenieros no puede navegar entre reglas y lineamientos, esa organización está demente, y justo ahí es donde la seniority aporta valor.
Si puede tomar una semana sin afectar el empleo de nadie, entonces sigue el proceso o cambia lo mínimo indispensable. Si la gente está en licencia sin goce de sueldo por culpa de IT, entonces todas las personas necesarias deben estar en la misma sala, física o virtual, hasta que el problema se resuelva.
Aquí falta ese contexto. Pero si Ed y toda la cadena de aprobaciones no conocen ese contexto, eso es una falla del sistema. Si hubieran sabido que la renta de alguien estaba en juego, probablemente el senior habría propuesto crear un segundo ticket para arreglarlo justo después. Si no, eso también es un problema que la gerencia debe resolver.
Esta historia es un caso en el que cambiar una línea con un valor hardcodeado en realidad salió bien.
Puedo imaginar un escenario en el que alguien guardó la cantidad de meses de backlog como un valor de 2 bits para parecer inteligente e ingenioso. Algo donde solo son posibles 0, 1, 2 y 3. Durante las pruebas, podría quedar oculto varias capas más abajo, en un subservicio no probado o en un servicio de automatización low-code, y el problema no aparecería.
Si cambias ese valor a 4, el backlog podría volverse 0. No sabes cuáles serían las consecuencias. Ese servicio podría cancelar todas las tareas en la cola de producción, o enviar correos a los clientes diciendo que sus tareas fueron canceladas.
Desde afuera parece un cambio fácil, pero si un cambio de política llegó al equipo de software como un problema urgente, la gerencia debería haberlo planeado mejor, no mover arbitrariamente la prioridad de los issues.
Al contrario, aumentaron el riesgo al exigir que se refactorizaran varias partes alrededor como “costo” del cambio.
Está bien si el gran jefe dice: “Decidí asumir el riesgo y avanzar, y también acepto las consecuencias”. No está bien si les cae a los programadores.
Si era una actualización importante y sensible al tiempo para una funcionalidad crítica, el responsable de operaciones debería haber conocido el tiempo promedio de despliegue del software y haber armado un equipo para procesarlo rápido, en lugar de meterlo con alta prioridad en el pipeline normal de desarrollo.
Las revisiones de código empiezan con buenas intenciones. Pero algún guardián termina instalándose y empieza a rechazar todo por motivos triviales.
Dice que le interesa proteger la “calidad del código”. Pero no hay nada peor que dejar durante más tiempo código con bugs que ya tiene una corrección lista, o retrasar una funcionalidad para que nadie pueda probarla.
Recomiendo un proceso en el que se permitan comentarios, pero el revisor no pueda bloquear el commit. Hay que confiar en que cada desarrollador será cuidadoso y hará cambios adecuados al trabajo. También puedes usar CI y, según el equipo, todo puede funcionar bastante bien.
Cambiar el proceso para poder ignorar a un revisor patológico es, en el mejor de los casos, una medida a medias.
Tengo sentimientos encontrados sobre los bloqueos. Entiendo que una gran señal roja de bloqueo es frustrante, así que en muchos casos hago un “bloqueo suave”: pido cambios sin bloquear. Pero cuando un PR se descarrila por completo, normalmente con un desarrollador junior, me parece adecuado enviar un mensaje claro.
Esta es una historia meta sobre trabajadores de fábrica y desarrolladores de software.
El líder de esta empresa está dispuesto a despedir a trabajadores de fábrica por una subutilización del 10%. Se pueden ajustar algunas variables para aumentar la productividad, pero al final las opciones son utilización completa o desempleo. Probablemente sea posible porque estos trabajadores son reemplazables, se los puede volver a contratar en temporada alta y la ganancia generada por empleado no permite ineficiencias.
Yo trabajo como desarrollador de software. En nuestro caso, la subutilización tendría que superar con mucho el 90% para que pensáramos en dejar ir a alguien. Mucha gente trabaja solo 4 horas por semana. Nadie administra nuestro tiempo minuto a minuto ni nuestros descansos para ir al baño, etc.
Ahora estamos en una época de capitalización masiva del software. No durará para siempre. Algún día se habrá construido la infraestructura principal del mundo IT y la industria pasará a modo mantenimiento. La mayoría de nosotros dejará de ser necesaria, nos volveremos reemplazables, y las ganancias que generemos en modo mantenimiento serán mínimas comparadas con lo que vemos hoy.
A un trabajador de fábrica normalmente lo despiden en minutos u horas si se percibe que su productividad individual es baja. Creo que dentro de nuestra vida esto también empezará a pasarles a los desarrolladores de software.
También hay que evaluar hasta qué punto eso es posible para el propio conjunto de habilidades.
Estoy de acuerdo con la idea básica de que la capitalización masiva del software no será eterna. No todas las empresas siempre necesitarán ingenieros para desarrollar software nuevo. Es más parecido a un negocio creativo con auges y caídas, como la producción cinematográfica. Si eliges desarrollo en vez de IT, tienes que aceptar ese riesgo. Aunque no veo por qué este tendría que ser el pico.
Por experiencia personal, después de trabajar varios años en equipos con revisiones de código formales, pasé a un equipo/empresa sin revisiones de código. Cualquiera podía hacer commit y merge libremente en cualquier rama.
Al entrar tenía sentimientos algo encontrados, pero en la práctica fue muy refrescante y me hizo sentir con autoridad, así que en pocos días ya estaba trabajando de forma productiva.
Dado el objetivo del equipo, la forma sin revisiones de código encajaba muy bien. Era un grupo de I+D cuyo objetivo principal era demostrar “funcionalidades nuevas geniales” a los ejecutivos. Llegaban muchas solicitudes con poco aviso, pero también se tiraba mucho código.
Después de la demo, el ejecutivo decía “se ve bien, pero no tiene caso de negocio”, y el repositorio no se volvía a tocar. Claro que a veces algo de lo que hacíamos llegaba a producto, y entonces el equipo downstream se encargaba de convertir ese código garabateado en calidad de producción. Esa gente nos odiaba con una furia ardiente.
A los nuevos integrantes se les asignaba un mentor que se sentaba cerca durante los primeros 2 o 3 meses, hacía pair programming con frecuencia y revisaba su código.
Fue un proyecto de 2,5 años; salió en vivo al mes 20, cumplió plazo y presupuesto, y entregó más funcionalidades que el alcance original. Muchos días pasábamos 2 o 3 horas discutiendo frente al pizarrón. Era informal y no siempre participaban todos.
Curiosamente, durante este proyecto cambiamos de PM tres veces. Teníamos una regla estricta de no usar correo ni mensajes fuera del standup, y dos de los tres pudieron “trabajar” con esa configuración. El director de IT del aeropuerto recién se dio cuenta dos años después de que no necesitábamos un PM.
Había una regla: si ibas a hacer algo nuevo en el codebase, tenías que hablar con al menos otro desarrollador. Nos sentábamos a pocos pies unos de otros en una oficina privada amplia con un pizarrón grande. Las historias se gestionaban con tarjetas índice pegadas en un pizarrón dedicado; si no podíamos explicar lo esencial ahí, había que dividirlo en partes más pequeñas.
Cada quien podía armar su propia máquina y usar tantos monitores como quisiera. Era el sistema de facturación y tarifas de un gran aeropuerto internacional, y el jefe y el director de contabilidad, además de otros usuarios, estaban a unas pocas puertas de distancia. Casi nunca faltaban al standup y tenían una política de recibir preguntas en tiempo real en cualquier momento.
El standup normalmente no era un reporte de estado, sino una discusión informal, demos y preguntas y respuestas. Para las actualizaciones de estado bastaba con mirar las tarjetas del pizarrón.
El sistema final mejoró los ingresos en 8% desde el primer mes y todos los meses posteriores. El director de contabilidad tuvo que explicarlo ante la junta de la autoridad aeroportuaria. Las disputas y conciliaciones de facturación con las aerolíneas bajaron de 9 días al mes a 1 día, y la carga mensual de facturación bajó de 18 días a 5. Se pudo transferir al usuario principal de un contador senior a una sola contadora junior con 3 años de experiencia.
Hubo 6 bugs en producción durante el primer año y 0 facturas incorrectas. No tengo datos posteriores. El intento anterior de reescritura había fracasado después de 3 años.
Usar el proceso de revisión de código para mantener los cambios como rehenes hasta que encajen con ideales altos y en constante cambio del equipo es disfuncional.
Una política de “actualizar sobre la marcha” deja una larga cola de transiciones a medio terminar, lo que dificulta que los nuevos desarrolladores se adapten al codebase. Como no hay garantía de que el foco del producto pase regularmente por todas las partes del codebase, la transición ni siquiera termina. Algunas áreas del producto quedan abandonadas durante años.
Si pasar a una nueva política es importante, debería separarse y abordarse como un proyecto enfocado; si no, entonces no es importante.
Están esperando que bombas de tiempo de trabajo no planificado por todo el codebase estallen a través de tareas aleatorias no relacionadas.
Si el nuevo estándar importa, hay que actualizar el código; si no, no. Depender del azar y retrasar trabajo urgente no es un plan.
Leer esto como un problema de revisión de código es un error. El problema es que la empresa puso un proceso compuesto por barreras internas por encima de los principios.
Todo proceso necesita vías de escape. Si el cambio evita un despido, deberían activarse todas las vías de escape.