From 5ed5702d9ded1212a67a660fa221eeb8f9200e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B7=BC=EC=A3=BC?= Date: Sun, 4 Jan 2026 19:41:03 +0900 Subject: [PATCH 1/3] =?UTF-8?q?20260107.=201~3=EC=9E=A5=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../geunju-lee/Chapter_1_to_3.md | 237 ++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 2026/Fundamentals_of_Software_Architecture_2nd_Edition/geunju-lee/Chapter_1_to_3.md diff --git a/2026/Fundamentals_of_Software_Architecture_2nd_Edition/geunju-lee/Chapter_1_to_3.md b/2026/Fundamentals_of_Software_Architecture_2nd_Edition/geunju-lee/Chapter_1_to_3.md new file mode 100644 index 00000000..6131f461 --- /dev/null +++ b/2026/Fundamentals_of_Software_Architecture_2nd_Edition/geunju-lee/Chapter_1_to_3.md @@ -0,0 +1,237 @@ +# 트레이드오프 위에서의 아키텍처 선택 + +## 1 ~ 3장 +--- + +## chapter 1 - '베스트 프랙티스'가 없다면? + +> 정답은 없다. 다만 트레이드오프만 있을 뿐이다. + +우리는 늘 정답을 찾는다. 나 또한 그렇다. +하지만 인생이 그렇듯, 소프트웨어 설계에도 절대적인 정답은 없다. +존재하는 것은 언제나 **장점과 단점**, 그리고 그 사이에서의 **선택**뿐이다. + +아키텍처 설계 역시 마찬가지다. +"어떤 구조가 가장 좋은가?"가 아니라, +**"지금 이 시점의 제약과 상황에서 무엇이 가장 합리적인 선택인가?"** 를 고민하는 문제다. + +그래서 이 책은 정답을 주기보다는, +그 선택을 하기 위해 필요한 **사고의 도구들**을 설명한다. + +### 이 책에서 반복적으로 등장하는 키워드들 + +- coupling / cohesion +- component 경계 +- sync / async +- orchestration / choreography +- atomicity +- contract + +이 단어들은 각각 따로 보면 어려울 수 있지만, +결국은 **"무엇을 함께 묶고, 무엇을 분리할 것인가"** 라는 질문으로 수렴한다. + +책에서 다루는 *한빛가이버* 사례를 읽으면서, +나는 지난 5년간 내가 겪어온 MSA 전환 과정과 굉장히 유사하다는 느낌을 받았다. +정답을 찾아 적용하기보다는, +트래픽·조직·장애·운영이라는 현실 속에서 +계속해서 **트레이드오프를 선택해 온 과정**에 더 가까웠기 때문이다. + +이 챕터는 +"베스트 프랙티스를 알려주는 장"이 아니라, +**이후 챕터들을 어떤 관점으로 읽어야 하는지를 정리해 주는 장**이라고 느꼈다. + +## chapter 2 - 아키텍처 퀀텀 + +> MSA는 '유행'이 아니라, 현재 시스템의 제약과 이해를 바탕으로 선택해야 하는 결과다. + +나의 경험을 예로 들면, 처음에는 다들 그렇듯이 레이어드 모놀리식으로 시작했다. +그 이후 MSA를 목표로 점진적인 전환을 시도하고 있다. + +아직은 DB를 완전히 분리하지 못해, 엄밀한 의미의 MSA를 적용했다고 보기는 어렵다. +다만 향후 DB 분리와 서비스 분리를 가능하게 만들기 위해, 미리 헥사고날 아키텍처와 이벤트 기반 아키텍처를 적용하는 방향으로 설계를 진행 중이다. +(이벤트 기반 아키텍처의 경우, 늘어나는 트래픽 대응이 주된 목적이다.) + +또한 비동기 통신을 위한 보상 처리로 Saga 패턴도 함께 적용하고 있다. + +이처럼 각자의 상황과 제약에 맞게 아키텍처를 선택하는 것이 중요하다고 생각한다. +MSA가 무조건 좋은 것도 아니고, 모놀리식이 무조건 나쁜 것도 아니다. + +## chapter 3 - 아키텍처 모듈성 + +> 아키텍처 별 성격 비교 + +유지 보수성, 시험성, 확장성, 가용성/내고장성 관점에서 보면 +모놀리식 < 서비스 기반 < MSA 순으로 점수가 매겨지는 흐름이 나온다. + +### 정리 + +아키텍처 모듈성을 +유지 보수성, 시험성, 확장성, 가용성/내고장성 관점에서 비교하면 +일반적으로 **모놀리식 < 서비스 기반 < MSA** 순으로 평가가 높아진다. + +이 결과는 "아키텍처의 우열"이라기보다는, +**결합을 얼마나 잘 분리했는가**에 대한 평가에 가깝다고 느꼈다. + +- 모놀리식은 변경·장애·확장의 범위가 하나로 묶여 있어 + 규모가 커질수록 리스크가 증폭되기 쉽다. +- 서비스 기반 아키텍처는 일정 수준의 분리를 제공하지만, + 공통 로직과 동기 호출 체인이 늘어나면 다시 결합도가 높아진다. +- MSA는 서비스별 DB 분리와 비동기 통신을 전제로 할 때, + 변경 영향 최소화, 독립 확장, 장애 격리 측면에서 가장 큰 이점을 가진다. + +다만 이 점수표는 +**MSA를 '제대로 운영할 수 있다는 전제'가 붙은 결과**라는 점이 중요하다. +운영 성숙도, 관측성, 재처리, 계약 관리가 뒷받침되지 않으면 +높은 점수는 오히려 높은 복잡도로 돌아올 수 있다. + +결국 이 비교는 +"어떤 아키텍처가 더 낫다"를 말하기보다는, +**어떤 트레이드오프를 선택할 준비가 되어 있는가**를 묻는 기준이라고 생각한다. + +### 논의사항 + +1. **서비스 기반 아키텍처는 ‘과도기’인가, ‘최종 형태’인가?** + 서비스 기반은 MSA로 가기 위한 단계인가? + 아니면 **조직·트래픽·운영 역량이 맞으면 충분히 ‘최종 형태’**가 될 수 있는가? + +2. **MSA의 장점을 얻기 위해 반드시 필요한 전제는 무엇인가?** + DB 분리 없이도 MSA를 했다고 말할 수 있는가? + + +> 아래 내용은 정리나 결론을 위한 글은 아니다. +> 혹시 비슷한 규모의 시스템을 운영하면서 +> 다른 팀은 어떻게 하고 있는지 궁금한 사람이 있다면, +> 참고가 될 수 있을 것 같아 남겨둔 개인적인 경험 기록이다. + +### 경험 사례 – 내가 겪은 아키텍처 선택의 흐름 + +#### 여러 아키텍처를 거치며 느낀 점 + +**레이어드 모놀리스**는 전통적이고 빠르게 시작하기에 좋았다. +하지만 규모가 커질수록 도메인 경계가 흐려지고, +작은 변경이 예상보다 넓은 영역에 영향을 주는 경험을 자주 하게 됐다. + +**모듈러 모놀리스**는 도메인 단위로 모듈을 나누면서 +변경 영향 범위를 줄이는 데는 분명 도움이 됐다. +다만 시간이 지나면서 +"이건 어느 모듈 책임이지?" 같은 애매한 지점이 생기기 시작했고, +그 순간부터 경계를 지키는 일이 생각보다 어렵다는 걸 체감했다. + +**마이크로커널 아키텍처**는 +확장 축(기능/전략)이 반복적으로 추가될 때는 꽤 매력적이다. +예를 들어 PG 연동처럼 +결제/취소/중단(Abort) 흐름이 유사한 기능이 계속 늘어나는 경우에는 +플러그인이나 전략 패턴으로 분리할 가치가 있다. +다만 실제로 운영해보니, +생각보다 이렇게 반복적으로 확장되는 영역은 많지 않았고 +그 외의 영역에서는 과설계가 되기 쉽다고 느꼈다. + +--- + +#### 결국 선택한 방향: 서비스 기반 + 헥사고날 + +서비스 기반 아키텍처는 +팀을 나누고 서비스를 분리하는 데 분명한 장점이 있다. +하지만 실제로 운영해보면 +공통 로직이 생기는 순간부터 선택이 어려워진다. + +- 그냥 복붙할지 +- 공용 라이브러리로 묶을지 +- 아니면 공통 서비스를 하나 더 만들지 + +이 선택을 매번 고민하게 된다. + +특히 서비스 간 동기 호출이 늘어날수록, +장애가 전파되고 배포가 서로 엮이는 경험을 여러 번 했다. +이 지점이 서비스 기반 아키텍처에서 +가장 크게 체감한 한계였다. + +그럼에도 불구하고, +현재의 조직 규모와 트래픽을 고려하면 +서비스 단위로 나누는 선택 자체는 피하기 어렵다고 판단했다. +그래서 내 기준에서의 질문은 +**"나눌 것인가?"가 아니라 "어디까지 나눌 것인가?"** 였다. + +그 결과 나는 +서비스 기반 구조를 유지하되, +헥사고날 아키텍처를 적용해 +서비스 내부의 도메인 경계를 최대한 명확히 하려고 했다. +그리고 공통 로직은 정말 불가피한 경우에만 +내부 모듈이나 라이브러리로 제한하고, +도메인 로직이 공통으로 새어나가지 않도록 의식적으로 막고 있다. + +--- + +### 그리고 EDA + +EDA를 도입한 지점은 **결제 이후**다. +결제 자체는 짧고 확실하게 끝내고, +결제 이후에 따라오는 후속 작업들을 +동기 호출로 묶지 않기 위해 Kafka 기반 이벤트로 분리했다. + +#### 이벤트 발행 (결제 서비스) + +결제가 완료되면 Kafka로 이벤트를 발행한다. +이 이벤트에는 대략 다음 정보가 담긴다. + +- paymentSeq (결제 식별자) +- amount (금액) +- item 정보 (상품 / 구성 / 수량 등) + +중요한 점은 +"무엇을 해라"가 아니라 +**"결제가 완료되었다"라는 사실을 발행**한다는 것이다. + +#### 팀1 컨슘: Timeline 적재 + +팀1은 이 이벤트를 컨슘해서 +결제 건을 Timeline에 적재한다. +이 작업은 결제의 성공/실패와 운명을 같이할 필요가 없고, +지연되더라도 나중에 따라잡을 수 있기 때문에 +비동기 방식이 잘 맞았다. + +#### 팀2 컨슘: 적립 계산 및 반영 + +팀2는 동일 이벤트를 컨슘한 뒤, +자기 정책에 따라 적립 금액을 계산하고 적립을 반영한다. + +적립은 정책·이벤트·프로모션에 따라 변수가 많고, +결제 서비스가 직접 알고 있어야 할 이유가 없다고 판단했다. +오히려 결제 플로우에 섞이면 +변경 영향 범위만 커진다. +그래서 계산과 반영의 책임을 아예 분리했다. + +--- + +#### EDA를 통해 얻은 효과 + +- 결제 서비스는 결제 자체에만 집중할 수 있었다 +- 동기 호출 체인을 끊으면서 더 빠른 결제 및 더 많은 처리량을 달성할 수 있었다 +- 후속 작업은 컨슈머 확장으로 처리량을 맞추고, + 피크 트래픽은 큐가 흡수하도록 만들 수 있었다 + +#### 미래 수정할 점 + +현재는 **결제 완료 이벤트**를 타 팀에서 직접 컨슘해 +내역 적재나 포인트 작업까지 처리하고 있다. + +하지만 앞으로는 다음 형태로 바꿀 예정이다. + +- 결제 서비스는 **결제 완료(Fact)** 이벤트만 발행한다. +- 해당 토픽을 컨슘하는 서비스가 + - **내역 발행 Command** + - **포인트 적립 Command** + 를 각각 발행한다. + +이렇게 하면 내역은 쌓였는데 포인트 적립이 누락된 경우에도 +Admin을 통해 **포인트 적립 Command만 재발행**하는 형태로 보상이 가능해진다. + +#### 운영하면서 중요했던 포인트 + +- 이벤트 중복/재처리는 전제로 두고 멱등하게 설계한다 +- 재처리를 항상 가능하게 만든다 +- 추적을 위해 requestUuid 같은 식별자를 이벤트에 포함한다 +- 사내에 FDC(financial Data Center)가 존재하고, 매일 bulk로 사내 전체 DB를 조회하여 적재한다. 그리고 매일 배치를 돌려서 누락된 적립이 있는지 확인하고, 존재한다면 노티 이메일을 보내준다. 따라서 + 재처리가 가능하다. 이것이 운영에서 가장 중요한 포인트였다. + +이제 마지막으로 검토 한 번 해줘  From 54003006c1b9772d4373b7f86f12b942be2e6ca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B7=BC=EC=A3=BC?= Date: Sun, 4 Jan 2026 19:42:27 +0900 Subject: [PATCH 2/3] =?UTF-8?q?20260107.=201~3=EC=9E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed a line requesting a final review. --- .../geunju-lee/Chapter_1_to_3.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/2026/Fundamentals_of_Software_Architecture_2nd_Edition/geunju-lee/Chapter_1_to_3.md b/2026/Fundamentals_of_Software_Architecture_2nd_Edition/geunju-lee/Chapter_1_to_3.md index 6131f461..a6defb46 100644 --- a/2026/Fundamentals_of_Software_Architecture_2nd_Edition/geunju-lee/Chapter_1_to_3.md +++ b/2026/Fundamentals_of_Software_Architecture_2nd_Edition/geunju-lee/Chapter_1_to_3.md @@ -233,5 +233,3 @@ Admin을 통해 **포인트 적립 Command만 재발행**하는 형태로 보상 - 추적을 위해 requestUuid 같은 식별자를 이벤트에 포함한다 - 사내에 FDC(financial Data Center)가 존재하고, 매일 bulk로 사내 전체 DB를 조회하여 적재한다. 그리고 매일 배치를 돌려서 누락된 적립이 있는지 확인하고, 존재한다면 노티 이메일을 보내준다. 따라서 재처리가 가능하다. 이것이 운영에서 가장 중요한 포인트였다. - -이제 마지막으로 검토 한 번 해줘  From 9303dab0769dc3ede11698fe1029f69c3cb771f4 Mon Sep 17 00:00:00 2001 From: tttghost Date: Sun, 4 Jan 2026 20:04:04 +0900 Subject: [PATCH 3/3] upload chapter 1 --- .../tttghost/chapter 1.md | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 2026/Fundamentals_of_Software_Architecture_2nd_Edition/tttghost/chapter 1.md diff --git a/2026/Fundamentals_of_Software_Architecture_2nd_Edition/tttghost/chapter 1.md b/2026/Fundamentals_of_Software_Architecture_2nd_Edition/tttghost/chapter 1.md new file mode 100644 index 00000000..dd3b8f29 --- /dev/null +++ b/2026/Fundamentals_of_Software_Architecture_2nd_Edition/tttghost/chapter 1.md @@ -0,0 +1,65 @@ +# 1장 '베스트 프랙티스'가 없다면? + +## 주요 내용 +하드파트: 어렵다와 단단하다의 뜻 +아키텍처 설계는 한번 정해놓으면 쉽사리 바꿀 수 없게 되기에 그만큼 근본적이다. +마이크로서비스: 나는 해당하는 부분이 없지만 서버팀에서 서버 설계 시 각 파트별로 나눠서 작업했던 걸 본 기억이 있다 + +오케스트레이션 +여러 서비스 호출의 순서, 성공/실패 판단, 보상 동작까지 하나의 흐름으로 책임지는 중앙 제어 로직 + +데이터는 모든 것: 데이터 설계가 가장 중요하다. +운영데이터와 분석데이터가 있다. +운영데이터는 회사 시스템이 돌아가는 데 필요한 데이터다. 정합성, 트랜잭션이 중요 +분석데이터는 서비스를 이해, 개선, 판단을 위한 데이터로 트랜잭션과 무관하며 과거 누적 축적형 데이터로 현재 운영에 필요하진 않지만 장기적인 전략 수립 및 의사결정에 중요하게 활용되는 데이터다. + +아키텍처 거버넌스 +시스템이 커져도 방향을 잃지 않게 하는 '기술 헌법'이다. +잘못 이해한 경우 = 통제 지옥 +잘 이해한 경우 = 자유를 유지하기 위한 최소 규칙 + +아키텍처 피트니스 함수 +관리해주는 함수. 피트니스 클럽은 몸을 관리해주지만 피트니스 함수는 아키텍처를 관리해준다. +필연적으로 트레이드오프가 발생할 수밖에 없다. 더 빠르게-더 정확하게, 더 강하게-더 가볍게 등 +목표가 하나라면 상관없지만 둘 이상이면 바로 트레이드오프가 발생한다. + +피트니스 함수와 단위테스트는 비슷하지만 다르다. +비슷한 부분은 자동 검증 + 실패 시 즉시 차단이라는 것인데 +피트니스 함수는 아키텍처의 특성을 검증하는 것이고 +단위테스트는 로직의 정확성을 보는 것이다. 즉 도메인 로직을 본다. + +코드 위생 도구인 소나큐브는 피트니스 함수의 재료를 턴키 방식으로 제공한다. +자바 진영의 아크유닛이라는 도구는 소나큐브와 다르게 경고 수준이 아닌 +"이 구조는 금지"라는 규칙을 테스트로 정의해 차단할 수 있다. +닷넷 진영에도 넷아크테스트(NetArchTest)라는 도구가 있다. + +피트니스 함수는 대부분 반복/자동화해 사용하지만 간혹 수동으로 실행해야 하는 경우도 있다. +민감한 법률 정보가 담긴 시스템은 합법성을 준수해야 하기에 변호사가 직접 검토해야 하므로 자동화할 수가 없다. + +이런 아키텍처 피트니스 함수가 중요한 이유는 엔터프라이즈 수준의 거버넌스 사례를 볼 때 지속적으로 체크해야 하는 영역이기 때문이다. +제로데이 익스플로잇이 발견될 수도 있지만, 지속적인 피트니스 함수로 구조, 의존성, 권한 경계 등을 체크한다면 그 확산과 피해를 최소화할 수 있다. + +피트니스 함수는 아키텍처 구조를 설계하는 사람에게 단비 같은 존재이다. +모든 코드를 직접 많이 볼 수는 없지만(코드의 디테일이 아니라 구조의 방향성을 보기 위함), 피트니스 함수를 통해 프로젝트의 구조와 상태를 검증할 수 있기 때문에 해당 프로젝트의 전반적인 방향성을 잡을 수 있다. + +하지만 피트니스 함수의 과용은 금물이다. +너무 복잡한 피트니스 함수는 오히려 설계 의도를 흐리고, 개발자에게 '무엇을 지켜야 하는지'를 모호하게 만든다. + +아키텍처와 설계는 구분되어야 한다. +아키텍처 결정 - 구조 설계 + +아키텍처의 기본 원칙을 이해할 때는 How보다 Why가 더 중요하다. +아키텍처 개념에 집중하면 구현부에 대한 상세한 이야기는 과감히 건너뛸 수 있다. +구현 과정을 일일이 따라가기 시작하면 논의 범위가 지나치게 방대해지기 때문이다. + +아키텍처의 개념들은 다음과 같이 볼 수 있다. +서비스, 커플링, 컴포넌트, 동기통신, 비동기통신, 오케스트레이션, 코레오그래피(오케스트레이션과 반대), 원자성, 컨트랙트(계약) 등이 있다. + +사가(Saga)는 영웅적인 업적을 기리는 긴 이야기라는 의미에서 유래했다. +결제 서비스와 배송 서비스가 있을 때, 결제 서비스는 성공했지만 배송 서비스가 실패한 경우, 오케스트레이션 사가를 통해 결제 취소라는 보상 트랜잭션을 실행하여 사가를 실패 상태로 종료한다. + +## 논의 주제: 아키텍처 검증의 자동화와 수동 검토 +피트니스 함수에서 자동화한 부분(소나큐브, 아크유닛 등)과 수동으로 검토해야 하는 부분이 +있다고 나오는데 실무에서 이 두 부분에 대한 경험이 있으신가요? + +어떤 것을 자동화하였고 어떤 것을 왜 사람이 직접 해야 했는지 궁금합니다. \ No newline at end of file