Database Driven Development에서 진짜 DDD로의 선회 -1-

DDD에 대한 오해에서 벗어나고 개발의 즐거움을 깨달은 이야기

들어가며 - 과거의 내 모습

이 글은 DDD(Domain Driven Design 또는 Development)에 대해 아무런 고민도 없던 제가 현장에서 DDD를 팀원들과 함께 실천하며 깨달은 것(주로 경험)에 대한 이야기 입니다.(내용이 길어지고 하고 싶은 이야기가 많아져서 디테일한 이야기들은 개별 포스트로 작성하게 될 것 같습니다.)

이해를 돕기 위해 과거에 제가 설계했던 시스템의 스키마의 윤곽을 설명드리자면, 이 시스템의 테이블들은 솔루션 비즈니스를 고려한 설계로, 테이블에는 공통 코드를 저장하는 것과 미래를 위한 여분 필드들이 있으며, 모든 테이블들은 긴밀하게 FK로 연결되어 있었습니다. 제가 생각하기에는 어디든 가서 스키마를 밀어넣고 초기 세팅만 테이블에 해주면 이런 저런 것들이 가능해지는 설계였습니다. 저는 무언가를 이뤄냈다는 성취감에 제 타임라인에 제가 설계한 시스템의 개략적인 이미지를 올려 두었고 이 스키마를 본 지나가던 업계 선배께서 제게 이런 느낌의 일침을 가해주셨습니다.

너, "Database" Driven Development(그 DDD가 아니야!) 하고 있구나..

당시만해도 SI에서 필요한 서비스를 디자인하던 저는 데이터 모델링으로 데이터만 넣으면 솔루션처럼 다 되는 이상적인 시스템을 구상했다고 기뻐했었으나, 업계의 선배께서는 제게 알려 주셨습니다.

제가 목적과 결과를 혼동하고 있다는 사실을요. 돌이켜 생각해보면 당시 제가 생각했던 디자인은 결국 시스템의 성장 가능성을 틀어막고 훗날 시스템을 꾸려나갈 개발자에게 선택의 여지를 빼앗는 닫힌 디자인이었습니다.

잠깐 그 시절 이야를 해보자면 결과지향적이던 SI에서는 다음과 같은 이야기를 자주 들었습니다.

DB에 꽂히면 다 끝난거야.

현재의 저는 이 생각에는 동의하지 않습니다.우리가 책을 사면 책장에 책을 꽂는 것이 목표 일까요? 아니면 책을 읽고 사고를 하는 것이 목표 일까요?

도서관 당시의 저는 데이터를 집어 넣는 결과에만 몰두한 나머지 그 과정에서 벌어지는 "인간적이고 현실적인 문제해결"을 간과했습니다.

방황을 끝마친 것은 "이직"이었습니다만. 그 이야기는 너무 길어서 이직하기 까지의 과정은 생략하겠습니다.

생략

그 시절 막연하게 생각했던 DDD에 대한 고백

DDD 를 제대로 이해하거나 시도하려는 생각은 쉬이 시작하지 못했었습니다. 당시 저는 SI의 관성에서 벗어나지 못한 상태였으며, 몇 가지 오해에 사로잡혀 있었습니다. 아래는 그 오해들 입니다.

DDD는 신앙에 가깝다.

부끄러운 이야기지만 당시 저는 DDD가 없어도 개발을 할 수 있는데, DDD는 너무 과한 이야기가 아닌가 생각했었습니다. 개발자들의 지나친 이상주의라고 생각했습니다. 그리고 주변의 실패 사례를 보고 들으며 '거봐, DDD는 현실적이지 않아..' 라는 생각도 했었습니다.

DDD는 설계의 영역이다.

DDD, Domain Driven Design 이라고 글자 그대로만 생각했습니다. 문자 그대로 디자인, 설계의 영역이라고만 생각했었습니다. '차라리 코드를 한 줄 더 짜는게 좋지 않을까? 기존 방법으론 이미 다 나오는데 왜 굳이?' 라는 생각이 있었습니다.

DDD는 어렵다.

