1 puntos por GN⁺ 8 시간 전 | 1 comentarios | Compartir por WhatsApp
  • En el proceso de modernizar la cadena de suministro de más de 435 tiendas y centros de distribución, adoptaron Haskell, y 8 años después cerca de 1 millón de líneas de código gestionadas por varios equipos operan en sistemas centrales de producción
  • Haskell reduce tipos de errores en tiempo de ejecución y facilita el refactoring con GHC y la integración con sistemas legacy, pero exige asumir el mantenimiento propio por la falta de SDKs y la complejidad de las funciones avanzadas de tipos
  • El éxito dependió más de la capacidad y la cultura del equipo que del lenguaje; por fugas de espacio y la salida de desarrolladores clave en equipos sin expertos en Haskell, en dos proyectos la adopción no logró consolidarse
  • El runtime de GHC nunca ha sido la causa de incidentes de producción en H-E-B, y a medida que el ecosistema evolucionó con HLS, OpenTelemetry y profiling, Haskell en producción se volvió una opción competitiva
  • Las funciones avanzadas deben limitarse a pequeñas librerías e interfaces claras, junto con pruebas, observabilidad y compartir conocimiento; en la era de los agentes de código, la validación de tipos de GHC y la retroalimentación rápida cobran aún más importancia

El reto de modernizar el mainframe

  • A los clientes de H-E-B, la mayor empresa minorista privada de Texas, les importa más ver los estantes llenos que los sistemas internos
  • Durante décadas, los mainframes COBOL operaron de forma estable, pero en los últimos 10 años aparecieron funciones centradas en la tecnología como pickup en la acera, entrega a domicilio, inventario en tiempo real y búsqueda dentro de la tienda
  • Al expandir la operación de la cadena de suministro a más de 435 tiendas y los centros de distribución que las respaldan, los sistemas centrales existentes empezaron a recibir exigencias que superaban el alcance para el que fueron diseñados originalmente
  • La dificultad clave de modernizar el mainframe no está en mover el código a la nube, sino en preservar el conocimiento propio de la organización acumulado durante décadas dentro de la lógica de negocio legacy
  • Dividir un monolito con cientos de tablas en microservicios propiedad de equipos de ingeniería autónomos es un trabajo enorme, costoso y complejo tanto técnica como políticamente

Adopción de Haskell y escala de operación

  • Los consultores propusieron Haskell como lenguaje común para un proyecto nuevo que reemplazaría la mayor aplicación de mainframe de la empresa
  • Lo que comenzó como un experimento creció hasta convertirse en varios sistemas críticos de producción para la cadena de suministro
  • Ocho años después de la adopción, varios equipos de distintos dominios mantienen cerca de 1 millón de líneas de código Haskell
  • La operación prolongada en producción dejó ver no solo resultados reales, sino también dificultades técnicas y organizacionales

Ventajas obtenidas en el negocio

  • Lo que una empresa busca no es la evaluación perezosa, las funciones puras ni los datos inmutables por sí mismos, sino un sistema tipo COBOL de nueva generación que funcione 40 años sin null pointer exceptions y con bajo costo de mantenimiento
  • Las aplicaciones Haskell eliminan por defecto tipos de errores en tiempo de ejecución comunes en programas imperativos y de tipado dinámico
    • Los bugs no desaparecen por completo, pero los problemas que quedan se concentran en errores de lógica de negocio más que en null pointer exceptions o confusiones de tipos
  • En una migración legacy de años con enfoque strangler fig, GHC facilita el refactoring seguro
    • Permite modificar repetidamente mientras los requisitos van tomando forma, haciendo posible una migración ágil en lugar de una de tipo cascada
    • La empresa puede medir resultados de forma gradual en lugar de invertir por adelantado en un resultado fijado prematuramente
  • Los parsers de Haskell permiten usar directamente formatos legacy de miles de líneas, como copybooks IBM de ancho fijo, como contratos
  • Gracias a una poderosa interfaz de funciones externas (FFI), también puede integrarse con servicios existentes que solo ofrecen librerías en C
    • H-E-B escribió librerías Haskell que envuelven simdjson C++, Oracle ODPI-C e IBM MQ

