아키텍처 패턴은 왜 계속 진화하는가
개발 공부를 하다 보면 새로운 단어가 끝없이 쏟아지죠. Monolith, Microservices, Hexagonal, DDD, CQRS, Event Sourcing, Serverless, Service Mesh… 누군가는 "요즘은 다 마이크로서비스"라고 하고, 또 누군가는 "Amazon이 모놀리스로 돌아갔다더라"라고 해요. 결론부터 말하면 패턴에는 정답이 없어요. 모든 패턴은 그 시대의 특정한 문제에 대한 답이고, 새 패턴은 이전 패턴의 한계 위에서 태어나거든요. 그래서 봐야 할 건 "최신"이 아니라 "왜"예요. 패턴이 진화하는 네 가지 압력 새 패턴은 "더 멋있어서" 나오지 않아요. 항상 네 가지 압력이 동시에 작용해요. 하드웨어와 인프라의 변화 서버가 비쌌던 시절에는 하나의 머신에 모든 걸 욱여넣을 수밖에 없었어요. 클라우드가 등장하면서 서버는 일회용품이 됐고, 컨테이너와 쿠버네티스가 보편화되면서 배포 비용은 거의 0에 수렴했죠. 할 수 있게 된 것은 곧 해야 하는 것으로 바뀌어요. 인프라가 가능하게 만든 일은 결국 누군가 시도하고, 그게 패턴이 돼요. 조직 규모의 변화 (Conway's Law) 1968년 Melvin Conway는 이렇게 썼어요. "시스템 구조는 그것을 만든 조직의 의사소통 구조를 닮는다." 5명짜리 팀이 만드는 시스템과 500명짜리 회사가 만드는 시스템은 절대 같을 수 없어요. 5명은 한 코드베이스에서 충돌 없이 일할 수 있지만, 500명은 불가능하거든요. Microservices는 기술적 결정이기 전에 조직적 결정이에요. 이전 패턴의 약점이 드러난다 새 패턴은 항상 이전 패턴이 일정 규모를 넘었을 때 터지는 지점에서 태어나요. Monolith → (배포가 무서워진다) → Microservices → (서비스 간 통신 지옥) → Service Mesh, Event-Driven → (분산 트랜잭션 문제) → Saga, Eventual Consistency 모든 처방은 새로운 부작용을 낳고, 그 부작용이 다음 패턴의 출발점이 돼요. 비즈니스 요구사항의 변화 예전에는 "내일까지 처리되면 됐던" 일이, 이제는 "1초 안에 알림이 와야 하는" 일이 됐어요. 한국에서만 팔던 서비스가 글로벌이 되기도 하죠. 비즈니스의 속도와 범위가 바뀌면 시스템도 따라가요. 시대별로 따라가 보는 아키텍처의 역사 각 시대가 어떤 문제에 직면했고 어떻게 풀었는지를 보면 흐름이 잡혀요. 1970~80년대: 절차적 시대 메모리는 KB 단위, CPU는 MHz, 프로그램은 한 사람이 다 짜던 시절이에요. 문제는 "어떻게 하면 자원을 아끼면서 동작하는 프로그램을 만들까"였고, 답은 절차적 프로그래밍과 구조적 프로그래밍이었어요. 이 시대의 코드는 본질적으로 함수의 나열이었어요. C언어가 대표적이죠. "GOTO를 쓰지 말고 함수로 나누자"는 게 당대의 큰 진보였어요(Dijkstra의 그 유명한 "GOTO Considered Harmful", 1968). 1990년대: 객체지향과 MVC의 시대 PC가 보급되고 GUI가 등장하면서 프로그램이 점점 커져요. 코드가 1만 줄을 넘어가면 함수만으로는 관리가 안 되고, UI까지 붙으니 더 복잡해지죠. 답은 객체지향 프로그래밍(OOP)과 MVC(Model-View-Controller)였어요. OOP는 데이터와 그것을 다루는 동작을 묶어서 "객체"로 보자는 발상이에요. Smalltalk가 시작이었지만 Java(1995)가 대중화시켰죠. MVC는 Trygve Reenskaug가 1979년에 제안했지만, 본격적으로 쓰인 건 GUI와 웹이 보편화된 90~2000년대예요. 2000년대 초반: 엔터프라이즈와 Layered Architecture 닷컴 버블 이후 은행, 보험사, 대기업이 본격적으로 웹 기반 시스템을 구축해요. 비즈니스 로직은 거대해지고, 수십 명의 개발자가 같은 시스템에 손을 대죠. 답은 Layered Architecture(N-tier)였어요. Controller → Service → Repository → DB. 이 구조는 지금도 압도적으로 많이 쓰이고, Java EE와 Spring이 표준이 됐어요. 이 시대의 또 하나의 큰 사건은 DDD(Domain-Driven Design)의 등장이에요. Eric Evans가 2003년에 책을 출간하며 정립했는데, 핵심은 "비즈니스 도메인을 코드 구조의 중심에 두자"는 거예요. Aggregate, Bounded Context 같은 개념이 여기서 나왔어요. DDD는 Layered/Clean Architecture와 결합해서 써요. Layered가 "그릇의 모양"이라면, DDD는 "그릇 안에 담길 객체를 어떻게 빚을 것인가"에 대한 답이거든요. 2000년대 중후반: SOA의 실험 회사 안에 시스템이 너무 많아져요. 결제, 회원, 상품 시스템이 따로 도는데 서로 데이터를 주고받아야 하죠. 여기서 나온 답이 SOA(Service-Oriented Architecture)예요. SOA는 Microservices의 조상이에요. 다만 당시엔 ESB(Enterprise Service Bus)라는 무거운 미들웨어를 통해 통신했어요. 이게 너무 무겁고 복잡해서 SOA는 결국 "이론은 좋지만 실패한 실험"으로 평가받게 되죠. 그래도 그 정신은 살아남아 2010년대에 다른 형태로 부활해요. 2010년대 초반: 클라우드와 Microservices의 시대 AWS가 자리를 잡고(EC2는 2006년 출시지만 대중화는 2010년대), 컨테이너가 등장하고(Docker, 2013), 스마트폰이 폭발하며 트래픽이 수천 배로 늘어나요. Monolith로는 더 이상 안 되는 순간이 와요. 한 줄 고치면 전체를 배포해야 하고, 한 부분이 죽으면 전체가 죽거든요. 팀은 100명, 1000명으로 커지는데 한 코드베이스를 같이 만지려니 지옥이고요. Netflix가 이 흐름의 대표 주자예요. 2008년 데이터센터 장애로 며칠 동안 서비스가 멈춘 사건을 계기로, 모놀리스를 버리고 AWS 위에서 마이크로서비스로 전환했어요. 그 과정에서 만들어진 도구들(Eureka, Hystrix, Zuul)은 OSS로 공개되어 업계 표준이 됐죠. Amazon은 그보다 일찍, 2002년 Jeff Bezos의 유명한 "API Mandate"로 내부 시스템을 모두 API로 통신하게 만들었고, 이게 결과적으로 AWS의 탄생으로 이어졌어요. 이 시대의 부산물로 나온 패턴들도 같이 보면 좋아요. API Gateway — 클라이언트가 수십 개의 마이크로서비스를 다 알 수는 없으니 하나의 입구를 만들자 BFF (Backend For Frontend) — 모바일과 웹은 필요한 데이터가 다르니 클라이언트별로 게이트웨이를 따로 두자. Netflix와 SoundCloud가 선도했어요 Circuit Breaker — 한 서비스가 죽었을 때 다른 서비스가 끝없이 기다리지 않게 차단하자. Netflix의 Hystrix가 대표예요 2010년대 중반: 비동기와 Event-Driven 마이크로서비스가 늘어나면서 동기 통신의 한계가 드러나요. A → B → C → D를 순서대로 호출하면 D가 느릴 때 전체가 느려지거든요. 그래서 나온 답이 Event-Driven Architecture, 그리고 Kafka예요. LinkedIn에서 시작한 Kafka(2011)는 이 시대의 가장 중요한 인프라예요. "이벤트를 로그로 저장하고 누구든 구독할 수 있게 한다"는 단순한 발상이 분산 시스템의 통신 방식을 바꿨죠. 이 흐름에서 같이 떠오른 패턴들이에요. CQRS (Command Query Responsibility Segregation) — 읽기와 쓰기를 다른 모델로 분리. 읽기 트래픽이 압도적으로 많은 시스템(예: 트위터 타임라인)에서 유용해요 Event Sourcing — 상태를 저장하지 않고 이벤트의 흐름을 저장. 모든 변경이 추적되니 감사가 중요한 도메인(은행, 보험)에 적합해요 Saga Pattern — 분산 트랜잭션을 보상 트랜잭션으로 처리. 주문이 실패하면 결제 취소를 자동으로 트리거하는 식이에요 2010년대 후반: Container, Kubernetes, Service Mesh 마이크로서비스가 100개, 1000개씩 되면서 운영 복잡도가 폭발해요. 답은 Kubernetes(2014, Google이 OSS로 공개)와 Service Mesh(Istio 2017, Linkerd 등)였어요. Kubernetes는 "컨테이너 오케스트레이션"의 표준이 됐어요. 여러 머신에 흩어진 컨테이너를 자동으로 배치하고, 복구하고, 확장해요. Service Mesh는 한 단계 더 나아가서 서비스 간 통신 자체를 인프라 레벨에서 처리해요. 재시도, 인증, 트래픽 분산 같은 걸 애플리케이션 코드에서 빼서 사이드카 프록시(Envoy)로 옮기는 거죠. 2010년대 후반~2020년대: Serverless AWS Lambda(2014)가 등장하면서 "서버를 관리할 필요가 없다"는 발상이 나와요. 트래픽이 들쭉날쭉한 워크로드나, 한 달에 몇 번 도는 배치 작업에 24시간 서버를 띄워두는 건 낭비였거든요. Serverless/FaaS(Function as a Service)는 함수 단위로 배포하고, 호출될 때만 비용이 발생해요. 이미지가 업로드되면 썸네일을 만들고 결제가 들어오면 알림을 보내는 식의 이벤트 기반 워크로드에 특히 잘 맞아요. AWS Lambda, Vercel, Cloudflare Workers가 대표적이에요. 2020년대: 회귀와 재평가 여기서부터 흥미로워요. 유행이 돌고 있거든요. Modular Monolith의 부활 — "마이크로서비스 가기 전에 모놀리스를 잘 모듈화하자"는 흐름. Shopify가 대표적이에요 Amazon Prime Video의 회귀(2023) — 마이크로서비스로 만든 비디오 모니터링 시스템을 다시 모놀리스로 합쳐서 비용을 90% 줄였다는 글이 화제가 됐어요 DHH(Basecamp/Hey 창업자)의 "Majestic Monolith" — 작은 팀에는 모놀리스가 답이라는 주장이에요 핵심은 이거예요. 마이크로서비스가 틀린 게 아니라, 모든 곳에 마이크로서비스를 적용한 것이 틀렸던 거죠. 한 장으로 압축한 흐름 [1970s] 절차적 ↓ (프로그램이 커진다) [1990s] OOP, MVC ↓ (엔터프라이즈 시스템이 거대해진다) [2000s] Layered, DDD, SOA ↓ (클라우드와 모바일이 폭발한다) [2010s] Microservices, Event-Driven, Kubernetes ↓ (운영 복잡도가 폭발한다) [2020s] Modular Monolith, Serverless, "필요한 만큼만" 각 화살표를 보면 알 수 있어요. 새 패턴은 이전 패턴이 부족해서가 아니라 환경이 바뀌어서 등장해요. 그리고 환경이 다시 바뀌면, 옛 패턴이 새 옷을 입고 돌아와요. 회사마다 선택이 다른 이유 같은 시대에도 회사마다 다른 패턴을 써요. 각자의 문제가 다르기 때문이에요. 회사 주요 패턴 이유 Netflix Microservices, BFF, Circuit Breaker 글로벌 스트리밍, 장애 회복력이 생명 Amazon Microservices(API Mandate), Event-Driven 거대한 조직, 독립 배포 필수 Uber Event-Driven, DDD 실시간 매칭, 복잡한 도메인 LinkedIn Kafka 기반 Event Streaming 대규모 데이터 파이프라인 Shopify Modular Monolith 빠른 개발, 명확한 도메인 분리 Basecamp/Hey Majestic Monolith 작은 팀, 빠른 의사결정 Stack Overflow Monolith(여전히!) 단순한 도메인, 비용 효율 Discord Elixir 기반, 일부 Rust 마이크로서비스 동시성, 성능 핫스팟 특히 Stack Overflow가 인상 깊어요. 전 세계 톱 50 사이트인데 여전히 모놀리스거든요. 마이크로서비스를 몰라서가 아니라, 자기 문제에 모놀리스가 더 적합하다고 판단했기 때문이에요. 패턴을 대하는 자세 "최신"보다 "왜"를 보기 새 패턴이 나왔다고 무조건 따라가면 안 돼요. 그 패턴이 어떤 문제를 풀려고 만들어졌는지를 먼저 물어야 해요. 내 시스템에 그 문제가 없다면, 그 패턴은 오버엔지니어링이에요. 패턴은 트레이드오프의 모음 모든 패턴은 무언가를 얻고 무언가를 잃어요. Microservices — 독립 배포 ↔ 분산 시스템 복잡도 Event-Driven — 느슨한 결합 ↔ 디버깅 어려움, 일관성 문제 CQRS — 읽기 성능 ↔ 코드 복잡도, 일관성 지연 Serverless — 운영 부담 감소 ↔ 콜드 스타트, 벤더 종속 공짜 점심은 없어요. 무엇을 얻기 위해 무엇을 포기할 것인가가 항상 핵심이에요. 조직과 비즈니스를 보기 기술적 패턴 선택은 항상 조직과 비즈니스의 함수예요. 아래 질문에 답하지 않고 패턴을 고르면 반드시 후회해요. 팀이 5명인가, 500명인가? 트래픽이 안정적인가, 들쭉날쭉한가? 도메인이 단순한 CRUD인가, 복잡한 비즈니스 규칙인가? 비용 민감도가 높은가, 성능이 우선인가? 점진적으로 가기 모든 글로벌 기업은 모놀리스로 시작했어요. Amazon도, Netflix도, Uber도요. 그들은 문제가 생긴 후에야 마이크로서비스로 갔어요. 처음부터 마이크로서비스로 시작한 스타트업의 80%는 인프라 복잡도에 발목이 잡혀요. Start with a monolith. Extract services when the pain is real. 그래서 지금 뭘 공부하면 좋을까 백엔드 개발자가 학습 순서를 정한다면 이런 흐름을 추천해요. Layered Architecture를 진짜로 짜보기 — Spring Boot든 Django든 Express든 상관없어요 그 코드를 Hexagonal로 리팩토링해보기 — 의존성 역전이 몸으로 와닿을 때까지 간단한 DDD 개념을 적용해보기 — Aggregate, Value Object 정도면 충분해요 이벤트 기반 통신을 한 번 써보기 — Kafka든 RabbitMQ든 그다음에 Microservices, CQRS, Event Sourcing 보기 — 아마 그때쯤이면 왜 필요한지가 보일 거예요 나머지는 그 패턴이 필요한 순간이 올 때 공부하면 돼요. 미리 다 배우려고 하면 깊이 없는 지식만 쌓이거든요. 마치며 아키텍처 패턴의 역사는 결국 "우리는 점점 더 큰 시스템을, 점점 더 큰 조직으로, 점점 더 빠르게 만들어야 한다"는 압력의 역사예요. 패턴은 그 압력에 대한 답이고, 압력이 바뀌면 답도 바뀌죠. 그러니 "이게 정답이다"라고 말하는 사람은 경계하는 게 좋아요. 정답은 항상 "무엇에 대한 답인가?"라는 질문 뒤에만 존재하거든요. 다음에 새로운 패턴 이름을 들었을 때, 이렇게 물어보세요. "이 패턴은 어떤 문제를 풀려고 나왔는가? 내게 그 문제가 있는가?" 그 질문이 기술 트렌드의 파도 속에서 길을 잃지 않게 해줄 거예요. 더 읽어볼 자료 Domain-Driven Design — Eric Evans (2003) Building Microservices — Sam Newman Designing Data-Intensive Applications — Martin Kleppmann Martin Fowler 블로그 — 패턴의 정의와 트레이드오프 Software Architecture: The Hard Parts — Neal Ford et al. Amazon Prime Video의 모놀리스 회귀 글 (2023) DHH의 "The Majestic Monolith" 블로그 It isn't what happens to us that causes us to suffer; it's what we say to ourselves about what happens.— Pema Chodron