내가 코딩을 멈추고 설계를 시작한 이유
예전에는 소프트웨어 개발이 단순히 기능을 구현하는 것이라고 생각했습니다. 엔티티를 만들고, 컨트롤러를 구축하고, 데이터베이스를 연결하는 것이 제 업무라고 믿었습니다.
최근 진행한 프로젝트가 제 관점을 바꾸어 놓았습니다. 코딩은 솔루션의 일부일 뿐이라는 것을 깨달았습니다. 진짜 작업은 코드 한 줄을 쓰기 전부터 시작됩니다.
아키텍처를 결정해야 합니다. 왜 이 아키텍처가 적합한지, 비용은 얼마나 드는지, 그리고 어떤 리스크를 해결할 수 있는지 질문해야 합니다.
여기 제가 배운 주요 교훈들이 있습니다:
• 아키텍처는 제품의 단계와 일치해야 합니다. 마이크로서비스(microservices), Kubernetes, 복잡한 이벤트 큐(event queues)를 즉시 도입하고 싶은 유혹이 생깁니다. 저희 프로젝트에서는 단일 프로세스 내의 계층형 아키텍처(layered architecture)를 선택했습니다. 이를 통해 분산 시스템의 골칫거리 없이도 책임을 분리할 수 있었습니다. 시작 단계에서는 단순한 것이 종종 더 낫습니다.
• 지금은 비용이 적게 들지만 나중에 큰 비용이 드는 결정들이 있습니다. 저희는 첫날부터 데이터 모델에 TenantId를 추가했습니다. 비록 클라이언트는 하나뿐이었지만, 덕분에 나중에 SaaS 모델로 전환하는 것이 쉬워졌습니다. 멀티 테넌시(multi-tenancy) 도입을 너무 미루면 마이그레이션은 악몽이 됩니다.
• 설계는 미래의 막다른 길을 방지합니다. 프로그래밍은 당면한 문제를 해결합니다. 설계는 미래의 가능성을 차단하지 않으면서 문제를 해결합니다. 저희는 인프라 이동을 쉽게 하기 위해 초기에 컨테이너(containers)를 사용했습니다. 또한 공급업체(providers)를 쉽게 교체할 수 있도록 인터페이스(interfaces)를 활용했습니다.
• 비즈니스의 변화가 기술적 변화를 이끕니다. 비즈니스가 성장함에 따라 시스템은 마이크로서비스로 전환됩니다. 단일 클리닉용 앱이 수백 개의 클리닉을 위한 SaaS 플랫폼이 되는 식입니다. 이러한 변화는 결제, 구독, 확장성(scaling)을 처리하는 방식을 완전히 바꿉니다.
• 신뢰성을 위해서는 스마트한 패턴이 필요합니다. 저희는 동기식 호출(synchronous calls)에서 이벤트 기반 아키텍처(event-driven architecture)로 전환했습니다. 의료 시스템에서 알림 서비스가 느려진다고 해서 예약 시스템이 중단되어서는 안 됩니다. 저희는 메시지 브로커(message broker)가 실패하더라도 데이터가 안전하게 유지되도록 Outbox 패턴을 사용했습니다.
• 패턴은 도메인에 적합해야 합니다. 패턴을 맹목적으로 사용하지 마세요. 의료 진단에는 강력한 일관성(strong consistency)이 필요합니다. 환자의 안전을 위해 최종 일관성(eventual consistency)에 의존할 수는 없습니다. 감사 추적(audit trail)을 깨뜨린다면 민감한 임상 데이터에 캐시(cache)를 사용하지 마세요.
• DevOps는 나중에 생각할 문제가 아닙니다. 배포(deployment), 상태 확인(health checks), 파이프라인(pipelines)은 초기 설계의 일부입니다. 비용을 추산하고 실제로 필요한 요구사항을 충족하는 컴포넌트를 선택해야 합니다.
프로그래머와 디자이너의 차이는 바로 "왜(why)"에 있습니다.
프로그래머는 묻습니다: "이것을 어떻게 작동하게 만들 것인가?" 디자이너는 묻습니다: "왜 이것이 이 특정 문제에 대한 올바른 해결책인가?"