Falta de SDKs y propiedad sobre los contratos

  • Cuando faltan SDKs de Haskell, hay que crear directamente el cliente y el código de integración necesarios y seguir dándoles mantenimiento
  • A cambio, se obtiene control directo sobre el contrato, se evita el lock-in con el proveedor y no hace falta esperar a que un mantenedor externo publique una corrección
  • En H-E-B consideraron que este intercambio valía totalmente la pena para las dependencias críticas
  • Los agentes de código pueden encargarse bien del trabajo mecánico de portar librerías de Go a Haskell, reduciendo la diferencia de velocidad de desarrollo entre lenguajes
    • Sin embargo, una traducción simple puede no aprovechar del todo las ventajas del sistema de tipos de Haskell si no hay prompts sofisticados

Integración multilenguaje mediante DSL embebidos

  • Haskell tiene fortalezas como lenguaje anfitrión para DSL embebidos (eDSL)
    • Un equipo central puede definir una vez el modelo de dominio o la lógica de negocio y luego generar código con tipos seguros en los lenguajes que usan otros equipos
    • Otros equipos pueden integrarse con ese sistema sin escribir Haskell directamente
  • Hydra es un framework open source de DSL que evolucionó a partir del trabajo de Uber con datos de grafos
    • Se bootstrappea en Haskell y genera implementaciones semánticamente equivalentes en Java, Python, Scala y otros lenguajes
    • Garantiza la equivalencia entre implementaciones por lenguaje con una suite de pruebas compartida
  • H-E-B está prototipando un DSL en Haskell para que equipos de Haskell, TypeScript y Java puedan compartir cálculos financieros sensibles
  • También construyeron un DSL bidireccional para esquemas JSON
    • Similar a autodocodec, pero usando una codificación tagless final que permite a los usuarios extender la semántica central con sus propias type classes
    • Estandariza el versionado de esquemas, la generación de documentación y OpenAPI, y las pruebas de regresión y golden tests
    • Es posible escribir intérpretes ad hoc para convertir esquemas JSON en definiciones de tablas PostgreSQL o reemplazar aeson por simdjson aplicando validaciones adicionales

Contratación y cultura de ingeniería

  • Como los lenguajes modernos también ofrecen muchas funciones de seguridad de tipos, pureza y concurrencia influenciadas por Haskell, la diferencia real está en la cultura de ingeniería que el lenguaje fomenta
  • Haskell atrae a desarrolladores que valoran la precisión y el diseño de abstracciones
  • Contratar para roles de Haskell no fue tan difícil como esperaba la dirección
    • Hubo candidatos que aplicaron por Haskell en sí, aun sin tener un interés especial en cadena de suministro

Los límites del presupuesto de complejidad

  • Haskell es un lenguaje antiguo con varios defectos, por lo que es importante mantenerse al día con las versiones recientes de GHC
  • Si el equipo no tiene expertos, un defecto del lenguaje puede propagarse a todo el proyecto
  • Al inicio, consultores experimentados establecieron guardrails para evitar el uso excesivo de extensiones del lenguaje y operadores personalizados
  • En la época en que no existían las ediciones del lenguaje GHC2021 y GHC2024, cada equipo gestionaba su propio conjunto base de extensiones
    • Eso funcionaba como un presupuesto de complejidad que limitaba el alcance del lenguaje que una nueva persona debía aprender antes de contribuir
  • Las dependencias también consumen presupuesto de complejidad, así que es difícil imponerlo a nivel organizacional
    • servant expresa APIs como un DSL a nivel de tipos, y extenderlo con combinadores personalizados implica type families y errores difíciles de entender
    • haxl modela todas las fuentes de datos como GADTs indexados por tipo de resultado para agrupar trabajo concurrente
  • Cuanto más se especializan los desarrolladores, más crece la tentación de introducir patrones como GADT, type family, generic, tagless final, arrow, free structure y higher-kinded data type
    • Cuando esos conceptos se apilan sobre dominios de negocio ya complejos, se debilita la promesa de mantenimiento sencillo
    • Como las funciones avanzadas aumentan gradualmente a medida que uno se familiariza con el ecosistema, el incremento de complejidad puede notarse tarde

Principios operativos del Haskell aburrido

  • A nivel organizacional es fácil recomendar Haskell aburrido, pero difícil imponerlo
  • Si se encapsula Haskell avanzado detrás de interfaces razonables, se reduce el área de impacto y el presupuesto de complejidad puede limitarse a pequeñas librerías gestionadas por unos pocos expertos
  • La complejidad a nivel de lenguaje no es un problema exclusivo de Haskell, pero Haskell destaca por la amplitud de herramientas avanzadas disponibles
  • Más que las líneas de código o la cantidad de tokens, lo que mejor muestra la complejidad de un proyecto Haskell es cuánto código se rompe en la siguiente actualización de GHC