그런 상황에서 DDD는 막연히 어렵다고 생각했습니다. 전략적 디자인 이라던가, 유비쿼터스 랭귀지, 바운디드 컨텍스트 등. 낯선 용어들이 높다란 장벽처럼 이해를 가로막고 있었습니다. 하나를 보면 다른 하나가 튀어나오고 숨바꼭질 마냥 튀어나오는 용어들 때문에 숲에서 길을 잃은 기분이었습니다. 대체 왜 이런 이야기들을 계속해서 내 머리를 아프게 하는가 싶을 정도로.

그런데 전부 오해였습니다.

  • DDD는 신앙이 아니라 그저 "문제해결에 대한 철저한 탐험과정"이었고,
  • 설계(Design) 뿐만 아니라 "개발(Development), 배포(Deployment), 운영(Direction)"을 고려해야 하는 더 넓은 것이었으며,
  • 낯설게만 들리던 용어들의 장벽을 넘어서면 "모든 수단과 방법을 동원해서 제대로 만들자" 라는 (무시무시 하지만) 명쾌한 결론에 다다를 수 있었습니다.

모든것은 문제해결을 위해서였다 DDD를 한다는 것은 "도메인 중심으로 사고"한다는 것이고, 이는 결국 문제 해결을 위해 "모든 수단과 방법을 제대로" 고려하는 것입니다. 이런 사고는 자연스럽게 클린 코드, 소프트웨어, 아키텍처를 고려하는 질문의 연쇄를 불러오게 됩니다.

이런 깨달음을 얻기 까지 참 많은 일들이 있었습니다. 아래는 그 과정의 기록입니다.

DDD의 학습 및 실천 과정

책을 (틈틈이) 읽다

개념을 쌓기 위해 책을 읽는 과정은 중요했습니다. 아래의 책들을 보며 부족한 개념을 쌓기 위해서 틈틈이 반복적으로 봤습니다.

  • 도메인 주도 설계(에릭 에반스): 가장 유명한 책으로 가장 어렵게 느껴졌습니다.
  • 도메인 주도 설계란 무엇인가?(에이벨 아브람, 플로이드 마리네스쿠): 에릭 에반스의 도메인 주도 설계를 요약해서 설명해주는 책이었습니다.

이 두 책을 봐도 구현적인 부분이 도통 감이 안와서 다음과 같은 책들을 읽었습니다.

  • 도메인 주도 설계 구현(반 버논): 에릭 에반스 책에서 말하는 부분들의 실제적인 구현에 대해서 실마리를 얻을 수 있었습니다.
  • 도메인 주도 설계 핵심(반 버논): 그래도 역시나 부족했기에 핵심 요약을 다시 참고해서 봤습니다.

좋은 책들을 봐도 이해가 바로 되진 않았습니다. 결정적인 진전의 계기는 지난 여름 작은 회의실을 점유하고 팀원들과 함께 했던 이벤트 스토밍과, 몹 프로그래밍을 하며 여러가지 실험적 사고를 팀으로써 함께 한 시간이었습니다.

이벤트 스토밍

몹 프로그래밍을 하기 전에 팀에서는 이벤트 스토밍이라는 방법을 통해서 도메인에 대해서 "탐험의 시간" 보냈습니다. 우리는 기존에 있던 도메인을 분석하고 그것을 있는 그대로 받아들이는 것이 아니라, 옳고 그른지 고민하고, 도메인(비즈니스) 적으로 그것이 합당한가 치열한 브레인스토밍을 실시간으로 해가며 몹 프로그래밍을 하다가 무언가 난관에 봉착하면 이벤트 스토밍을 한 결과물을 다시 살펴보고 이상한 것이 있으면 다시 수정해가며, 우리 머리 속의 컨텍스트를 하나로 만들어 갔습니다. 저는 이 과정에서 가상의 부서와 사람들이 어떤 식으로 메시지를 주고 받고 소통을 하는지 그려가며 점점 견고해지는 도메인 지식을 체험했습니다.

이벤트 스토밍을 하기에는 화이트 보드와 포스트잇만 있으면 충분하지만 장기적으로 재점검하고 여러번 수정해야 하는 현실적인 부분 때문에 Miro를 추천합니다. 다만 처음 시작하신다면 점진적으로 개선하고 통합하는 감각을 익히실 때까지는 물리적인 수단인 포스트잇 사용을 권합니다.

몹 프로그래밍

