3 puntos por GN⁺ 2023-07-21 | 1 comentarios | Compartir por WhatsApp
  • Estructuras o código que originalmente parecían triviales o temporales pueden, con el tiempo, asumir el rol de sostener el sistema, así que antes de hacer cambios hay que revisar también las dependencias actuales
  • Chesterton's Fence es un principio útil: entender por qué algo se instaló antes de quitarlo, pero si solo se mira la intención original se pueden pasar por alto roles que aparecieron después
  • Durante una remodelación del baño de una casa, un montante vertical que parecía un obstáculo seguía soportando parte de la carga del segundo piso, aun después de que desapareciera su propósito como división de un clóset, debido a cambios estructurales mal hechos
  • En sistemas informáticos complejos, el historial de cambios y los documentos de diseño son solo un punto de partida; también hay que ver cómo un componente está actualmente integrado al sistema
  • Al eliminar o modificar componentes antiguos, si no se revisan al mismo tiempo la razón de diseño del pasado y los roles ocultos del presente, se pueden provocar fallas inesperadas

Lo que Chesterton's Fence puede pasar por alto

  • Chesterton's Fence es la idea de que, antes de cambiar o eliminar algo, primero hay que entender por qué se creó
  • Algo hecho por personas, como una cerca o una puerta, por lo general probablemente tuvo una razón por la que alguien lo consideró útil
  • Incluso un diseño que parece completamente inútil puede indicar que quien quiere modificarlo está pasando por alto algún aspecto del problema
  • Sin embargo, este enfoque puede hacer que uno se concentre solo en el rol que pretendía la persona que lo creó originalmente, y pase por alto nuevas dependencias que surgieron después

Soporte de carga accidental descubierto en una reparación de la casa

  • Hace algunos años, al rehacer el baño de la casa, había un montante vertical que estorbaba el trabajo
  • Ese montante originalmente formaba parte de una división de clóset, y ese rol de división del clóset ya no parecía necesario
  • Si se siguiera solo la perspectiva de Chesterton's Fence, parecía que se podía quitar sin problema, pero en realidad, con el paso del tiempo, se había convertido en una estructura que soportaba carga
    • Tras otros cambios estructurales mal hechos, ese montante estaba contribuyendo a sostener el segundo piso de la casa
  • Hay que verificar no solo por qué se creó algo al principio, sino también qué roles adicionales asumió después

Lecciones aplicables a sistemas informáticos complejos

  • Al cambiar sistemas informáticos complejos, el mismo problema se repite
  • Revisar el historial de cambios, leer los documentos de diseño originales y entender por qué cierto componente se construyó de esa forma sigue siendo útil
  • Pero para que sea seguro, también hay que revisar de qué manera ese componente está actualmente conectado y usado dentro del sistema
  • Con el tiempo, los componentes tienden a asumir roles secundarios distintos de su propósito original
  • Un cambio seguro empieza por verificar juntos la intención de diseño del pasado y el rol real del presente

