H-E-B의 엔터프라이즈 Haskell 도입과 운영
요약
소매업체 H-E-B가 435개 매장 공급망 시스템을 현대화하며 Haskell을 도입했습니다. 이 과정에서 Haskell은 런타임 오류를 줄이고 레거시 연동을 지원하는 강력한 선택지로 입증되었습니다. 성공의 핵심은 언어 자체보다 팀 역량과 문화에 달려있으며, 점진적 마이그레이션 전략이 중요합니다.
핵심 포인트
- Haskell은 런타임 오류 감소와 안전한 리팩터링을 제공한다.
- 성공적인 도입은 기술보다 팀의 역량과 조직 문화에 크게 좌우된다.
- 레거시 시스템은 교살자 무화과(strangler fig) 방식으로 점진적 마이그레이션이 필수다.
- SDK 부족은 자체 유지보수 부담으로 이어지지만, 공급업체 종속성 회피라는 가치가 있다.
435개가 넘는 매장과 물류센터의 공급망을 현대화하는 과정에서 Haskell을 도입했으며, 8년 뒤 여러 팀이 관리하는 약 100만 줄의 코드 가 핵심 프로덕션 시스템에서 운영되고 있음
Haskell은 런타임 오류 유형을 줄이고 GHC 기반 리팩터링과 레거시 연동을 지원하지만, SDK 부족에 따른 자체 유지보수와 고급 타입 기능의 복잡성 을 감수해야 함
성공 여부는 언어보다 팀 역량과 문화에 크게 좌우됐으며, Haskell 전문가가 없던 팀의 공간 누수와 핵심 개발자 이탈로 두 프로젝트에서는 도입이 정착하지 못함
GHC 런타임은 H-E-B의 프로덕션 장애 원인이 된 적이 없으며, HLS·OpenTelemetry·프로파일링 등 생태계가 발전하면서 프로덕션 Haskell은 경쟁력 있는 선택지 로 바뀜
고급 기능을 작은 라이브러리와 명확한 인터페이스 뒤에 제한하고 테스트·관측성·지식 공유를 병행해야 하며, 코딩 에이전트 시대에는 GHC의 타입 검증과 빠른 피드백 이 더욱 중요해짐
메인프레임 현대화 과제
텍사스 최대 비상장 기업인 소매업체 H-E-B의 고객은 내부 시스템보다 매장 선반에 상품이 채워져 있는지를 중시함
수십 년간 COBOL 메인프레임 이 안정적으로 운영됐지만, 최근 10년 사이 커브사이드 픽업·가정 배송·실시간 재고·매장 내 검색 같은 기술 중심 기능이 등장함
435개가 넘는 매장과 이를 지원하는 물류센터로 공급망 운영을 확장하면서 기존 핵심 시스템이 처음 설계된 범위를 넘어서는 요구를 받게 됨
메인프레임 현대화의 핵심 난점은 코드를 클라우드로 옮기는 일이 아니라, 수십 년간 레거시 비즈니스 로직에 축적된 조직 고유 지식 을 보존하는 데 있음
수백 개 테이블을 다루는 모놀리스를 자율적인 엔지니어링 팀 소유의 마이크로서비스로 분할하는 작업은 기술적·정치적으로 거대하고 비용도 많이 듦
Haskell 도입과 운영 규모
컨설턴트들은 회사에서 가장 큰 메인프레임 애플리케이션을 대체하는 신규 프로젝트의 공통 언어로 Haskell 을 제안함
실험으로 시작한 작업은 여러 핵심 공급망 프로덕션 시스템으로 성장함
도입 8년 뒤에는 서로 다른 도메인의 여러 팀이 약 100만 줄 에 이르는 Haskell 코드를 유지보수하고 있음
장기간의 프로덕션 운영을 통해 실제 성과뿐 아니라 기술적·조직적 어려움도 드러남
비즈니스에서 얻은 장점
기업이 원하는 것은 지연 평가·순수 함수·불변 데이터 자체가 아니라, 40년간 null pointer exception 없이 낮은 유지보수 비용으로 작동할 차세대 COBOL 같은 시스템임
Haskell 애플리케이션은 명령형·동적 타입 프로그램에서 흔한 런타임 오류 유형을 기본적으로 제거함
버그가 완전히 사라지지는 않지만, 남는 문제는 null pointer exception이나 타입 혼동보다 비즈니스 로직 오류 에 집중됨
수년에 걸친 교살자 무화과(strangler fig) 방식의 레거시 이전에서 GHC는 안전한 리팩터링을 지원함
요구사항이 형성되는 동안 반복적으로 수정할 수 있어 폭포수 방식 대신 애자일하게 이전할 수 있음
기업은 잘못 굳어진 결과물에 선불 투자하는 대신 점진적으로 성과를 측정할 수 있음
Haskell 파서는 고정 폭 IBM copybook처럼 수천 줄에 이르는 레거시 형식을 직접 계약으로 사용할 수 있게 함
강력한 외부 함수 인터페이스(FFI) 를 통해 C 라이브러리만 제공하는 기존 서비스와도 연동할 수 있음
H-E-B는 simdjson
C++, Oracle ODPI-C
, IBM MQ를 감싸는 Haskell 라이브러리를 작성함
SDK 부족과 계약 소유권
Haskell SDK가 부족하면 필요한 클라이언트와 통합 코드를 직접 만들고 계속 유지보수해야 함
그 대가로 계약을 직접 소유하고 공급업체 종속을 피하며, 상위 프로젝트 관리자가 수정본을 배포하기를 기다리지 않아도 됨
H-E-B는 핵심 의존성 에 대해서는 이 교환이 충분한 가치가 있다고 판단함
코딩 에이전트는 Go 라이브러리를 Haskell로 옮기는 기계적인 작업을 잘 처리해 언어 간 개발 속도 차이를 줄일 수 있음
다만 단순 번역은 정교한 프롬프트가 없으면 Haskell 타입 시스템의 이점을 충분히 활용하지 못할 수 있음
내장 DSL을 통한 다언어 통합
Haskell은 내장 DSL(eDSL) 의 호스트 언어로 강점을 가짐
중앙 팀이 도메인 모델이나 비즈니스 로직을 한 번 정의한 뒤 다른 팀이 사용하는 언어의 안전한 타입 코드로 생성할 수 있음
다른 팀은 Haskell을 직접 작성하지 않고도 해당 시스템과 통합 가능함
Hydra 는 Uber의 그래프 데이터 작업에서 발전한 오픈소스 DSL 프레임워크임
Haskell에서 부트스트랩되며 Java·Python·Scala 등의 의미상 동등한 구현을 생성함
공유 테스트 스위트로 언어별 구현의 동등성을 보장함
H-E-B는 민감한 재무 계산을 Haskell·TypeScript·Java 팀이 공유할 수 있는 Haskell DSL을 프로토타이핑함
양방향 JSON 스키마 DSL도 구축함
autodocodec 와 유사하지만, 사용자가 자체 타입 클래스로 핵심 의미 체계를 확장할 수 있는 tagless final 인코딩 을 사용함
스키마 버전 관리와 문서·OpenAPI 생성, 회귀·골든 테스트를 표준화함
임시 인터프리터를 작성해 JSON 스키마를 PostgreSQL 테이블 정의로 변환하거나 aeson
을 simdjson
으로 교체하고 추가 검증을 적용할 수 있음
채용과 엔지니어링 문화
현대 언어도 Haskell에서 영향을 받은 타입 안전성·순수성·동시성 기능을 다수 제공하므로, 실제 차이는 언어가 촉진하는 엔지니어링 문화 에 있음
Haskell은 정확성과 추상화 설계를 중시하는 개발자를 끌어들임
Haskell 역할의 채용은 경영진이 예상한 것만큼 어렵지 않았음
공급망에 특별한 관심이 없더라도 Haskell 자체 때문에 지원하는 후보가 있었음
복잡성 예산의 한계
Haskell은 오래된 언어로 여러 결함이 있어 최신 GHC 릴리스를 따라가는 것이 중요함
팀에 전문가가 없으면 하나의 언어적 결함이 프로젝트 전체에 퍼질 수 있음
초기에는 숙련된 컨설턴트들이 언어 확장과 사용자 정의 연산자의 과도한 사용을 막는 가드레일을 마련함
GHC2021·GHC2024 언어 에디션이 없던 시기에는 각 팀이 기본 확장 집합을 직접 관리함
신규 입사자가 기여하기 전에 익혀야 할 언어 범위를 제한하는 복잡성 예산 역할을 했음
의존성 자체도 복잡성 예산을 소모하므로 조직 차원의 강제는 어려움
servant
는 API를 타입 수준 DSL로 표현하며, 사용자 정의 결합자(combinator) 확장에 type family와 난해한 오류가 수반됨
haxl
은 동시 작업을 일괄 처리하기 위해 모든 데이터 소스를 결과 타입으로 인덱싱된 GADT로 모델링함
개발자가 숙련될수록 GADT·type family·generic·tagless final·arrow·free structure·higher-kinded data type 패턴을 도입하려는 유혹이 커짐
이미 복잡한 비즈니스 도메인 위에 이런 개념이 쌓이면 쉬운 유지보수라는 약속이 약해짐
생태계에 익숙해지면서 고급 기능이 점진적으로 늘어나기 때문에 복잡성 증가는 뒤늦게 드러날 수 있음
지루한 Haskell의 운영 원칙
조직 차원에서 지루한 Haskell 을 권장하기는 쉽지만 강제하기는 어려움
고급 Haskell을 합리적인 인터페이스 뒤에 캡슐화하면 영향 범위를 줄이고, 복잡성 예산을 소수 전문가가 관리하는 작은 라이브러리에 한정할 수 있음
언어 수준의 복잡성은 Haskell만의 문제는 아니지만, Haskell은 사용할 수 있는 고급 도구의 범위가 특히 넓음
코드 줄 수나 토큰 사용량보다 다음 GHC 업그레이드에서 얼마나 많은 코드가 깨지는지가 Haskell 프로젝트의 복잡성을 더 잘 보여줌
정착하지 못한 두 프로젝트
Haskell은 한 팀의 역량을 강화하면서 다른 팀에는 장벽이 될 수 있으며, H-E-B에서도 서로 다른 이유로 두 프로젝트에 정착하지 못함
첫 사례에서는 Haskell 경험이 없는 숙련 개발자들이 다른 팀의 프로젝트 템플릿과 관례를 따랐지만, 공간 누수(space leak) 로 프로그램 전체가 멈춤
강한 Haskell 개발자가 팀을 안내하지 못해 이 문제 하나가 프로젝트 중단으로 이어짐
두 번째 사례에서는 Haskell을 지지하고 애플리케이션을 만든 엔지니어들이 우선순위 변경으로 다른 프로젝트로 이동함
두 팀 모두 기존 기술로 돌아갈 대안이 있었으며 Haskell이 생산성을 높인다고 확신하지 못함
Spring Boot 템플릿 같은 탈출구가 있으면 어려운 공간 누수를 끝까지 진단할 동기가 약해질 수 있음
LLM이 코드베이스 전체를 기계적으로 번역할 수 있게 되면서 재작성 선택지는 더욱 넓어짐
장기적인 방어선은 영리해서 재작성하기 어려운 코드가 아니라, Haskell을 계속 유지하고 싶어 하는 팀 임
프로덕션 장애와 진단
Haskell을 받아들인 팀에서도 여러 심각한 문제가 발생함
GHC 런타임 은 H-E-B의 프로덕션 장애 근본 원인이 된 적이 없음
정상 상태의 처리량과 메모리 사용량은 H-E-B 워크로드에서 충분히 경쟁력이 있었으며, 문제 사례들은 일반적인 상황이 아니라 예외였음
엔지니어들은 세그멘테이션 오류 코어 덤프, 가비지 컬렉션 지표, 힙 프로파일을 추적해 문제를 해결함
강한 타입 시스템을 이유로 테스트 커버리지를 희생해서는 안 됨
Haskell 애플리케이션은 단순한 오류 유형이 컴파일 단계에서 제거되므로 카오스 엔지니어링 을 통해 실제 로직·자원 장애를 더 직접적으로 드러낼 수 있음
달라진 개발 도구와 생태계
초기 시스템은 GHC 8.2 에서 시작했으며, 당시에는 인기 플랫폼용 API 클라이언트와 SDK 대부분을 직접 작성해야 했음
Haskell Language Server는 존재하지 않았고 GHCup은 막 등장했으며 런타임 프로파일링도 어려웠음
Java IDE에 익숙한 개발자들은 Haskell 도구 환경을 불편해했고, H-E-B는 VS Code 사용자를 위한 Debug Adapter Protocol 지원 개발을 후원하기도 함
현재는 프로덕션급 Haskell 개발이 가능한 수준을 넘어 경쟁력 있는 수준으로 발전함
개발 도구에는 HLS, ghcid
, ghciwatch
, static-ls
, tricorder , 편집기 플러그인이 있음
일부는 풍부한 GHCi 중심 개발을 위해 GHC 플러그인을 사용하고, 일부는 VS Code와 HLS를 사용함
개발자가 선호하는 도구를 선택할 수 있도록 함
관측성에는 hs-opentelemetry
와 opentelemetry-auto 를 사용함
opentelemetry-auto
는 Haskell 함수에 OTel span을 자동 삽입하는 GHC 플러그인임
Java·Python과 비교해도 유사한 계측 환경을 제공할 수 있음
프로덕션 라이브러리와 런타임 개선
서비스는 warp
, aeson
, attoparsec
, stm
, conduit
, servant
, orville-postgresql 같은 라이브러리를 사용함
생태계에 필요한 기능이 없으면 자체 라이브러리를 개발함
arbiter 는 H-E-B 작업에서 나온 트랜잭션 기반 PostgreSQL 작업 큐이며 현재 프로덕션에서 운영됨
GHC는 런타임 진단, 컴파일러 성능, eventlog streaming 같은 모니터링 기능과 예외 주석 을 개선하고 있음
GHC 9.2에 info table profiling 이 도입된 뒤 공간 누수에 대한 우려가 크게 줄어듦
내부 커뮤니티와 지식 분산
H-E-B는 내부 라이브러리를 중요하게 다루며, 개발자가 사내 프로젝트와 오픈소스 프로젝트 모두에 참여하도록 권장함
수년간 격주 Haskell 모임을 운영해 엔지니어가 탐구 결과를 공유하고 다른 구성원을 교육함
엔터프라이즈 조직의 사일로를 줄이려면 팀 사이에서 아이디어와 패턴이 교류돼야 함
더 많은 엔지니어가 코드베이스를 읽고 소유하게 만들면 한 사람의 퇴사가 프로젝트를 흔드는 버스 팩터 위험 을 낮출 수 있음
고급 기능을 허용하는 기준
느슨한 기본 규칙을 두되, 복잡성 예산을 어디에 쓸지는 기술 리드가 최종 결정함
저장된 개인식별정보(PII)를 암호화해야 한다면 민감한 데이터 유출을 런타임 사고가 아니라 컴파일 오류로 만드는 타입 수준 보장이 투자 가치가 있을 수 있음
네 개의 API 계약을 trees-that-grow 패턴으로 통합하는 작업은 type family로 외부 스키마를 가릴 만큼 가치가 없을 수 있음
지루한 Haskell은 타입 수준 프로그래밍이나 고급 GHC 기능을 금지하지 않고, 원칙 있는 관례를 정한 뒤 이탈 비용을 평가함
주요 관례는 “멀리 떨어진 곳의 예기치 않은 작용 없음 ”임
TemplateHaskell
코드 생성과 Generic
기반 직렬화 로직을 피함
상용구를 직접 작성해 프로그래머에게 동작을 명시적으로 보여줌
quasiquoter나 Generically
를 통한 deriving을 완전히 금지하지는 않음
웹 폼에 타입 수준 상태 머신을 구현하거나 일반 ADT로 충분한 곳에 GADT를 사용할 때는 건전한 의심과 팀 차원의 반론이 필요함
고급 Haskell은 라이브러리와 프로덕션 애플리케이션 모두에 존재하지만, 실험의 범위를 제한해야 함
일과 기술적 놀이 사이를 조절하는 과정에서 실제 엔지니어링이 이뤄짐
앞으로의 Haskell과 코딩 에이전트
여러 해 동안 GHC를 사용하며 소수의 버그를 발견해 보고했지만, 업무를 중단시킬 정도의 문제는 없었음
프로덕션 사고는 드물며 타입 오류나 런타임보다 비즈니스 로직 에서 발생하는 경우가 훨씬 많았음
코딩 에이전트가 작성하는 코드 비중이 커지면서 병목은 코드 작성에서 검증으로 이동하고 있음
GHC의 타입 시스템은 사람이 안전하게 리팩터링하도록 돕는 동시에, 에이전트가 환각으로 만든 코드를 실행 전에 거부하는 빠른 피드백 루프 를 제공함
산업 현장에서 Haskell의 가능성을 확장하려면 실제 프로덕션 성공 사례가 더 많이 공유돼야 함
댓글과 토론
AI 자동 생성 콘텐츠
본 콘텐츠는 GeekNews의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기