"Nos faltan columnas" - La mejor y la peor base de código
(jimmyhmiller.github.io)"¿La tabla
merchants2? Sí, creamosmerchants2porque amerchantsle faltaban columnas."
- Cuando empecé a programar, no sabía que la gente ganaba dinero programando
- Aprendí muchísimo en mi primer trabajo de software, y la base de código de ese lugar fue lo peor y lo mejor al mismo tiempo
Las bases de datos sobreviven para siempre
- En un sistema legado, la base de datos hace más que solo almacenar datos. Define las restricciones de todo el sistema y es el punto donde se encuentra todo el código
- SQL Server tiene un límite en la cantidad de columnas por tabla. En ese entonces era 1024; ahora es 4096. Como faltaban columnas en la tabla
Merchants, crearonMerchants2(con más de 500 columnas) MerchantsyMerchants2eran el núcleo del sistema. Todo estaba conectado conMerchants. Había otras tablas normalizadas, pero también tenían relaciones de clave foránea conMerchants
SequenceKey
SequenceKeyera una tabla simple con una sola columna y un solo valor- Se usaba para generar IDs. Supongo que se creó porque SQL Server no soportaba IDs autoincrementales
- Todos los procedimientos almacenados tomaban una clave de
SequenceKey, la incrementaban y la usaban como ID en varias tablas. Funcionaba como una unión implícita
Calendar
Calendarera una tabla de calendario ingresada manualmente. SiCalendarexpiraba, no se podía iniciar sesión en el sistema- Esto pasó hace algunos años y un pasante agregó cinco años más. Nadie sabe qué sistema usa eso
Employees
- Todos los días a las 7:15 de la mañana, la tabla
employeesse borraba y se volvía a llenar con un CSV recibido de ADP - Durante ese proceso no se podía iniciar sesión en el sistema. A veces este trabajo fallaba
- Como los datos tenían que replicarse a la oficina central, se los enviaban por correo a una persona para que cada día apretara un botón y copiara los datos
La base de datos de reemplazo
- Uno podría pensar que se podía limpiar la base de datos. La empresa también lo pensó
- Había una copia de la base de datos, pero los datos tenían un retraso de unos 10 minutos. La sincronización ocurría solo en un sentido
- Esta base de datos estaba normalizada, así que para encontrar un número de teléfono en
merchantshacían falta 7 joins
Resultados de ventas
- Todos los vendedores tenían una cuota mensual llamada "win" que debían alcanzar
- La tabla que gestionaba esto era extremadamente compleja. Cada día corría un proceso que buscaba filas agregadas o modificadas y las sincronizaba con el sistema de la oficina central
- El problema empezó cuando un vendedor pidió que le cambiaran un registro manualmente
- Ese vendedor ya había alcanzado su win e hizo además una venta grande ese mismo mes, pero quería moverla al mes siguiente
- Un pasante se hizo cargo de esto y, cuando el rumor se extendió, las solicitudes crecieron exponencialmente durante 3 años
- Hubo un momento en que 3 pasantes se dedicaban por completo a escribir sentencias SQL. Crear una aplicación para esto se consideraba demasiado difícil
La base de código
- La primera base de código que conocí estaba en Team Foundation Server, un sistema de control de versiones centralizado
- La base de código en la que más trabajé estaba mitad en VB y mitad en C#. Corría sobre IIS y usaba estado de sesión por todos lados
- Eso significaba, en la práctica, que si llegabas a una página por la Ruta A o por la Ruta B, veías cosas muy distintas en esa misma página
- Todos los frameworks de JavaScript que existían en ese entonces estaban versionados en ese repositorio, casi siempre con modificaciones personalizadas que su autor creyó necesarias. Se notaban especialmente
knockout,backbone,marionette, además dejqueryy plugins dejquery - Además de esta base de código, había unas 12 aplicaciones SOAP y varias aplicaciones nativas de Windows
El disco duro de Gilfoyle
- Gilfoyle tenía fama de ser un programador absurdamente rápido. Nunca lo conocí, pero lo conocía por su código y por el código que quedaba en su disco duro
- Munch guardaba el disco duro de Gilfoyle en configuración RAID sobre su escritorio, aun años después de que Gilfoyle se fuera de la empresa
- Porque Gilfoyle era famoso por no hacer check-in de su código y por crear aplicaciones arbitrarias, de un solo uso, de Windows, para usuarios individuales
- No era raro que un usuario llegara con un reporte de bug de una aplicación que existía únicamente en el disco duro de Gilfoyle
El bug de envíos
- Gran parte de mi trabajo consistía en rastrear bugs que el equipo no quería asignarse
- Había un bug particularmente molesto que aparecía cada ciertos meses: pedidos que, después de enviarse, quedaban atorados en la cola de envíos y aparecían como no enviados aunque ya se habían enviado
- Para resolverlo probamos distintas soluciones (scripts SQL, aplicaciones de Windows, etc.). Me aconsejaron no rastrear la causa raíz, pero no pude evitarlo
- En el proceso aprendí a pensar como Gilfoyle. La app de envíos traía toda la base de datos, luego filtraba por fecha y conservaba todos los pedidos posteriores a la fecha de inicio de la aplicación
- La app dependía de un servicio SOAP, pero no para hacer cosas propias de un servicio, sino como si fuera una función pura. El cliente causaba todos los efectos secundarios
- En ese cliente encontré una jerarquía gigantesca de clases: 120 clases, cada una con varios métodos, y herencia de hasta 10 niveles
- El único problema era que todos los métodos estaban vacíos
- Eso existía para crear una estructura que pudiera usar reflexión. Esa reflexión armaba una cadena separada por pipes (basada en la base de datos, pero completamente estática) y la enviaba por socket
- Al final eso se enviaba a Kewill, un servicio que se comunicaba con el transportista. El bug ocurría porque Kewill reutilizaba cada mes números de 9 dígitos, y alguien había desactivado un
cronque borraba pedidos antiguos
Un caos hermoso
- Podría decir mucho más sobre esta base de código: el equipo de desarrolladores senior que pasó 5 años reescribiéndola toda sin liberar código, o los consultores de Red Hat que construyeron una sola base de datos para controlarlo todo
- Esta base de código tenía muchísimos rincones de locura, y muchas razones por las que habría valido la pena tener un equipo dedicado solo a rehacer una funcionalidad desde cero
- Pero la historia más importante es la de cómo Justin mejoró la página de búsqueda de comerciantes. Esa página era el punto de entrada de toda la aplicación
- Todos los representantes de servicio al cliente hablaban por teléfono con comerciantes e ingresaban un ID o un nombre para buscar su información. Luego iban a una página enorme con toda la información
- Esa página estaba llena de toda la información necesaria y de todos los enlaces a los que uno querría entrar; era densa de información en el mejor sentido posible. Pero era increíblemente lenta
- Justin era el único desarrollador senior de mi grupo. Era inteligente, sarcástico y no tenía demasiado interés en el negocio
- Decía las cosas de frente, no se guardaba nada, y siempre podía resolver solo un problema más rápido que los equipos de alrededor
- Un día Justin se cansó de escuchar lo lenta que era la página de búsqueda de comerciantes, así que fue y la arregló
- Cada recuadro de la pantalla se convirtió en su propio endpoint. Al cargar, todo lo que estaba above the fold empezaba a obtenerse, y cuando una cosa terminaba de cargar entraban más requests
- El tiempo de carga de la página pasó de varios minutos a menos de un segundo
Dos formas de desacoplar
- Justin pudo hacer eso porque esta base de código no tenía un plan maestro
- No había un plano general al que el sistema tuviera que ajustarse, ni un formato esperado para la API, ni un sistema de diseño documentado, ni un comité de revisión de arquitectura que garantizara consistencia
- La aplicación era un desastre total. Nadie podía arreglarla, así que nadie lo intentaba. En vez de eso, construíamos nuestros propios pequeños mundos de cordura
- Esta app monolítica fue creciendo en los bordes, por pura necesidad, como un microcosmos de buenas apps pequeñas
- Cada persona encargada de mejorar una parte de la app inevitablemente renunciaba a intentar deshacer esa telaraña, encontraba un rincón bueno y pequeño donde construir algo nuevo, y luego actualizaba lentamente los enlaces para apuntar a lo nuevo y dejar huérfano lo viejo
- Esto puede sonar desastroso. Pero era sorprendentemente agradable trabajar ahí. Desaparecía la preocupación por la duplicación de código, también la preocupación por la consistencia, y también la preocupación por la escalabilidad
- El código se escribía para usarse, tocando lo menos posible las áreas de alrededor y de forma que fuera fácil reemplazarlo. Nuestro código estaba desacoplado porque simplemente era más difícil acoplarlo
Después de eso
- Nunca más en mi carrera he tenido el privilegio de trabajar en una base de código tan maravillosamente fea
- Todas las bases de código feas que conocí después no lograron trascender la necesidad de consistencia
- Tal vez porque los desarrolladores "serios" abandonaron la base de código hace mucho tiempo. Lo único que quedó fueron pasantes desordenados y desarrolladores junior
- O tal vez porque no había una capa intermedia entre los desarrolladores y los usuarios. No había traducción, ni levantamiento de requisitos, ni tarjetas. Solo estabas parado frente al escritorio de una persona de servicio al cliente preguntándole cómo podías mejorar su vida
- Extraño esa conexión directa. El feedback rápido, no tener que hacer planes grandiosos, la conexión entre problemas simples y código
- Tal vez sea solo nostalgia ingenua. Pero así como a veces quiero volver a algunos de los peores años de mi juventud, cada vez que me enfrento a los "patrones de diseño empresariales", mi mente vuelve a esa base de código hermosa y terrible
Opinión de GN⁺
- Este texto puede dar empatía y consuelo a desarrolladores que lidian con sistemas legados. Muestra que incluso una base de código imperfecta puede tener valor y mucho que enseñar
- Pero no se deben romantizar los problemas de esta base de código. Cuando la deuda técnica se acumula, la velocidad de desarrollo cae mucho y el mantenimiento se vuelve difícil. A largo plazo, cuesta más
- Renunciar a mejorar la base de código y seguir apilando parches no es la respuesta. Hace falta una estrategia para mejorar gradualmente o migrar el sistema legado
- La cultura y los procesos de desarrollo también importan. Seguir buenas prácticas de ingeniería, como code review, diseño de arquitectura y documentación, ayuda a construir una mejor base de código
- La comunicación cercana con los usuarios y el feedback rápido son puntos positivos. Lo ideal es fomentarlos con metodologías como Agile sin dejar de gestionar la calidad del código
- Al final, todo es una cuestión de equilibrio. Más que perseguir la perfección, lo importante es satisfacer las necesidades de los usuarios de forma sostenible y gestionar la deuda técnica
3 comentarios
En mi primer trabajo, como desarrollador de firmware, la tarea que me dieron fue analizar el código ensamblador extraído del
hexde un MCU 8051 de un producto del que no había desarrolladores ni código fuente, y reimplementarlo en C…Por suerte había un producto que al menos funcionaba, así que entre revisar el código y probar el producto, de algún modo logré sacarlo adelante…
También llegué a escuchar amenazas de que, o lo arreglaba durante un viaje de trabajo a provincia, o me cortara un dedo antes de volver,
y hubo una vez en que un bug inexplicable resultó que en realidad era por un elevador que estaba detrás de la pared donde estaba instalado el equipo,
y también me acuerdo de haber entrado antes de la apertura oficial del recinto de la cumbre APEC en Dongbaekseom, Busan, para instalar varias cosas jaja
Opiniones de Hacker News
En su primera empresa mantuvo una aplicación compleja en VB
En su primer trabajo dio mantenimiento a un producto legado escrito en COBOL y Java
Refactorizó un script de Perl de más de 12,000 líneas
Sintió la diferencia entre la teoría y la práctica
El codebase del cliente de Telegram para Android era extremadamente complejo
En su primer trabajo resolvió un problema de memoria en un proceso de reportes
Le gustó la experiencia de resolver problemas comunicándose directamente con los clientes
Construyó un sistema que daba soporte a varios mercados
En su primer trabajo había muchas personas con poca experiencia
Explicó cómo resolver problemas en SQL Server moderno
La tabla de numeración (
SequenceKey) y la tabla de días hábiles (Calendar)Qué recuerdos. No sé cómo se hace ahora, pero antes eran tablas de uso común. Cuando hacías proyectos de SI, las funciones relacionadas se implementaban en la parte común del negocio.