1 comentarios

 
GN⁺ 2023-07-21
Comentarios de Hacker News
  • Siento que por fin ya hay un nombre para esto
    Trabajo mucho dando soporte a sistemas de control, y no es raro que código PLC que maneja equipo físico de forma peculiar termine creando problemas no intencionales
    A menudo termino repitiendo la frase: “Cada vez que arreglas un problema eléctrico/mecánico con software, nace un gremlin”
    Incluso si encuentro la causa raíz de un bug o una limitación programada que quiero eliminar, siempre me niego hasta entender por qué ese código está ahí. Ningún código entra sin motivo, así que primero hay que averiguar por qué hacen falta ese temporizador o esa redefinición
    A veces resulta que era código que resolvía un problema que ya desapareció, y eso está bien, pero muchas veces también era código puesto para evitar algún accidente, y con los cambios de personal se perdió el propósito original. Sin documentación, uno se vuelve muy cauteloso al revertir de inmediato el trabajo de otra persona
    También está el tema de confiar en tus colegas. Normalmente nadie hace algo porque sí, así que si el código existe, asumo que tiene un propósito y que al principio se revisó lo suficiente. Si esa confianza se rompe, toda toma de decisiones se vuelve difícil

    • Por eso siempre dejo comentarios de por qué en líneas de código que no son totalmente obvias
      Si la razón tiene que ver con interactuar con cosas fuera del codebase, como el sistema operativo, el sistema de archivos, una base de datos, un endpoint HTTP o hardware, entonces lo comento 100%, salvo que sea una simple llamada de API o de librería
      Si metí un sleep por el límite de velocidad de otro servicio, escribo quién lo exige, cuál es el límite según lo que se sabía en ese momento, y si no se sabe con precisión, aclaro que “es una suposición, pero parece funcionar”, además de cómo podría verse el sistema si se excede
      Si se usa una base de datos para algo trivial que parecería resolverse con el sistema de archivos, pero en realidad acceder al sistema de archivos de la forma que hace falta en ese entorno agotaría recursos por llamadas al sistema que se descontrolan bajo carga, también lo comento
      Los workarounds para bugs de librerías muy usadas que Ubuntu no corrige en una versión LTS también merecen comentario. He escrito muchísimos comentarios del tipo “sé que esto no está padre, pero esta es la razón”
      También dejo comentarios cuando escribo código que no va a escalar bien a gran tamaño, porque ahora da flojera hacerlo bien o porque según lo que esperamos ni siquiera será necesario. Tal vez sea más para proteger el orgullo, pero cosas como: “sí, sé que esto lee todo el archivo en memoria, pero es un batch raro y predecible, y el archivo debería ser pequeño, así que está bien. Si falta memoria, revisa aquí primero. Si vas a cambiarlo a llamadas on-demand, reescríbelo”
    • Me parece que eso es simplemente la lógica general de la valla de Chesterton
      Lo que el texto quiere señalar es que eso por sí solo no basta. También hay que entender qué otras cosas se construyeron asumiendo que ese código estaba ahí
    • El comentario más inquietante que vi en las profundidades de un PLC Allen Bradley fue este
      “No sé por qué hace falta este rung, pero bórralo y compruébalo tú mismo”
      No lo toqué sin necesidad, y tampoco lo comprobé
    • Parte de esto también es cultural
      Históricamente, los ingenieros eléctricos y mecánicos han tendido a tomar el software menos en serio que los sistemas eléctricos y mecánicos, y como resultado, en culturas de ingeniería dominadas por EE/ME es fácil terminar con código desastroso
      Incluso entre personas que formalmente son Professional Engineer, sigue siendo común ver ingeniería de software tan inmadura que resulta difícil de aceptar
    • Creo que nunca volveré a trabajar con PLC
      Dejando de lado el código sin documentación, por lo general el hardware con el que trabajas fue hecho a la medida hace 30 años, así que ni siquiera existe el diagrama eléctrico del equipo
  • Me pasó algo parecido
    Hace unos años compré una casa vieja, y los dueños anteriores habían hecho ellos mismos la mayor parte del trabajo desde los años 60
    Una canaleta de zinc probablemente tuvo fugas durante décadas y dañó parte de la estructura del techo, y el techo estaba sostenido por paneles de madera que habían pegado en los 70 para cubrir el interior. O sea, esos paneles de madera eran los que realmente estaban soportando la carga
    En esta casa encontré muchas más cosas así. Por ejemplo, como les faltaba ancho de tejas en el borde del techo, en vez de comprar más tejas rellenaron el espacio con cemento y pedazos de macetas de cerámica rotas

    • Si te vas a inicios de los 1900, el revestimiento exterior instalado en diagonal ayudaba mucho a evitar que el edificio se deformara
      Hoy en día ese papel se delega al tablarroca y al contrachapado frente a sismos y tormentas
      Si ves una casa reconstruida dejando solo la estructura, seguramente notarás que se añadieron algunos refuerzos. No es para que las paredes no se caigan, sino para mantener escuadra y planeidad hasta que vuelvan a levantar las paredes
    • Mi cochera se siente exactamente así
      A primera vista parece que alguien chocó la puerta de la cochera y la dejó muy abollada, pero viéndolo bien, el techo apenas se sostiene sobre el riel donde va la puerta y está casi al borde del colapso
      Al principio quería solo cambiar la puerta y empalmar los extremos de las vigas, porque alguien ya había hecho eso en el lado opuesto antes y parecía funcionar, pero ahora creo que tendré que rehacer todo el techo
      Lo que sí me preocupa de verdad es el cableado sospechoso por todo el sótano. Hay una mezcla de cables relativamente nuevos, cable viejo con aislamiento de tela y cinta aislante uniendo cosas. Por suerte, no parece que haya cables soportando carga
    • Ya faltan pocas etapas para llegar a pintura que soporte carga
    • Hubo una casa con daños gravísimos por termitas, y el contratista lo llamaba estuco estructural
  • Parece que este texto y casi todos los comentarios están pasando por alto el problema real. La clave es la falta de pruebas
    El software, a diferencia de prácticamente cualquier otro medio de producción, sí permite probar cambios en la práctica antes de reflejarlos en la realidad
    Si hay buenas pruebas, no importa cuál era la intención original ni si esa función adquirió un nuevo uso o nuevos usuarios. Lo corriges, ejecutas las pruebas y eso te dice si el cambio fue bueno
    Si hay buenas pruebas, no hacen falta la arqueología de software, los veteranos curtidos que conocen cada grieta, los prodigios que modelan sistemas complejos en su cabeza, los documentos exhaustivos de requisitos ni los sistemas de despliegue cuidadosos que usan a ciertos grupos de usuarios como conejillos de indias
    Si hay buenas pruebas, incluso podrías cambiar el sistema al azar y detenerte cuando aparezca una mejora. Es exactamente igual a cómo Google reportó que la IA “desarrolló” mejoras de ranking
    Y aun así, a los desarrolladores de pruebas se les paga menos de la mitad, los departamentos de pruebas son relativamente pequeños, QA está presionado por calendarios fijos y limitados, y casi no hay héroes técnicos que vengan de QA. Supongo que es porque parece un trabajo derivado y reactivo

    • Aunque las pruebas verifiquen el comportamiento para el que se diseñó el código, puede ocurrir que otros sistemas dependan de lo que el código realmente hace
      Puede que elimines código que no se usa y sus pruebas, y en realidad todavía se esté usando
      Puede que una prueba falle después de un cambio, pero como la prueba era frágil la actualices para la nueva situación, y luego resulte que algo dependía del comportamiento anterior
      Las pruebas son excelentes, y en sistemas suficientemente autocontenidos pueden bastar por sí solas. Pero en sistemas más grandes, a veces también hacen falta la telemetría y los despliegues graduales
    • Las pruebas tienen un alcance específico. Cubren el alcance del que el código debería responsabilizarse, pero muy probablemente no cubren todo lo que, tras meses o años de uso, ahora se espera que haga
      El código original era para calcular el IVA de una lista de compras, pero poco a poco puede terminar siendo una forma de forzar la actualización de la caché de IVA por categoría de producto y ser llamado desde contextos que al principio nadie anticipó
      Lo mismo pasa con los comentarios. Cubren la intención original y los efectos secundarios, pero no pueden cubrir dónde termina usándose ese método o clase mucho tiempo después ni qué es lo que en la práctica terminó haciendo
      En un mundo ideal, los comentarios también se actualizarían cuando cambia el mundo alrededor, pero en la realidad casi nunca pasa a menos que también cambie el código interno
    • Si trabajas en proyectos que duran muchísimo tiempo, descubres que las pruebas o un QA bien financiado no evitan los problemas organizacionales
      Normalmente las pruebas se pudren. Parece que también tienen fecha de vencimiento, y con el tiempo algunas empiezan a morir
      Se mezclan problemas de dependencias, cambios en las expectativas de la API, actualizaciones de seguridad, vencimiento de cuentas y credenciales, cambios en endpoints y estados de máquinas, y el resultado es que las pruebas dejan de indicar si el programa es correcto o no
      El valor de negocio marginal de arreglar una sola prueba rota suele ser muy bajo, así que muchas veces simplemente se desactiva o se fuerza a que “pase” aunque debería dar error
      Después de 10 o 20 años de repetir esto, enseguida se separan las “pruebas en las que realmente confiamos” de las “pruebas que estamos demasiado ocupados para arreglar o limpiar”
      Saber qué pruebas son buenas o malas se vuelve conocimiento tribal que desaparece con los cambios de puesto y de rol, y en algún momento ese bloque de “pruebas que mienten diciendo que todo funciona” y “pruebas cuyo fallo ya nadie investiga para ver si dice la verdad” termina accidentalmente soportando carga
    • La primera parte parecía repetir el optimismo del desarrollo guiado por pruebas, pero de pronto pasa a hablar del departamento de pruebas y pierde coherencia
      Sería mejor decir que los programadores deberían escribir las pruebas, guardarlas junto con el código y ejecutarlas automáticamente durante el proceso de build
      Pero incluso un desarrollo guiado por pruebas bien hecho no puede reemplazar un buen diseño ni las buenas prácticas. Ni siquiera una especificación muy simple puede sustituirse por pruebas
      Si solo se especifica que f(S) devuelve la cadena concatenada consigo misma, es difícil verificar que f es correcta usando únicamente pruebas obvias que traten a f como una caja negra. La especificación formal también importa
      Puedes probar unos cuantos puntos, pero si una sola salida incorrecta es catastrófica, las pruebas no van a mostrarlo
      Se puede satirizar la arqueología de software, a los veteranos curtidos, a los prodigios que modelan sistemas en su cabeza, a los documentos exhaustivos de requisitos y a los sistemas de despliegue que usan a algunos usuarios como conejillos de indias, pero todos existen como respuesta a que el software es difícil. Y el software realmente es difícil
    • La propia separación entre desarrolladores de pruebas, departamentos de pruebas y equipos de QA es casi un lujo en la mayoría de las organizaciones de software
      Por lo general, los equipos de software tienen que asumir directamente la responsabilidad de la calidad de su propio trabajo y no pueden pasar el problema a otra parte de la organización
  • Entiendo que un stud que no era importante después termine soportando carga, pero en mi experiencia eso parece una señal de diseño perezoso
    Al menos al hacer software, uno puede darse cuenta de que está intentando hacer que una parte de la casa se sostenga con studs decorativos, y si decide simplemente dejarlo así en vez de crear una estructura nueva mejor, después el equipo de desarrollo termina bastante deprimido
    Estoy de acuerdo con el artículo, pero es mucho mejor trabajar en un lugar donde se pueda esperar no encontrarse con este tipo de descubrimientos tan seguido

    • En lo que hiciste “tú”, quizá “tú” puedas saberlo, pero en mi carrera me ha tocado mucho más lidiar y rehacer cosas hechas por otros
      El punto del artículo no es tanto “no uses studs decorativos como elementos de carga”, sino más bien reconocer que alguien pudo haberlo hecho antes de que llegaras
      Es una postura incluso más conservadora que la interpretación básica de la valla de Chesterton, y hasta esa interpretación básica mucha gente la descarta por considerarla demasiado restrictiva
      A mí este artículo me llega. En términos de programación, realmente me ha pasado que quité una moldura “decorativa” y el techo se me vino encima
    • ¿Siempre es flojera en el mal sentido? En software no hay una división tajante entre “hecho para soportar carga” y “hecho para sujetar panel de yeso”
      Que un sistema sea robusto o peligrosamente imposible de escalar depende del contexto
      Siempre se pueden hacer experimentos mentales como “¿y si duplicamos el equipo de ventas y vendemos e incorporamos clientes lo más rápido posible hasta capturar el 100% del mercado?”, y hasta bajo esas condiciones podría estar bien usar la base de datos como cola de mensajes
      Si el resultado fue que el equipo de desarrollo la pasó mal, entonces fue un error. Se volvió difícil de mantener o un infierno operativo
      Pero usar studs decorativos del software como elementos de carga no siempre lleva a ese resultado. También hay muchos sistemas que hacen su trabajo felices y sin llamar la atención, mientras te ahorran meses de construir la solución “correcta”
    • Supongamos que escribes código de forma defensiva. Agregas manejo de entrada inválida a una función
      El resto del codebase nunca envía entradas inválidas, así que esa rama es código muerto y no soporta carga
      Luego en algún momento entra un bug que sí manda una entrada inválida, y esa rama la procesa diligentemente y se recupera. En ese momento esa rama se convierte en una rama portante
    • Pensabas que estabas operando bien un servicio sin importancia, y cuando hubo una caída descubriste que otro equipo había empezado a depender de eso para una función crítica del negocio, en una situación que originalmente no debía ser nada del otro mundo
    • Lo que he visto con más frecuencia, en realidad, es que estas cosas pasan precisamente porque uno no lo sabe
  • De los artefactos “accidentalmente portantes” que he visto, mi favorito fue un sudo mal configurado
    Permitía sudo sin contraseña para el comando find, así que era fácil ejecutar código arbitrario como root usando -exec, y varios scripts de soporte importantes del producto estaban escritos para usar eso
    Era una especie de escalación de privilegios portante

  • Hace unos años remodelé la cocina
    En un extremo de la cocina vieja había una viga grande, agregada en alguna remodelación anterior a que compráramos la casa para poder levantar un segundo piso. Para ampliar la cocina había que quitarla
    Al abrir el techo descubrimos que la viga estaba como a 2 pies a la derecha de donde debía estar para sostener la pared del piso de arriba
    Al final se corrigió y se movió la viga hacia dentro de la pared del piso superior, y todo quedó bien, pero cuando preguntamos por su posición original el contratista dijo más o menos esto
    “Había una persona que quería hacerlo bien y otra a la que no le importaba. La calidad al final se ajusta al valor mínimo

  • Una ventaja del software frente a los sistemas físicos es que es mucho más fácil documentar la intención dentro del código con comentarios y tipos, para dejarla más clara
    En lenguajes dinámicos como Python no es perfecto, pero ayuda muchísimo
    La analogía del stud portante podría ser un proyecto de hackatón que no pensabas que iba a terminar en producción
    En realidad, mucho de lo que hacemos consiste en hackear algo hasta que apenas funcione, y luego pasar a la siguiente cosa

    • Sí. Problemas exactamente así fueron la razón de introducir la ingeniería de sistemas en el sector aeroespacial y de defensa
      Los planes de mantenimiento necesitan saber qué “cargas” soporta cada pieza o ensamblaje reemplazable
      Por desgracia, la ingeniería de sistemas actual se ha alejado muchísimo de ese objetivo original, pero esa era la idea inicial
      Una de las razones por las que hoy los departamentos de ingeniería de sistemas tienen relativamente poco poder es que finanzas se metió en la planificación del mantenimiento. La depreciación del inventario es brutal, y “qué debe mantenerse como repuesto” rara vez es ya una decisión de ingeniería de sistemas, al menos en mi experiencia
      El resultado es predecible, aunque se compensa un poco porque el estándar del personal de mantenimiento aeroespacial es muy alto. Comparados, por ejemplo, con un técnico de lavadoras, suelen estar en otro nivel
      Claro, finanzas también quisiera bajar ese estándar varios escalones
    • Si es intencional, es fácil hacerlo así
      Pero siempre me sorprende con qué frecuencia uno ve sistemas donde un componente aguas arriba que parece “decorativo” en realidad está imponiendo un límite de velocidad, y si lo quitas el resto se descontrola
  • Me hace pensar en cuando los usuarios aprovechan un bug del software sin darse cuenta e integran ese comportamiento a su flujo de trabajo normal
    Como resultado, cuando corriges el bug, el flujo de trabajo se rompe y llega la inconformidad

  • Dice “era fácil ver por qué estaba ahí. Era parte de la división de un clóset”, pero con el tiempo terminó soportando carga por accidente, y a través de otros cambios estructurales erróneos ese stud ahora ayudaba a sostener el segundo piso de la casa
    Pero claramente no era tan fácil ver por qué estaba ahí. Además, tampoco me convence eso de que hubiera terminado soportando carga por accidente
    Aunque a ti te parezca una razón equivocada, también parece bastante posible que lo hayan hecho intencionalmente portante por motivos que para la gente de entonces sí tenían sentido

    • Sí se podía saber por qué estaba ahí
      Solo que saber por qué estaba ahí al principio no te dice qué está haciendo ahora
  • Un posdoctorado en física con el que trabajé antes solía pegar a veces este tipo de letreros encima de configuraciones de equipo
    “No tocar. Hay peligro oculto”
    El laboratorio estaba lleno de gente inteligente, acostumbrada a mirar algo y sacar por sí sola una conclusión razonable sobre si se podía cambiar
    El letrero era una advertencia para no apresurar demasiado ese juicio