함수형 프로그래밍, 시스템 설계에선 무엇을 조심해야 할까?
함수형 프로그래밍(Functional Programming)의 강력한 도구들이 시스템 수준의 문제 해결에는 한계가 있음을 지적함
배포 환경(Deployment Environment)에서의 여러 버전의 코드, 데이터 마이그레이션(Data Migration) 문제를 핵심으로 다룸
데이터의 의미론적 변화(Semantic Drift)는 기존의 타입 검사(Type Check) 도구로는 감지하기 어려움을 강조함
배포 시 호환성 검사(Compatibility Check)를 위한 다양한 도구와 접근 방식을 소개함
궁극적으로, 단일 프로그램이 아닌 배포 집합(Set of Deployments)을 고려한 시스템 설계를 강조함
단일 프로그램 vs. 배포 집합
글쓴이는 함수형 프로그래밍(Functional Programming)의 강력한 도구들이 단일 프로그램의 정확성(Correctness)을 보장하는 데는 효과적이지만, 실제 운영 환경인 배포 집합(Set of Deployments)의 복잡성을 간과할 수 있다고 지적한다. 특히, 여러 버전의 코드가 동시에 실행되는 상황, 데이터베이스 스키마(Database Schema) 변경, 메시지 큐(Message Queue)를 통한 데이터 교환 등은 단일 프로그램 분석으로는 해결하기 어려운 문제들을 야기한다. 이러한 문제들은 시스템 전체의 관점에서 접근해야 한다고 강조한다.
데이터 마이그레이션(Data Migration)의 어려움
데이터베이스 스키마(Database Schema) 변경은 롤백(Rollback)이 어렵고, 롤백 시 테스트되지 않은 상태가 발생할 수 있다는 점을 지적한다. 글쓴이는 확장-축소 패턴(Expand-and-Contract Pattern)을 통해 안전한 마이그레이션을 수행할 것을 권장한다. 이는 새로운 컬럼을 추가하고, 데이터를 백필(Backfill)한 후, 기존 컬럼을 삭제하는 일련의 과정을 거치는 방식이다. 이러한 접근 방식은 데이터의 일관성을 유지하고, 롤백 시 발생할 수 있는 위험을 최소화한다.
의미론적 변화(Semantic Drift)의 위험성
타입은 동일하지만 의미가 변경되는 의미론적 변화(Semantic Drift)는 기존의 타입 검사(Type Check) 도구로는 감지하기 어렵다는 점을 강조한다. 예를 들어, `amount` 필드가 센트(Cents)에서 달러(Dollars)로 변경되는 경우, 타입은 동일하게 `Int`로 유지되지만, 실제 데이터의 의미는 100배나 달라진다. 이러한 문제는 회계 시스템(Accounting System)과 같이 정확성이 중요한 시스템에서 치명적인 오류를 발생시킬 수 있다. 따라서, 데이터 계약(Data Contract)의 의미를 명확히 문서화하고, 단위(Unit)를 명시하는 새로운 타입을 사용하는 것이 중요하다.
버전 경계에서의 '파싱, 검증하지 말고 파싱하라'
글쓴이는 단일 프로그램 내에서의 '파싱, 검증하지 말고 파싱하라(Parse, Don't Validate)'는 원칙을 버전 경계(Version Boundary)에도 적용해야 한다고 주장한다. 즉, 배포 N에서 생성된 데이터가 배포 N+1에서 사용될 때, 데이터를 검증하기 전에 파싱(Parsing)하여 호환성을 보장해야 한다. 이를 위해 스키마 레지스트리(Schema Registry), GraphQL, Protobuf, Avro와 같은 도구들을 활용하여 배포 시 호환성 검사를 수행하는 것이 중요하다. 이러한 접근 방식은 런타임(Runtime)에서 발생하는 오류를 줄이고, 개발 프로세스 초기에 문제를 발견할 수 있도록 돕는다.
배포 시 호환성 검사(Compatibility Check) 자동화
글쓴이는 배포 시 호환성 검사를 자동화하기 위해, 버전 태그(Version Tag), 호환성 함수(Compatibility Function), 런타임 버전 인벤토리(Runtime Version Inventory)의 세 가지 요소가 필요하다고 강조한다. 스키마 레지스트리(Schema Registry)는 시리얼라이제이션(Serialization) 형식에 대한 버전 정보를 제공하고, GraphQL Inspector와 같은 도구는 API 스키마(API Schema)의 호환성을 검사한다. 또한, 서비스 메시(Service Mesh)는 런타임 환경에서 실행 중인 서비스의 버전을 파악하는 데 도움을 준다. 이러한 도구들을 통합하여 배포 파이프라인(Deploy Pipeline)에서 호환성 검사를 수행함으로써, 안전한 배포를 보장할 수 있다.