치열하게 이벤트 스토밍을 했어도 도메인에 대한 이해가 저마다 다르다는 것은 코딩을 하는 순간 바로 포착이 됩니다. 인터페이스와 클래스의 이름. 메서드의 이름에서 도메인에 대한 이해가 부족함이 느껴지는 순간들이 여럿 있었습니다. 테스트 코드를 작성 할 때도 우리는 도메인과 관련된 질문을 반복적으로 서로에게 참 많이 했습니다.

  • "현장의 사용자들이 과연 이 행위와 동작을 그들의 생각(도메인 지식)과 언어(유비쿼터스 랭귀지)로 이해할 수 있는가?"
  • "이것이 진정 그들의 관심사(바운디드 컨텍스트) 안에 있는가?"

함께 코드를 구현하고 책에 나온 이야기와 각자의 생각을 코드로 구현하며, 우리는 실마리를 하나씩 풀어갔습니다. "XX란 무엇인가?" 라는 화두를 매번 던져가며 열심히 토론하고 그것을 입증하는 테스트를 작성하고 통과하고 리팩토링하고.. 하루가 끝나면 다들 너무 지쳐서 집에 가면 바로 곯아 떨어지던 나날이었습니다.

잦은 토론과 실험

그 어떤 디자인적 사항들도 한 번에 확정적으로 정해지지 않았습니다. 우리는 탐험가의 자세로 해결하고자 하는 문제가 어떻게 생겼는지, 사람들의 증언과 현재 시스템의 모양새와, 앞으로 나아가고자 하는 방향과 계속 확인하며, 무엇이 최선인지를 끝없이 고민하고 기꺼이 토론하고 고민했었습니다. 코드를 짜는 것 보다 더 많은 것들에 대해서 논하고 그림을 그리고 실험해봐가며 우리의 컨텍스트를 꾸준히 쌓아갔습니다. 변수명이나 메서드명 하나도 마음에 들지 않으면 며칠 고민해서 다시 더 적합한 이름으로 바꾸기를 수 차례 반복했습니다.

(이 때, 테스트 코드가 없었다면 우리는 이런 다양한 가설을 검증하고 무엇이 더 올바른지 판단할 수 없었을 것이며 중간에서 표류하거나 좌초 했을 것 입니다.)

어!?, 되네?! (간증의 순간)

DDD를 추구하며 팀으로 호흡 하자 자연스럽게 많은 질문이 쏟아져 나왔고 우리는 이런 집요한 질문이 결국 "객체지향 설계원칙들" 마저 포함하는 질문이라는 것을 어느순간 깨닫게 되었습니다.

그리고 강둑이 터지듯 모든 도구와 방법론들이 지금 이 순간 DDD라는 이름 하나로 연결되는 깨달음의 순간이 찾아왔습니다.

클라우드 서비스의 등장과 성장이 그 동안 불가능에 가까웠던 도메인 계층과 애플리케이션과 인프라 계층을 매우 유사하게 표현할 수 있는 실마리를 제공해 주었고, 그 동안 하고 싶었어도 적절한 수단이 없어 개발 대중에게 미진했던 DDD의 길이 마침내 일반 개발자들에게도 슬금슬금 보이기 시작했고, 그걸 필두로 다양한 방법론과 도구들이 DDD라는 지극히 당연한 소프트웨어의 사명(문제해결)을 위해서 총동원 되어야 한다는 사실을 깨달았습니다.

클라우드 서비스가 시장에 등장하던 시절 마케팅이라고 뜬구름 잡는다던 교수님 말씀을 들었던 십여 년 전의 기억부터 MSA를 구성하는 수 많은 아키텍처적 패턴들과 DDD 까지 제가 아는 모든 개발지식들의, 느슨하지만 실존하는 연결이 강렬하게 느껴졌습니다.

(저는 10여 년 전의 교수님이 틀렸다는 사실을 깨달으며 특히 신났습니다.)

55 이것들이 전부 있어야 그게(DDD)가 가능하구나!!!!

우리팀이 일궈낸 비즈니스적 쾌거는 우리들이 만든 시스템이 별 탈 없이 전례없던 트래픽을 견뎌내며 과거의 레거시 시스템과 압도적으로 뛰어난 성능을 선보였다는 점입니다. 만약 팀이 아닌 개인이었다면, 또는 우리가 기술적으로 성급히 결론을 내렸다면 이런 일은 일어나지 않았을 겁니다.