Dos proyectos donde no logró asentarse

  • Haskell puede potenciar a un equipo y al mismo tiempo convertirse en barrera para otro, y en H-E-B no logró asentarse en dos proyectos por razones distintas
  • En el primer caso, desarrolladores experimentados pero sin experiencia en Haskell siguieron las plantillas y convenciones de otro equipo, pero una fuga de espacio (space leak) detuvo por completo el programa
    • Como ningún desarrollador fuerte de Haskell pudo guiar al equipo, ese solo problema llevó a detener el proyecto
  • En el segundo caso, los ingenieros que apoyaban Haskell y habían construido la aplicación fueron movidos a otros proyectos por un cambio de prioridades
    • Esa razón no tenía relación con el lenguaje en sí
  • Ambos equipos tenían la alternativa de volver a tecnologías previas y no estaban convencidos de que Haskell elevara su productividad
  • Si existe una vía de escape como una plantilla Spring Boot, puede debilitarse la motivación para diagnosticar a fondo una fuga de espacio difícil
  • Ahora que los LLM pueden traducir mecánicamente una base de código completa, las opciones de reescritura son aún mayores
  • La defensa a largo plazo no es código tan ingenioso que resulte difícil de reescribir, sino un equipo que quiera seguir manteniendo Haskell

Incidentes de producción y diagnóstico

  • Incluso en los equipos que sí adoptaron Haskell ocurrieron varios problemas serios
  • El runtime de GHC nunca ha sido la causa raíz de incidentes de producción en H-E-B
  • El throughput en estado estable y el uso de memoria fueron suficientemente competitivos para las cargas de trabajo de H-E-B, y los casos problemáticos fueron excepciones, no la norma
  • Los ingenieros resolvieron los problemas rastreando core dumps por segmentation fault, métricas de garbage collection y perfiles de heap
  • No debe sacrificarse la cobertura de pruebas por confiar en un sistema de tipos fuerte
  • Como las aplicaciones Haskell eliminan en compilación tipos de errores simples, la ingeniería del caos puede exponer con más claridad fallos reales de lógica y recursos

Herramientas y ecosistema que cambiaron

  • Los sistemas iniciales comenzaron con GHC 8.2, y en ese momento había que escribir directamente la mayoría de los clientes API y SDKs para plataformas populares
  • Haskell Language Server no existía, GHCup apenas aparecía y hacer profiling del runtime era difícil
  • A desarrolladores acostumbrados a los IDE de Java les incomodaba el entorno de herramientas de Haskell, y H-E-B incluso patrocinó el desarrollo de soporte Debug Adapter Protocol para usuarios de VS Code
  • Hoy el desarrollo de Haskell para producción ya no solo es viable, sino competitivo
  • Entre las herramientas de desarrollo están HLS, ghcid, ghciwatch, static-ls, tricorder y plugins de editor
    • Algunos usan plugins de GHC para un desarrollo centrado en GHCi más rico, y otros usan VS Code y HLS
    • Eso permite que cada desarrollador elija las herramientas que prefiere
  • Para observabilidad usan hs-opentelemetry y opentelemetry-auto
    • opentelemetry-auto es un plugin de GHC que inserta spans de OTel automáticamente en funciones Haskell
    • Puede ofrecer un entorno de instrumentación comparable al de Java o Python

Librerías de producción y mejoras del runtime

  • Los servicios usan librerías como warp, aeson, attoparsec, stm, conduit, servant y orville-postgresql
  • Cuando el ecosistema no ofrece la funcionalidad necesaria, desarrollan librerías propias
    • arbiter es una cola de trabajo PostgreSQL transaccional nacida del trabajo en H-E-B y actualmente opera en producción
  • GHC sigue mejorando el diagnóstico del runtime, el rendimiento del compilador, funciones de monitoreo como eventlog streaming y las anotaciones de excepciones
  • Desde que GHC 9.2 introdujo info table profiling, la preocupación por las fugas de espacio se ha reducido mucho

Comunidad interna y distribución del conocimiento

  • H-E-B da mucha importancia a las librerías internas y anima a los desarrolladores a participar tanto en proyectos internos como open source
  • Durante años mantuvieron una reunión de Haskell cada dos semanas para que los ingenieros compartieran hallazgos y formaran a otros miembros
  • Para reducir los silos en una organización empresarial, las ideas y patrones deben circular entre equipos
  • Hacer que más ingenieros lean y se apropien de la base de código puede reducir el riesgo de bus factor que implica que la salida de una sola persona ponga en peligro un proyecto

