En estos días deberíamos pensar críticamente sobre cómo hacemos las cosas en la programación. Necesitamos aplicar el enfoque de ingeniería a nuestros procesos. Nosotros, los ingenieros de software, confiamos en las discusiones sobre clases abstractas y funciones puras. Por otro lado, nos escapamos cuando hay necesidad de discutir cosas "gerenciales". La revisión del código tiene algunas fallas y tenemos que rediseñarla arreglando la estructura del proceso y la divergencia de la visión.
En estos días deberíamos pensar críticamente sobre cómo hacemos las cosas en la programación. Necesitamos aplicar el enfoque de ingeniería a nuestros procesos. Nosotros, los ingenieros de software, confiamos en las discusiones sobre clases abstractas y funciones puras. Por otro lado, nos escapamos cuando hay necesidad de discutir cosas "gerenciales". Mi proceso de programación favorito ampliamente difundido que tiene una enorme cantidad de fallas es la revisión de código. Esta historia lo mirará desde diferentes perspectivas y propondrá mejoras. El primer hecho significativo que leí sobre las inspecciones de software fue en el libro "Hechos y falacias de la ingeniería de software" de Robert Glass. Afirma lo siguiente:
Las inspecciones rigurosas pueden eliminar hasta el 90 por ciento de los errores de un producto de software antes de ejecutar el primer caso de prueba.
No pude determinar si estas palabras se referían únicamente a la revisión del código. Los trato como referidos a diferentes tipos de inspecciones, que describiré más adelante.
. Michael Fagan formuló la idea de las inspecciones en 1976 en su artículo "Inspecciones de diseño y código para reducir errores en el desarrollo de programas".
Descubrí los siguientes tres tipos de inspecciones allí:
inspección de diseño,
Inspección de código antes de la prueba unitaria,
Inspección de código después de la prueba unitaria.
El trabajo de Fagan no propone un nuevo enfoque del código, sino que documenta los fenómenos ya existentes y los defiende. Sin embargo, el artículo es el primer signo escrito de inspecciones que he encontrado. Las inspecciones de código se parecen a nuestras revisiones de código modernas. ¿Por qué echamos de menos otro tipo de inspecciones hoy en día?
Por qué solo hay revisiones de código hoy: algunas suposiciones
La popularidad de las inspecciones de códigos y la casi inexistencia de otros tipos de inspecciones en la actualidad proviene de nuestras herramientas. GitHub, BitBucket o GitLab tienen instrumentos de revisión de código incorporados y, naturalmente, encajan en el flujo de Git, el flujo de GitHub y otros enfoques. ¿Qué herramienta utiliza para las actividades de diseño? No se trata de la UI/UX. Se trata de la estructura del código que construirás. Es posible que haya oído hablar de las herramientas CASE o UML. No los he visto seriamente utilizados en ninguna empresa para la que trabajé, y he trabajado para siete.
En HackerNoon, la consulta de búsqueda " UML " arroja solo dos resultados relevantes. Por lo tanto, no hay lugar para introducir la inspección de diseño cuando no existe un proceso de diseño de solución tangible. En el equipo que dirijo, utilizamos Miro para el diseño de la interfaz. El proceso podría haber sido más satisfactorio: al igual que con otras herramientas de creación de diagramas, pronto empiezas a dibujar en lugar de resolver tus problemas. Podemos ser independientes de nuestras herramientas. Aquí hay una pequeña cita para apoyar esto del libro "Investments Unlimited":
...si solo hacemos lo que las herramientas pueden hacer, entonces siempre estaremos limitados a las capacidades de nuestras herramientas.
¿Qué fallas tienen las revisiones de código existentes?
Veamos el proceso en su forma clásica desde diferentes perspectivas. Cada uno de ellos muestra problemas significativos.
Perspectiva BPMN
BPMN es una notación de modelado de procesos de negocio. Describe procesos con acciones, eventos, puertas de enlace lógicas, mensajes y otros medios. Incluso recomiendo usarlo si desea desarrollar un algoritmo, ya que es más descriptivo que un diagrama de flujo. Describamos el proceso de revisión de código para un solo revisor con esta notación y analicémoslo. He usado una herramienta basada en texto para generar . Hay un pequeño problema con muchas cartas que regresan.
Todo comienza con una creación de relaciones públicas, y nada es notable aquí. El siguiente paso es notificar a un revisor, que es una simplificación de todos los diferentes medios disponibles para decir: "¡Oye, mi PR te está esperando! 👋" Lo importante aquí es liberarse de las actividades actuales. Aquí el PR espera una duración desconocida. Luego, el revisor se sumerge en la tarea y realiza la revisión. Existe la posibilidad de que un PR se fusione de inmediato. Sin embargo, podría suceder lo contrario: aparecerían algunos comentarios que requieren correcciones. El autor del código podría estar ya en la siguiente tarea y hay un tiempo de espera más de una duración desconocida. Además, volver requiere la restauración del contexto, la interpretación de los comentarios y su corrección. El siguiente paso es la notificación del revisor.
¿No hemos estado ya allí? Sí, tiene usted razón. Acabamos de terminar nuestra primera iteración del ciclo potencialmente infinito. Sí, infinito. Siempre existe la posibilidad de que aparezcan nuevos comentarios. O que uno de los períodos de espera duraría para siempre.
¿Queremos el ciclo potencialmente infinito como parte de nuestras operaciones diarias? No estoy seguro, ya que generalmente es preferible tener una entrega más rápida.
Solución Visión Perspectiva
A veces, tenemos desarrolladores o arquitectos senior en nuestros equipos como revisores. Desean tener una base de código consistente, apegarse a algunos métodos y patrones y evitar otros. Tienen una visión. Los desarrolladores también tienen su idea. Por lo general, no son conscientes de la intención de sus superiores. Requiere una transmisión constante o un entorno auxiliar, lo que rara vez sucede. Echemos un vistazo a la siguiente imagen.
Puede ver cómo difieren las dos visiones de los participantes de la revisión de código. Después de la primera iteración, comienzan la alineación, pero aún queda camino por recorrer. El revisor ajusta su visión, y el autor del código se mueve de acuerdo a la interpretación de las propuestas. Podemos usar la metáfora de "imagina que has pedido una casa y luego ¡sorpresa! No es la que esperabas". O podemos mirar su núcleo. Imagina que le has pedido a una persona que logre algo. Luego vuelves y ves los resultados, pero te sorprende el conjunto de decisiones que ha tomado el triunfador. No se sorprenda, ya que no requirió un marco particular para la toma de decisiones.
Perspectiva Interpersonal
La imagen dice por sí misma. ¿Le pediría a su compañero ingeniero que solucione el problema de diseño después de pasar muchos días en la tarea? Imagina que tu sprint termina y el ticket fue la causa de cierta tensión en un standup. Ayudará a su colega a fusionarlo lo más rápido posible. Por otro lado, podría haber un ingeniero senior revisando el código del junior. Podría pedirle que recorra un largo camino para arreglar la decisión tomada al principio. Sin embargo, ¿es este el momento adecuado para dar ese consejo? Tantas decisiones ya se basan en la elección equivocada.
La manufactura esbelta todavía tiene que influir en la programación. Sin embargo, ya tenemos una herramienta del libro "Lean Software Development" de Mary Poppendieck y Tom Poppendieck. Esta herramienta son los siete desechos del desarrollo de software:
Trabajo parcialmente hecho,
Características adicionales,
reaprender,
traspasos,
retrasos,
Cambiar de tarea,
defectos
¡La revisión del código clásico gana 6 de 7!🎉
Obra parcialmente realizada . Una tarea en la revisión se abandona la mayor parte del tiempo. Por lo general, trato esta etapa de desarrollo como una cola en lugar de una donde está la acción. Crear una reseña también tiene un efecto psicológico interesante: "¡La tarea está lista y ya no es mi trabajo!" La revisión del código es la "tierra de responsabilidad de nadie", por lo que a menudo vemos que se eleva a los niveles superiores.
Reaprendizaje . Puede ver el reaprendizaje en el diagrama BPMN anterior. Restaurar el contexto es volver a aprender.
Entregas . Si somos honestos, esto no es un desperdicio aquí. Es la mecánica central.
Retrasos El diseño de revisión de código contiene dos tipos de retrasos que hemos discutido anteriormente. Lo que es aún más aterrador es su bucle.
Conmutación de tareas . Las personas pausan sus tareas para prestar atención a una revisión.
defectos La revisión es buena para encontrar problemas estéticos, pero no fallas de diseño, que serían las más perjudiciales. La mencionada falta de motivación para pedir a los becarios cambios significativos conduce a defectos sustanciales en el proyecto.
Hemos cubierto los problemas de las revisiones de código desde muchos lados. ¿Qué podemos hacer para solucionar este proceso?
Revisión de código de rediseño
En esta sección, cubriremos los mismos temas que la anterior pero desde el punto de vista de la fijación.
Fijación de la estructura del proceso
Aquí tenemos un autor de código esperando que se complete una revisión y una sesión de programación en pareja después de la descripción general de un revisor.
En el proceso propuesto, podemos observar varios cambios significativos respecto al anterior:
No más ciclos de revisión potencialmente infinitos;
Tiempo de espera único de duración desconocida, también lo manejaremos;
No es necesario restaurar el contexto ni interpretar los comentarios para el autor del código. Los comentarios ahora sirven como recordatorios para la pareja.
¿Cuáles son los requisitos básicos para que este proceso suceda? Ahora un equipo necesita un rol adicional. Implica que alguien realiza las actividades auxiliares, por ejemplo, maneja la deuda técnica o corrige errores de menor prioridad. Cuando aparece la revisión de código en el radar, esta persona abandona inmediatamente la tarea actual y salta al PR llegado. Si alguna vez te has preguntado por qué necesitas cierta holgura en la estructura de tu trabajo, este es un ejemplo. Si todo el mundo está ocupado con las funciones de máxima prioridad, las entregará más tarde.
Arreglando la divergencia de la visión
¿Qué discutimos en las revisiones de código? Las decisiones tomadas durante el desarrollo. Algunas las hicimos hace una hora y otras hace una semana. Nuestras elecciones se superponen y no son independientes.
¿Qué tan agradable encuentra la oportunidad de cuestionar una de las primeras decisiones en las que se encuentran los próximos cientos? Es posible que no esté satisfecho con la oportunidad. El momento más apropiado para discutir las decisiones de diseño es cuando aparecen. Necesitamos un tipo adicional de revisión: revisión de diseño. A veces, cuando el problema es desafiante, es bueno dedicar algo de tiempo al plan y discutirlo con sus colegas expertos. Hay un famoso adagio militar:
Ningún plan de batalla sobrevive al contacto con el enemigo.
Si lo traducimos al lenguaje de los sistemas, obtendremos algo como: "Sin duda, el sistema necesitará ajustar su comportamiento cuando llegue la primera retroalimentación". En el caso de la programación, la retroalimentación serían los problemas que enfrentamos al intentar implementar el diseño en nuestro sistema. Algunas de las decisiones necesitan ser revisadas. Tendríamos que cambiarlos y volver a divergir en nuestras visiones con un revisor. Adam Thornhill, en su abrumador libro "Software Design X-Rays", propuso un método:
Es por eso que le recomiendo que haga su tutorial de código inicial mucho antes. En lugar de esperar a que se complete una función, acostúmbrese a presentar y debatir cada implementación en un tercio de su finalización. Concéntrese menos en los detalles y más en la estructura general, las dependencias y qué tan bien se alinea el diseño con el dominio del problema. Por supuesto, completar un tercio es subjetivo, pero debe ser un punto donde la estructura básica está en su lugar, el problema se comprende bien y existe el conjunto de pruebas inicial. En esta etapa inicial, una reelaboración del diseño sigue siendo una alternativa viable y la detección de problemas potenciales aquí tiene una gran recompensa.
He acuñado un término para que mi equipo tenga un lenguaje conveniente: revisión básica. Espero que ayude a reflejar la idea detrás de la actividad.
Perspectiva Lean sobre el proceso propuesto
El proceso propuesto elimina o aborda significativamente los desechos descubiertos.
Obra parcialmente realizada . No se permite cambiar a otra tarea durante el tiempo de anticipación para un autor de código, por lo que no hay trabajo parcialmente realizado significativo para el usuario. Las actividades parcialmente realizadas de menor prioridad son la compensación.
Reaprendizaje . No se produce reaprendizaje ya que pasa poco tiempo entre la finalización de la codificación y la programación en pareja.
Retrasos Hemos acortado significativamente el retraso del revisor de código y eliminado el del autor.
Conmutación de tareas . Ya no se permite para un autor y se gestiona para un revisor.
defectos Ahora arreglar los defectos de diseño se vuelve más barato, y el más importante de ellos, los defectos de diseño, se arreglan.
Pensamientos Adicionales
Hemos revisado el enfoque de revisión de código para un solo autor y un solo revisor. Cuando aparecen más revisores, los problemas se multiplican. Entonces, desafortunadamente, no todos los errores se vuelven superficiales si agrega personas últimamente para ver todas las decisiones que ha tomado. En su lugar, haría que su código se fusionara más tarde. Dos de los problemas más desafiantes que enfrenté al intentar introducir el proceso propuesto fueron los siguientes:
Los desarrolladores tratan la etapa de revisión como un trabajo hecho. Los gerentes se horrorizan cuando proponen introducir la redundancia en el trabajo diario. Es genial que no manejen los equipos de bomberos. La cura para el primer problema es la repetición y la velocidad.
El segundo problema es más complicado. Aquí quiero citar el libro "Actionable Agile Metrics for Predictability" de Daniel Vacanti:
Hay muchas estrategias que emplea FedEx, pero la que probablemente sea más importante es que en un momento dado FedEx tiene aviones vacíos en el aire. Sí, dije aviones vacíos. De esa manera, si una ubicación se abruma, o si los paquetes se dejan atrás porque un avión programado regularmente estaba lleno, se redirige un avión vacío (justo a tiempo, debe decirse) al lugar del problema. ¡En cualquier momento, FedEx tiene "repuestos en el aire"!
Si es gerente, considere esto la próxima vez que planifique la maximización de la utilización. ¿Estamos satisfechos con la actualización? Sí, se ve mejor que lo que tenemos ahora.
¿Podemos hacerlo mejor? Si podemos.
El objetivo es eliminar la revisión de código en un momento en que podamos garantizar que toda la calidad necesaria ya está en el código. Para lograr esto, necesitamos construir un marco auxiliar de toma de decisiones para ayudar a los desarrolladores a aplicar lo que se trata como una buena práctica y evitar la mala. Nunca he oído hablar de un marco de este tipo, pero los linters en IDE son un paso hacia él.
¡Gracias por leer! Escriba un comentario si desea discutir las ideas descritas.