우리가 DDD를 시도하며 얻은 진정한 가치는 격언과 원칙으로만 받아들이던 사실들이 이런 절실하고 성실한 과정을 통해서 도달한 경험적인 부분과 학문적인 부분이 부합한다는 사실을 체험했다는 사실 입니다.

학문과 경험이 마주하는 순간

우리는 더 이해하기 쉽고 합리적인 시스템을 만들기 위해서 기술 스택의 확정을 최대한 보류했습니다. 꾸준히 테스트 주도 하에 도메인 영역을 우선적으로 만들고 알맞는 최적의 인프라를 추가해 가는 식이었습니다.

우리가 만든 도메인의 테스트 커버리지가 꾸준히 100%에 육박할 때, 하나씩 인프라를 추가하면서, 거기에 적합한 최적의 기술을 하나씩 선별해서 그것이 동작하게 만들 때, 과거의 정해진 환경에서 무언가를 만들어내던 것과는 전혀 다른 감동을 느꼈습니다.

그렇지만 그 순간부터 기술적 고난이 찾아왔습니다. 인프라는 우리가 생각한 것 보다 호락호락 하지 않았으며, 설정과 성능에 대한 다양한 이슈가 저희에게 많은 고통을 주었습니다. 개발까지의 여정은 성공했으나, 배포와 운영(효율화와 모니터링 등)이라는 암초를 마주하게 되었습니다.

그래서 감히 강조해가며 말씀 드리고 싶은 부분(DDD를 시도할 때 주의할 점)은 DDD와 관련된 원리에 몰두하는 것 만큼 기술적인 것들에 대해서도 매우 많은 노력이 필요 했다는 사실을 분명히 말씀드리고 싶습니다.

어?! 이게 안되네!? (야근의 시간)

저희와 비슷한 방법으로 이 여정의 막바지에 도달한 분들이라면 공감하시겠지만 DDD를 시도하는 순간 모든 수단과 방법을 동원해서 목적하는 바를 이뤄내야 합니다. 여기까지 온 이상 기술적 이유로 인한 후퇴는 없습니다. (어떻게 만든 테스트 커버리지 인데!)

처한(익숙한) 기술적 상황에 우리가 만들어내는 서비스를 끼워 넣는 것이 아니라 우리가 만들고자 하는 서비스에 필요한 모든 것을 최선을 다해 최고의 수단을 제공해 주어야했습니다. 우리가 당황했던 부분들은 '인프라'라고 통칭할 수 있는 여러가지 배경적인 기술과 도구들의 특성이 우리가 의도한 것과 다르거나 상당히 까다롭다는 사실이었습니다.

그럼에도 우리는 도메인적 특징을 포착하고 데이터 소스를 MongoDB와 MySQL 두개를 혼합해서 썼으며, 최적의 퍼포먼스를 측정해낸다거나 드라이버의 버전 이슈와 하찮게 여겼던 라이브러리의 버전업으로 인한 재난이라던가, 그 외에도 각종 설정과 배포와 모니터링 등 온갖 장애물에 질리도록 두드려 맞아가며 전진했습니다.

이 과정에서 AWS를 책임지는 내부 SEO 조직의 불철주야 노력과 처음 만드는 불확실한 환경 구성임에도 성실하게 구성하고 처리량이라던가 최적의 인스턴스 사이즈라던가를 전부 실험해가며 최적의 값을 찾아준 덕분에 우리가 만들어낸 서비스의 목적에 부합하는 인프라를 손에 넣을 수 있었습니다.

즉, DDD를 한다는 것은 인프라 차원에서도 매우 도전적인 과제였으며, DDD의 특성(도메인 중심!) 상 인프라도 도메인 중심적인 구성과 책임의식이 수반되도록 전환되는 과정이었습니다.

1편의 마무리

우리팀은 이제 DDD의 최소한의 경험을 손에 넣었습니다. 오라클 DB의 nvl 쿼리 때문에 NPE도 자주 봤던 제가 이제는 컬리에서 DDD를 조금 이해했다고 합니다. 이 글이 DDD로의 도전을 망설이는 여러분들에게 조금이나마 도움이 되었으면 좋겠습니다. 코쓱

다음편에는 실천에 대한 자세한 이야기로 찾아뵙겠습니다. :)


이미지 출처