Criterios para permitir funciones avanzadas

  • Hay reglas base flexibles, pero la decisión final sobre dónde gastar el presupuesto de complejidad la toma el líder técnico
  • Si hace falta cifrar información personal identificable (PII) almacenada, una garantía a nivel de tipos que convierta una filtración de datos sensibles en error de compilación puede valer la inversión
  • Unificar cuatro contratos de API con el patrón trees-that-grow puede no justificar ocultar esquemas externos con type families
  • Haskell aburrido no prohíbe la programación a nivel de tipos ni las funciones avanzadas de GHC; establece convenciones con principios y luego evalúa el costo de desviarse de ellas
  • La convención principal es “sin efectos inesperados a distancia
    • Se evita la generación de código con TemplateHaskell y la lógica de serialización basada en Generic
    • Se escribe el boilerplate a mano para mostrar explícitamente al programador cómo funciona el comportamiento
    • No se prohíben por completo los quasiquoters ni el deriving mediante Generically
  • Cuando se implementa una máquina de estados a nivel de tipos para un formulario web, o se usa un GADT donde bastaría un ADT común, hace falta escepticismo sano y discusión a nivel de equipo
  • El Haskell avanzado existe tanto en librerías como en aplicaciones de producción, pero el alcance de la experimentación debe limitarse
  • La ingeniería real ocurre al equilibrar el trabajo con el juego técnico

El futuro de Haskell y los agentes de código

  • Tras varios años usando GHC, descubrieron y reportaron unos pocos bugs, pero ninguno tan grave como para detener el trabajo
  • Los incidentes de producción han sido raros, y con mucha más frecuencia surgieron de la lógica de negocio que de errores de tipos o del runtime
  • A medida que crece la proporción de código escrito por agentes, el cuello de botella se desplaza de escribir código a validarlo
  • El sistema de tipos de GHC no solo ayuda a las personas a hacer refactoring seguro, sino que también ofrece un bucle de retroalimentación rápida que rechaza antes de ejecutar el código alucinado por agentes
  • Para ampliar las posibilidades de Haskell en la industria, hace falta compartir más casos reales de éxito en producción

1 comentarios

 
GN⁺ 8 시간 전
Opiniones en Lobste.rs
  • Fuera de Texas quizá no se conozca mucho, pero H-E-B es una institución emblemática de Texas, con un tamaño e influencia tan grandes que bien podría considerarse otro departamento del gobierno estatal.
    Muchas tiendas tienen instalaciones para fabricar tortillas, y para ser producción a gran escala, la calidad también es excelente. Además, dicen que también usan Haskell.

    • El nombre proviene de las iniciales H.B. de Howard Butt, de la familia fundadora. Podrían haberlo nombrado por el fundador, como Wegmans, Hannaford Market o Walmart, pero por suerte no lo llamaron Buttmart.
    • Me pregunto si es algo así como un Costco regional.
  • Es realmente sorprendente que una empresa como H-E-B haya elegido Haskell para reemplazar COBOL.
    Las dos frases que dicen que un agente de programación puede trasladar mecánicamente una biblioteca de Go a Haskell, reduciendo la diferencia en velocidad de desarrollo, y que enseguida admiten que sin prompts inteligentes quizá no se aproveche lo suficiente el sistema de tipos, revelan problemas contradictorios.
    En cambio, el hecho de que los errores triviales se eliminen en la etapa de compilación y que, al inyectar fallas de infraestructura con ingeniería del caos, aparezcan errores reales de lógica y recursos en lugar del ruido de los lenguajes de tipado dinámico, parece la razón más convincente para considerar Haskell.

    • H-E-B, al igual que Walmart, tiene una organización de ingeniería grande y con bastante buena reputación, así que no es tan sorprendente. Incluso opera una oficina dedicada a software en Austin para atraer talento de software que no quiera trabajar en la sede de San Antonio.
  • La semana pasada intenté configurar builds de Haskell aislados en Bazel, pero no encontré una solución lista para usar.
    rules_haskell no está aislado de forma predeterminada, y el enfoque común parece depender mucho de nixpkgs. Parece que Haskell depende del linker C++ del sistema; me pregunto si esa es la situación real actual o si hay alguna alternativa que se me haya escapado.