El dedo medio de Chesterton
(arp242.net)- La cerca de Chesterton es un consejo de no cambiar a la ligera código cuya razón se desconoce, pero el código y el historial de commits que no dejan registrada esa razón trasladan la misma carga al desarrollador que viene después
- En este repositorio, el cuerpo de los commits de los últimos 13 años suma apenas 295 líneas según el conteo por comandos, y si se excluyen los cuerpos relacionados con dependabot, revert y typos, se reduce a 167 líneas
- Los títulos de los commits, incluso en cambios grandes, no dan contexto con cosas como “fix page A”, y casi no hay documentación aparte ni comentarios en el código, por lo que es difícil rastrear el motivo de los cambios
- En el código quedan refactorizaciones inconclusas, restos de funciones eliminadas, funciones agregadas pero no conectadas ni usadas, y funciones que aparentemente nadie usa
- Los mensajes de commit y la documentación deberían dejar al menos qué se cambia, por qué se cambia y por qué es una buena solución; si no se deja nada, el costo para los desarrolladores que vienen después crece
La carga que deja un código sin razones
- La cerca de Chesterton es una metáfora que dice que, si no entiendes por qué algo está así, no deberías cambiarlo a la ligera
- En programación también puede pasar que “arregles” código que se ve raro y después descubras que esa rareza tenía una razón de ser
- En este caso aparece el problema del lado contrario
- Hay mucho código y decisiones extrañas, pero no hay registros que permitan saber por qué terminaron así
- Después de que todos los desarrolladores anteriores se fueron, ya no hay a quién preguntarle
- El historial de commits del repositorio casi no aporta contexto real
- El cuerpo de los commits de los últimos 13 años suma 295 líneas en total
- Si se excluyen manualmente los cuerpos de commits de dependabot, “revert commit” y “fix typo”, quedan 167 líneas
- Eso equivale más o menos a una línea por mes
- Los títulos de los commits también suelen ser insuficientes para explicar cambios grandes, con cosas como “fix page A”
- No hay documentación separada y casi no hay comentarios en el código
- Esta situación se parece más a un dedo medio de Chesterton: “hicimos muchas cosas raras, pero no vamos a decir por qué”
El registro mínimo que un desarrollador debe dejar
- En la base de código quedan varios tipos de código incompleto o residual
- Refactorizaciones inconclusas
- Restos de funciones eliminadas
- Funciones agregadas pero no conectadas ni usadas
- Funciones que parece que nadie usa
- En general, también parece grave el problema de la brecha de Chesterton
- Algo como “todavía no hay una cerca, así que pongamos una”, sin preguntarse si de verdad hace falta una cerca
- Escribir bien es difícil, pero no es difícil dejar una explicación apenas suficiente para pasar
- Un registro de cambios debería responder básicamente tres preguntas
- Qué se cambia
- Por qué se cambia
- Por qué esta solución es buena
- A veces “Implement new feature X” puede ser suficiente, pero en la mayoría de los casos hay algo que decir sobre por qué o cómo se agregó una función de esa manera
- En correcciones de bugs, refactorizaciones y cambios sustanciales, normalmente se puede dejar al menos uno o dos párrafos explicando el cambio y su motivo
- Esto no es opcional, sino parte del trabajo de un desarrollador de software
- No hace falta que sea elegante
- No hace falta que sea inglés perfecto
- No hace falta que sea un ensayo grandilocuente
- Aunque falten cosas, sigue siendo muchísimo mejor que no dejar nada
- Si no dejas nada, terminas trasladando el problema a todas las personas que vengan después
1 comentarios
Comentarios en Lobste.rs
A veces no está claro en el momento qué cosas van a volverse importantes después. Ayuda muchísimo que todo el proceso que llevó hasta un commit quede registrado públicamente, pero como todas las personas involucradas ya tienen mucho contexto, también hay cosas que se omiten por parecer “demasiado obvias”.
Si la discusión no queda registrada, se vuelve mucho más difícil desenterrar el proceso de toma de decisiones como si fuera arqueología digital. Al final, a veces hay que lidiar con no saber por qué está esa cerca, y evaluarlo con base en el contexto actual y el conocimiento del sistema que tiene la gente de ahora.
También ayuda mucho cuando hay alguien que lleva mucho tiempo en el proyecto y ha desarrollado comprensión e intuición sobre el sistema completo. Las organizaciones que ven a los desarrolladores como engranes reemplazables hacen que nadie se quede el tiempo suficiente, así que repiten los mismos errores y vuelven a inventar la rueda.
Así, la siguiente persona que vea el código al menos tiene una probabilidad mayor que cero de entender por qué está hecho así.
Nunca he entendido a los desarrolladores que en el mensaje del commit solo escriben cosas como “fix” o “WIP commit”. Supongo que nunca han hecho arqueología de código en serio, o ni siquiera habían pensado que eso era algo que se podía hacer.
Yo siempre intento equivocarme del lado de dar demasiada información. Así, al menos existe la posibilidad de que mi yo del futuro, mi reemplazo, o la pobre persona a la que llamen cuando haya una caída, logre entender por qué algo terminó rompiéndose.
En esos casos, es difícil llevar en la cabeza qué cambió después de cada checkpoint o ponerle una explicación con sentido, y el commit termina tratándose más como el botón de “guardar” de un videojuego que como una forma de dividir el trabajo en unidades bien definidas.
En cambio, si haces un commit grande como resultado de un refactor grande de una API, probablemente cualquier cosa que no sea una explicación casi al nivel de un documento de diseño se quede corta; y si no vas a hacer eso, el sentido de un mensaje largo también se vuelve ambiguo. Aun así, hay gente que toma esto como si fuera una medalla y empieza a poner en las notas de lanzamiento frases como “corrección de errores y mejoras de funcionalidades”, pero esa es claramente la conclusión equivocada.
Muchos desarrolladores olvidan con frecuencia que “la otra persona” que tendrá que leer y entender el contexto de un cambio puede ser su yo del futuro. A casi todo el mundo le resulta familiar esa situación de rascarse la cabeza frente a un bloque de código, correr
git blame, y ver que su propio nombre le devuelve la mirada.He perdido la cuenta de cuántas veces un buen mensaje de commit me ha ahorrado horas, o incluso días, de buscar entre issues, correos y logs de chat para encontrar el por qué. Incluso en casos donde se suponía que yo debería poder responderlo de inmediato.
Hay que ser amable con tu yo del futuro. Conviene volcar en el log de git todo lo que sabías, pensabas y se discutió. Nunca está claro qué cosas seguirán siendo obvias dentro de 5 años.
git blameno me pasa tanto, al menos cuando hubo una razón detrás. Cuando se trata de algo aleatorio, como el comportamiento extraño de otra persona, es difícil dar una explicación útil si no puedes ver el proceso que siguió; pero si era algo que en su momento tenía sentido para mí, al releerlo por lo general vuelvo a entenderlo.Mi forma de aprender parece más bien por acumulación en capas de lava. Desde la preparatoria no he cambiado tanto; más bien he ido agregando continuamente cosas que sé y formas en que puedo usarlas.
Hace poco alguien sostuvo que, si un mensaje de commit pasa de una oración, por lo general es una pérdida de tiempo; quise rebatirlo con fuerza, pero resultó que no fui tan bueno como esperaba para demostrar lo contrario
Una pregunta es qué información debería ir en el mensaje de commit y cuál debería ir en comentarios en línea, ADR u otros documentos de formato más largo
Sigo intentando escribir buenos mensajes de commit, pero en el trabajo ya no hay esperanza, y ni siquiera en mis proyectos personales de juguete logro ser consistente
Pero el código final debería poder entenderse sin leer el mensaje de commit. Si hay algo en el código nuevo que necesita justificación, eso debería ir en un comentario
Dicho de otro modo, el mensaje de commit explica por qué hicimos este cambio ahora, y los comentarios explican por qué el código, al terminar el cambio, quedó de esa manera
Los cambios más grandes, en especial las funciones nuevas, deberían tener un documento de diseño en alguna parte. Si necesita revisión, puede ser un documento real dentro del repositorio o puede estar en el rastreador de issues
El mensaje de commit debería apuntar a ese documento, y quizá también tenga que explicar los detalles que surgieron al bajar el diseño al código. Si es posible, conviene incluir también un resumen corto del documento de diseño. Esto es especialmente importante cuando hay varios posibles revisores: da una señal de quién debería prestar más atención y ayuda a detectar si faltó alguien que debió haber dado feedback en la etapa de diseño
git logojj log, sino casi siempre a través de la vista de anotaciones por líneaLa línea de título suele ser muy útil para decidir si vale la pena profundizar más. Si el cuerpo contiene información sobre por qué se hizo el cambio, ayuda cuando esa razón no es intuitiva
Por ejemplo, aunque haya bastante código, muchas veces basta con “admin: add impersonation”. Pero si dice “auth: shorten JWT timeouts”, sí quisiera ver una o dos oraciones sobre por qué había que acortar los tiempos de expiración
Los mensajes de commit realmente largos, en la práctica, me parecen bastante poco útiles. Estoy en gran parte de acuerdo con las razones que señala el artículo. Ese formato parece venir de flujos de trabajo donde el mensaje de commit es también la descripción del PR, como los flujos basados en correo electrónico o Gerrit. En esos casos no diría que sea perjudicial, pero tampoco me convence que necesariamente aporte valor
Yo también estoy en una situación parecida. En el grupo más amplio de mi trabajo, los únicos que escribimos mensajes de commit detallados somos yo y otra persona
Aunque sepas por qué se construyó una cerca, puede que no sepas por qué sigue ahí ahora. Incluso si fuiste quien construyó la cerca de Chesterton, no necesariamente sabes si puedes derribarla
El árbol de dependencias intencionales cuando se creó un sistema es solo un subconjunto del árbol de dependencias real en un momento dado. Así que, incluso si un desarrollador perfecto te explicara por completo por qué se construyó la cerca, su utilidad sería limitada
Lo que saben es por qué la construyeron, no la respuesta a “¿qué se rompe si quito esta cerca?”. Basta con ver https://xkcd.com/1172/. Entre los casos de uso graciosos, algunos pueden parecer irrelevantes, pero siempre existen usos legítimos que ni el propio desarrollador original podía conocer
Está bien saber qué pensaba el desarrollador original o qué se había fumado, pero esa información está en algún punto entre incompleta e irrelevante
Como ejemplo inventado, supongamos que la cerca de Chesterton se levantó originalmente para mantener a los niños alejados de un charco cuando todavía había granjas a ambos lados. Ahora se construyó una autopista, y esa cerca podría haberse convertido accidentalmente en la única barrera que evita muertes masivas de animales y personas por choques entre ciervos y autos
Nadie sabe esto. La combinación de autopista + ausencia de cerca no solo no se ha probado, sino que nunca ha existido, y ni quienes construyeron la autopista ni el ministerio de recursos naturales saben por qué hay tan pocos atropellamientos de fauna en esa carretera. En unos años, cuando todas las granjas se conviertan en viviendas y deje de ser un corredor principal de fauna, la cerca podría volverse inútil; o no
Si esto te parece forzado o sientes que no aplica a tu caso, te envidio. En mi experiencia, salvo en empresas de cierto tamaño y que no sean demasiado viejas, así es como suelen funcionar las cosas
La verdad es que todo lo que hacemos forma parte de un ecosistema, y depende de cosas con las que nunca acordamos interactuar explícitamente, y a la vez otras cosas dependen de ello. Se puede reducir la superficie del API y evitar que todos los detalles de implementación se vuelvan asunto del vecino, pero el acoplamiento no intencional se parece más a una ley universal, tan inevitable como el aumento de la entropía
A algunas personas esto les suena nihilista y derrotista. Podrían decir que hay que luchar contra la entropía. Pero creo que el mejor uso del tiempo y el mejor retorno de inversión vienen de aceptar que esto, en el fondo, no es algo contra lo que se lucha, sino algo que se gestiona
Asumir que siempre puedes conocer el estado del mundo es garantizarte el fracaso y la culpa propia. Igual que el 100% de uptime no existe y, para la mayoría de las cosas, es un objetivo equivocado
Si aceptas que estás gestionando un proceso con cierto grado de incertidumbre heisenbergiana, puedes elegir cómo usar de forma efectiva el tiempo limitado que tienes cada día para producir mejores resultados. En particular, eso permite hacer concesiones inteligentes entre respuesta preventiva y reactiva, y entender que no se puede llevar la respuesta reactiva a cero, y que a veces no tiene sentido hacer un año de trabajo preventivo para evitar un solo día de trabajo reactivo
Entonces, ¿cuánta documentación debería escribirse en un commit? ¿Cuántos documentos de diseño o planes de prueba debería haber? No lo sé. Pero si tengo que proponer una idea, sería esta: toda documentación se escribe para un lector
Si cambias el codebase, la gente del equipo actual —y también quienes se incorporen después— debería poder entender, mediante investigación, qué hizo el cambio y por qué se hizo, y también debería haber algunas advertencias sobre trampas peligrosas o bugs que sostienen carga
Esto normalmente no requiere prosa larga, sino más bien punteros hacia contexto adicional que ayude a preparar el escenario. Por ejemplo, algo como “Se exigió autenticación en este paso como parte de la política que requiere aprobación multipartita para todos los cambios. see: go/multiparty”
Los sistemas que buscan la perfección cuando tratan con humanos son realmente incómodos. Cosas como DRM, trusted computing, remote attestation, Faro Plague y smart contracts
Son mucho mejores los sistemas que puedes reiniciar en modo servicio y arreglar. Porque no podemos predecir en qué dirección tendrá que evolucionar el software para ayudar de verdad a las personas. Es mejor hacerlo fácil de modificar que dejarlo bloqueado al 100%
Casi no escribimos cuerpos de commit, pero sí solemos escribir títulos bastante buenos. Si esa es la métrica, no tengo muy claro qué está midiendo
En codebases grandes, código claro y suficiente cobertura de pruebas suelen ser mucho más útiles que la documentación
Puede ocurrir que se haya hecho un cambio completamente válido y que las pruebas se hayan actualizado en consecuencia, pero después siga siendo totalmente poco claro por qué ese cambio era necesario. Más aún si las líneas modificadas producen un comportamiento inesperado o adicional en producción
Un simple revert puede no ser deseable, y en ese momento ayuda muchísimo tener el historial completo de por qué se hizo el cambio
He visto muchos casos donde la idea era correcta, pero aparecieron consecuencias imprevistas. Si conoces la intención, puedes llegar a un cambio realmente correcto que también corrija el nuevo problema y preserve la razón original del cambio
Si vas a insistir en commits de una sola línea, al menos incluye el número del ticket para que el historial pueda leerse ahí
Me gané bastante buen dinero durante 5 años recorriendo regiones exóticas para rescatar codebases como estos. @arp242, siempre sube tus tarifas y duerme con https://archive.org/details/working-effectively-with-legacy-code bajo la almohada
Por suerte, los generadores de porquería con IA sí escriben mensajes de commit gigantescos. A veces incluso tienen cierta relación con el cambio real, así que al menos esa parte ya estaría resuelta