Los cambios en los sistemas de software complejos parecen tomar una eternidad, ¿verdad? ¡Incluso los ingenieros a menudo piensan que los cambios van más allá de lo que se supone que son, aunque somos conscientes de la complejidad del sistema!
Para los clientes, la situación es aún más incomprensible. El problema se agrava por la complejidad aleatoria, que se agrega con el tiempo debido a la falta de soporte del sistema. Existe la sensación de que estamos tratando de extraer agua de un barco con mil agujeros.
Por lo tanto, tarde o temprano, el cliente enviará una carta: "¿Por qué demonios tarda tanto?" No olvidemos que nosotros, como ingenieros de software, tenemos una ventana al mundo, que a menudo les falta. Confían en nosotros mucho, pero a veces un cambio aparentemente insignificante realmente lleva mucho tiempo. Debido a esto, surgen preguntas.
No se ofenda por esta pregunta; Tómelo como una oportunidad para mostrar empatía y darle a una persona una imagen más clara de la complejidad del sistema. Al mismo tiempo, puede sugerir formas de mejorar la situación. Cuando alguien está molesto, ¡este es el mejor momento para ofrecer una solución!
A continuación se publica una carta que, de una forma u otra, hemos enviado repetidamente a lo largo de los años. Esperamos que te ayude a responder estas preguntas.
Una carta
Estimado cliente,
Vi su comentario en la tarjeta "Notificar antes del vencimiento de la tarea" y estaré encantado de discutirlo en nuestra próxima reunión. Aquí, como referencia, resumiré mis pensamientos, no es necesario responder.
Parafraseando tu nota:
Cambiar la fecha límite para completar las tareas en un día para la notificación por correo debería tomar una línea. ¿Cómo puede tomar de 4 a 8 horas? ¿Qué me estoy perdiendo?Por un lado, estoy de acuerdo contigo. Simplemente cambie la parte de la solicitud de
tasks due <= today
a
tasks due <= tomorrow
.
Por otro lado, reduciéndolo a una idea tan simplificada, ignoramos inadvertidamente la complejidad inherente y tomamos una serie de decisiones de ingeniería. Algunos de ellos deberíamos discutirlos.
Parte 1. ¿Por qué este pequeño cambio es más de lo que parece?
Este es un cambio simple y pequeño, una línea de código. Pasar todo el día en él, incluso medio día, parece excesivo.
Por supuesto, no puede simplemente implementar un cambio en la producción sin ejecutar al menos localmente o en un servidor de prueba. Debe asegurarse de que el código se ejecute correctamente, y si la solicitud cambia, debe comparar el resultado y asegurarse de que se vea más o menos correcto.
Aquí, comparar el resultado puede ser mínimo, solo una pequeña comprobación puntual: asegúrese de que los resultados tengan sentido, etc. Esta es una notificación para los empleados internos. Si las matemáticas por fecha son incorrectas (un pequeño error), los equipos nos informarán rápidamente. Si fuera, digamos, un correo electrónico para sus clientes, se requeriría un estudio más profundo. Pero para esta prueba y revisión fáciles, son suficientes 20-40 minutos, dependiendo de si aparece algo extraño o inesperado. Excavar en los datos puede consumir tiempo. Liberar cambios sin realizar una revisión es simplemente negligencia no profesional.
Por lo tanto, agregamos tiempo para la logística normal, como la confirmación de un código, la fusión de cambios, la implementación, etc., desde el comienzo del trabajo hasta el lanzamiento en producción, al menos una hora pasa de un ingeniero profesional competente.
Por supuesto, esto supone que usted sabe exactamente qué línea de código cambiar. El flujo de trabajo de la tarea básicamente vive en el sistema antiguo, pero algunas partes de la lógica viven en el nuevo sistema. Mover la lógica del sistema anterior es bueno, pero significa que la funcionalidad de la tarea se divide actualmente en dos sistemas.
Como hemos estado trabajando juntos durante tanto tiempo, nuestro equipo sabe qué proceso envía un correo electrónico con una tarea vencida y puede señalar una línea de código en el nuevo sistema que inicia el proceso. Por lo tanto, no tenemos que perder el tiempo resolviendo esto.
Pero si miramos el código de la tarea en el sistema anterior, hay al menos cuatro formas diferentes de determinar si la tarea se debe. Además, al observar los patrones y el comportamiento del correo electrónico, hay al menos dos lugares más donde parece que se implementa una lógica personalizada para esta tarea.
Y luego la lógica de notificación es más complicada de lo que pensabas. Distingue entre tareas generales e individuales, abiertas y privadas, repetitivas, la función de notificación adicional del gerente en caso de una tarea atrasada, etc. Pero podemos descubrir rápidamente que, de hecho, solo 2 de 6+ definiciones de la tarea atrasada se utilizan para notificaciones. Y solo una cosa necesita ser cambiada para lograr la meta.
Tal revisión puede tomar fácilmente otra media hora más o menos, tal vez menos si ha estado recientemente en esta parte de la base de código. Además, la complejidad latente significa que podemos superar nuestra estimación para las pruebas manuales. Pero agreguemos 30 minutos para un esfuerzo extra.
Por lo tanto, llegamos a 1,5 horas para sentirnos seguros de que el cambio se llevará a cabo como se esperaba.
Por supuesto, aún no hemos verificado si algún otro proceso utiliza una consulta mutable. No queremos interrumpir accidentalmente otras funciones cambiando el concepto de "fecha límite" al día anterior al último día para completar la tarea. Debemos considerar la base del código desde este punto de vista. En este caso, parece que no hay dependencias importantes, probablemente porque la mayor parte de la interfaz de usuario todavía está en el sistema anterior. Por lo tanto, no hay necesidad de preocuparse por cambiar o probar otros procesos. En el mejor de los casos, estos son otros 15-30 minutos.
Ah, y dado que la parte principal de la interfaz de usuario de la tarea todavía está en el sistema anterior, realmente necesitamos hacer una descripción general rápida de la funcionalidad de la tarea en este sistema y asegurarnos de que la respuesta sea correcta. Por ejemplo, si la interfaz de usuario resalta tareas cuya fecha límite ha llegado, podemos cambiar esta lógica para que coincida con la notificación. O al menos vuelve y pregunta al cliente cómo quiere hacerlo. Recientemente, no examiné la funcionalidad de la tarea en el sistema anterior y no recuerdo si tiene alguna idea de la fecha límite / retraso. Esta revisión agrega otros 15-30 minutos. Quizás más si el viejo sistema también tiene varias definiciones de una "tarea", etc.
Por lo tanto, pasamos al rango de 2 a 2.5 horas para completar la tarea con la confianza de que todo saldrá bien, sin efectos secundarios no deseados o confusión en el trabajo del usuario.
Parte 2. ¿Cómo puedo reducir este tiempo?
Desafortunadamente, el único resultado de estos esfuerzos es solo el cumplimiento de la tarea. Esto no es óptimo, lo cual es muy decepcionante. El conocimiento adquirido por el desarrollador en el curso del trabajo es personal y efímero. Si otro desarrollador (o nosotros mismos después de 6 meses) nuevamente necesita hacer cambios en esta parte del código, el proceso tendrá que repetirse.
Hay dos tácticas principales para remediar la situación:
- Limpie activamente la base del código para reducir la duplicación y la complejidad.
- Escribe pruebas automatizadas.
Nota: ya hemos discutido la documentación, pero en este caso esta no es la mejor solución. La documentación es útil para ideas de alto nivel, como la explicación de la lógica empresarial o los procesos repetidos con frecuencia, como una lista de nuevos socios. Pero cuando se trata de código, la documentación rápidamente se vuelve demasiado voluminosa y se vuelve obsoleta a medida que cambia el código.
Notó que ninguna de estas tácticas está incluida en nuestras 2–2.5 horas.
Por ejemplo, mantener una base de código limpia significa que, en lugar de simplemente completar la tarea, hacemos preguntas:
- ¿Por qué hay tantas formas diferentes de identificar tareas cuya fecha límite se ha acercado / expirado?
- ¿Todos los necesitan y trabajan en ellos?
- ¿Se pueden reducir estos métodos a uno o dos conceptos / métodos?
- Si el concepto se divide entre el sistema antiguo y el nuevo, ¿se puede consolidar?
Y así sucesivamente.
Las respuestas a estas preguntas pueden ser bastante rápidas: por ejemplo, si nos encontramos con un código claramente muerto. O pueden tomar varias horas: por ejemplo, si las tareas se utilizan en muchos procesos complejos. Tan pronto como tengamos estas respuestas, llevará más tiempo refactorizar para reducir la duplicación / confusión y obtener una descripción única del concepto de "fecha límite", o cambiar el nombre de los conceptos en el código para comprender claramente en qué se diferencian y por qué.
Pero al final, esta parte de la base del código se volverá mucho más simple, será más fácil de leer y modificar.
Otra táctica que usamos habitualmente es la prueba automatizada. En cierto sentido, las pruebas automatizadas son similares a la documentación que no puede estar desactualizada y que es más fácil de detectar. En lugar de ejecutar manualmente el código y ver la salida, escribimos un código de prueba que inicia la solicitud y verifica la salida mediante programación. Cualquier desarrollador puede ejecutar este código de prueba para comprender cómo debería funcionar el sistema y para asegurarse de que todavía funciona de esa manera.
Si tiene un sistema con una cobertura de prueba decente, estos cambios tomarán mucho menos tiempo. Puede cambiar la lógica y luego ejecutar el conjunto de pruebas completo y asegurarse de que
- el cambio funciona correctamente;
- el cambio no rompió nada (esta información es aún más valiosa que en el primer párrafo).
Cuando creamos sistemas desde cero en Simple Thread, siempre incluimos tiempo para escribir pruebas automatizadas en la evaluación de plazos. Esto puede ralentizar el desarrollo inicial, pero mejora enormemente la eficiencia del trabajo y el mantenimiento. Solo cuando el sistema crece, realmente comprende la importancia de las pruebas, pero en este punto puede ser muy difícil devolver las pruebas al sistema. La presencia de pruebas también simplifica enormemente el trabajo de los nuevos empleados, y cambiar el comportamiento del sistema es mucho más rápido y seguro.
Parte 3. ¿De dónde venimos? A donde vamos
Hoy, rara vez indicamos en su evaluación el tiempo para borrar el código o escribir pruebas. Esto se debe en parte a que escribir pruebas desde cero es una sobrecarga menor, y agregar pruebas a la datación de código base es mucho trabajo, como restaurar la base debajo de la casa donde viven las personas.
Esto también se debe en parte al hecho de que, al comenzar a trabajar con usted, cambiamos inmediatamente al modo de reanimación. Tenemos problemas casi diarios con la sincronización de datos de terceros, problemas semanales con la generación de informes, solicitudes constantes de soporte para pequeños cambios de datos, monitoreo inadecuado y registro del sistema, etc. La base del código se está ahogando bajo el peso de las deudas técnicas, y estamos intentando febrilmente mantener los sistemas en funcionamiento flote, mientras pega agujeros con cinta aislante.
Con el tiempo, los sistemas se vuelven más estables y confiables, automatizamos / proporcionamos IU para autoservicio de solicitudes de soporte frecuentes. Todavía tenemos muchas deudas técnicas, pero salimos del modo de emergencia. Pero no creo que alguna vez nos alejemos por completo de esta mentalidad de reanimación a una mentalidad más proactiva y madura de "planificar y ejecutar".
Intentamos borrar el código sobre la marcha, y siempre probamos a fondo. Pero ser cuidadoso y diligente no es una refactorización proactiva o la creación de la infraestructura necesaria para buenas pruebas automatizadas.
Si no comenzamos a pagar algunas deudas técnicas, nunca podremos mejorar significativamente la situación. Los desarrolladores altamente calificados y competentes tardarán meses en navegar y realizar cambios no triviales.
En otras palabras, de 4 a 8 horas para esta tarea es aproximadamente de 2 a 4 veces el suministro, pero reducirá significativamente los esfuerzos para tales cambios en el futuro. Si esta parte de la base del código fuera más limpia y tuviera una buena cobertura con pruebas automáticas, un desarrollador experimentado competente la completaría en una hora o menos. Y el punto clave es que el nuevo desarrollador tomará un poco más de tiempo.
Para tal cambio en los términos, necesitamos su consentimiento. Este es un intento consciente de mejorar fundamentalmente el rendimiento de su sistema, no solo cómo lo perciben los usuarios. Entiendo que es difícil aceptar tales inversiones precisamente porque no hay un beneficio visible, pero nos complace sentarnos con usted y preparar algunas cifras claras que muestren cómo estas inversiones se amortizarán a largo plazo desde un punto de vista de ingeniería.
Gracias
Al