diff --git a/2026/Fundamentals_of_Software_Architecture_2nd_Edition/taehyoung/8.md b/2026/Fundamentals_of_Software_Architecture_2nd_Edition/taehyoung/8.md new file mode 100644 index 00000000..b38b16cb --- /dev/null +++ b/2026/Fundamentals_of_Software_Architecture_2nd_Edition/taehyoung/8.md @@ -0,0 +1,30 @@ +# 8장 + +- 논의주제 + - 책에 나오는 코드 재사용의 구체적인 방법들 중에서, 실제로 겪은 가장 최고의 경험과 최악이 있다면, 공유하고, 책에 나온 관점에서 어떻게 수정해볼 수 있을지 생각해보면 좋을 것 같다. +- 요약 + - 여러 마이크로 서비스의 코드 재사용의 구체적인 방법과 그 트레이드오프에 대해서 논의한다 +- 키워드 + - 코드 재사용(code reuse) + - 코드 복제 + - 공유 라이브러리 + - 디펜던시 관리 vs 변경 관리 + - 버저닝 전략 + - 공유 서비스 + - 변경 리스크 + - 성능 + - 확장성(트래픽 대비) + - 내고장성(장애상황 대비) + - 사이드카 +- 내 생각 + - 코드 복제의 경우는 매우 원시적인 방법처럼 보일지 모르지만, 어찌보면, 가장 빠르게 문제를 해결할 수 있는 방법일 수도 있다고 생각한다. 이후에도 나오겠지만, 공유라이브러리, 공유 서비스 등을 도입했을 때, 고려해야하는 수많은 트레이드오프를 생각하면, 가장 원시적이지만, 가장 간단하게 처리할 수 있는 방법일 수 있다. 그래서, 원시적 방법이므로, 배척하기보다는 상황에 맞게 쓸 수 있으면 좋을 것 같다 + - 코드 복제의 개인적인 경험은 2가지 정도 있는데, + - 첫 번째는, common으로 사용하는 Utility성 코드를 코드 복제로 사용해 본 적이 있다. 사내에서 사용하는 java spring skeleton project에 이미 구현된 common package 가 있었고, 이걸 클론해서 개발하게 되면, 자연스레 이 common package 를 사용하게 되었다. 책에 나온대로, 애초에 전사 단위에서 맞춘 Utility성 코드들이었기 때문에, 클론한 이후에 한 번도 수정한 적이 없었고, 나름 나쁘지 않은 전략이라고 볼 수 있었다 + - 두 번째는, SNS message schema 를 관리하는 별도의 repo를 두고, schema 를 각 MS 별로 모두 협의가 되면, 이 repo의 코드를 복사, 붙여넣기 하는 방식으로 했었다. EDA 환경에서 Event 를 정의하고, 협의하고, 이를 적용하기까지 MS가 많으면 많을수록, 이 과정이 복잡한데, 나름의 합리적인 방법을 풀었다고 생각한다. 다만, 수정이 잦을 때,(이벤트 추가/수정 등) 이 부분이 병목이 되기도 하였고, 복사 붙여넣기를 사람이 수기로 하면서, 잘못 붙여넣기를 하는 경우도 있긴 했었다(물론 코드리뷰에서 발견 되었지만) 책에서는 서비스 마다 코드가 중복되기 때문에, 코드 바꿀 일이 있을 때, 서비스 전체에 반영해야 하는 어려움이 있다고 했는데, 이미 협의된 프로세스였기 때문에, 병목이긴 했지만, 문제라고 생각하진 않았었다 + - 공유 라이브러리의 경우는 사내에서 한번 겪어보았는데, 특정 topic에 SNS event를 publish 하는 client library 였다. 간단한 기능이었고, 수정이 거의 없었기 때문에, 책에서 말하는 디펜던시나, 변경관리의 문제가 크진 않았었다. 다만, 한 번 버전이 업데이트된 적이 있었는데, 이때 버전을 업데이트해야 하는 절차 자체가 라이브러리 업데이트 이후, 기능 테스트까지 진행하면서, 번거로웠던 기억이 있다. 하지만, 책에서 말한대로, 변경 빈도가 낮다는 전제하에서, 컴파일 타임에 서비스에 바인딩 되어서, 미리 문제를 확인할 수 있는 것은 큰 장점인 것 같고, 단점으로 제시하는 디펜던시 관리나 변경관리는 큰 문제는 아니었다(아마도, 이를 딥하게 쓰는 회사에서는 제때 라이브러리 업데이트를 하지 않았다면, 큰 문제가 되었을 수도 있을것 같다) + - 공유 서비스의 경우는 사내 인증 서버 연동을 통해서 경험해보았다. 아마 인증서버를 공유서비스로 구현한 사유는 사내에 파이썬 개발환경, 자바 개발환경의 서버가 공존하고 있는 MSA 환경을 고려한 것이지 않을까 생각된다. 책에서 문제를 제기하는 성능, 확장성은 로그인의 횟수가 트래픽에 큰 영향을 줄 정도로 큰 작업은 아니다 보니, 운영하면서 큰 문제는 아니었던 것 같다. 다만 내고장성의 경우는 서버가 어떤 문제로 죽었을 때, 로그인을 못하는 문제가 발생한 적은 있어서, 개인적으로는 이 부분이 가장 큰 문제이지 않을까 생각된다. 이런 공유서비스는 반드시 하위호환성을 고려해서 API 를 설계해야하는데, 이를 위해서는 반드시 API 버저닝이 필요하다. 책에서는 이 버저닝으로 API path를 변경하는 게 문제라고 말했는데, 실제 운영할 때, 클라이언트 입장에서는 api path 만 변경 하면 되고, 새 API에서 비즈니스로직의 문제가 있더라도, 개발서버에서 미리 확인이 되기 때문에 큰 문제는 아니었던 것 같다 + - 사이드카 패턴은 istio 사용을 통해서 경험을 해보았다. k8s 환경에서 많은 MS들의 Pod 간의 네트워크 트래픽 제어를 위해서 사용하고 있고, MS 수가 많다보니, 공통의 네트워크 정책을 적용하기 위해서 도입한 것으로 알고 있다. Istio의 트래픽 라우팅을 많이 사용하고 있는데, 팀별 오너십의 관점에서 사용되는 것으로 볼 수 있을 것 같다 + - 코드 재사용 문제는 꼭 마이크로 서비스가 아니더라도, 항상 있는 문제 같다. 책에서 말하는 재사용의 오남용 위험성은 나도 매우 동의하는 바이다. 특히 변경이 잦고, 변경 시에 매우 크리티컬한 문제가 발생할 수 있는 경우에는 코드의 격리가 제대로 되지 않은 문제 때문에, 오히려 코드 재사용이 문제가 되는 경우가 더 많았었다. 마이크로 서비스에서도 마찬가지로 무작정 중복이라서 추출하지 말고, 상황을 잘 고려해서 가장 적절한 전략이 무엇일지 고민하고 적용하는게 좋다고 생각한다 + - 중복은 나쁜 것이라고 치부하고, 무조건 적인 추출 및 추상화를 하기보다는, 설계 의도를 더 많이 고민하는게 좋을 것 같다. + - 8.6에 나오는 그림 8-16의 고객 도메인 MS 의 사례가 현재 내가 일하고 있는 회사의 팀에서 맡고 있는 도메인의 상황과 비슷하다. 외부 중개사와 연동하는 MS 라는 딱지를 붙이다 보니, 관련된 모든 기능들의 추가 혹은 수정이 잦고, 무분별하게 코드 중복을 처리하다보니, 유지보수하기 매우 어렵게 되어 있는 상황이다 + - 8.7의 경우 데이터베이스 접근하는 코드를 어떻게 제공할 것인가에 대한 내용인데, 일단 서비스 자체도 잘못 나눈 것 같고, 공유서비스로 쓰는 것 자체도 잘 공감이 되진 않는다. 일반적이라면, 티켓이라는 MS 로 묶어서 운영할 것 같고, 각 생성, 배정, 완료에 대한 DB 액션은 repository 객체로 구현해서 사용할 것 같다. \ No newline at end of file diff --git a/2026/Fundamentals_of_Software_Architecture_2nd_Edition/taehyoung/9.md b/2026/Fundamentals_of_Software_Architecture_2nd_Edition/taehyoung/9.md new file mode 100644 index 00000000..24c7fb5f --- /dev/null +++ b/2026/Fundamentals_of_Software_Architecture_2nd_Edition/taehyoung/9.md @@ -0,0 +1,37 @@ +# 9장 + +- 논의 주제 + - 데이터 일관성이 중요하다고 판단이 된다면, 분산 트랜잭션의 최종 일관성을 지키는 방법들을 고민하는 것보다, 최초에 설계할 때부터, 분산 트랜잭션이 되지 않도록, 경계 컨텍스트 설정 시부터, MS들을 과도하게 나누지 않도록 설계하는 게 어떨지 만약 이와 같이 했을 때 생길 수 있는 문제점은 무엇일지 의견 나누어보면 좋을 것 같다. + - 최근에 드는 생각은 크리티컬한 도메인일수록, MS를 나눌 때, 더욱 트랜잭션을 고려해서, 트랜잭션이 중요한 경우는 차라리 나누지 않는 게 더 이로울 수 있다는 것이다. 이벤트를 통해서 통신하려고 하는 이유는 비동기성을 활용한 처리량을 높이는 것이라고 생각하는데, 처리량을 늘리기 위해서, 고려해야 할 분산 트랜잭션 트레이드오프는 너무 큰 것 같다는 느낌이다. 실제 운영을 해보았을 때는 장애가 나지 않는 이상은 메시지가 유실돼서 문제가 생긴 적은 없었던 것 같다. 가끔씩 동시성 이슈나 순서 꼬임 문제들이 있긴 했지만, 큰 이슈는 아니었다. 다만, 장애가 난 경우에 각 서비스마다 DB 상태가 다 틀어지는 문제들은 아직도 겪고 있다. + - but, 문제점은 MSA 이론을 열심히 적용해서, 서비스를 잘 나눠놨는데, 도로 모놀리식이 될 수도 있다고 생각한다. 다만, 이론 자체보다는 현재 내 회사와 팀의 맥락 하에서, 고객의 요구사항을 잘 들어주면서, 유지보수하기 쉬운 형태인지를 판단해서, 더 실용적인 방법을 도입하는 쪽으로 고민하는 게 더 좋지 않을까 생각한다 +- 요약 + - 데이터 오너쉽 + - 운영 유지보수를 원활하게 하기 위해서, 각 MS 별 데이터 오너쉽을 명확하게 해야 한다 + - 분산 트랜잭션 + - 분산 환경에서, DB의 ACID 트랜잭션을 활용할 수 없기 때문에, 어쩔 수 없이 최선으로는 최종적 일관성을 맞추기 위한 노력을 해야 한다 +- 키워드 + - 데이터 오너쉽 + - 단독 + - 공통(common) + - 공동(joint) + - 서비스 통합 + - DB 트랜잭션 + - ACID + - 분산 트랜잭션 + - BASE + - 최종 일관성 + - 백그라운드 동기화 + - 오케스트레이티드 요청 기반 + - 이벤트 기반 +- 내 생각 + - 단독 오너쉽을 결정하는 것은 그리 어렵지 않다. 나뉘어진 도메인들을 기준으로 해당 테이블에 값을 쓰는 게 가장 적절하다고 생각하는 혹은 어색하지 않은 서비스를 판별해서 결정하면 된다. 그래서 책에서 말한 대로, 단독 오너쉽을 먼저 다 결정한 이후에, 판단 내리기 어려운 것들만 모아서, 공통/공동/서비스 통합을 나누면 될 것 같다. + - 공통 오너쉽의 예시로 Audit이 나왔고, 책에서는 Audit 테이블에 책임을 지는 감사 서비스를 만드는 방식으로 문제를 해결하였다. 공통 오너쉽의 예시를 만들기 위해서는 이해하기 쉽다는 취지에서 적절한 해결책으로 보이긴 한데, 현실 세계에서 적절한 예시는 아닌 것 같다. 경험상 감사 기능은 각 서비스별로 필요에 따라서, 구현을 했었기 때문에 굳이 서비스로 나누어서 관리해야 하나라는 생각이 들었다. 만약에 감사 로그에 대한 기록을 제공하는 화면을 제공해야만 하는 상황 맥락이 주어졌다면, 감사 로그 조회를 하나의 DB에서 쿼리하는 것으로 할 수 있기 때문에 조금 공감이 갔을 것 같긴 하다 + - 공동 오너쉽에 나오는 테이블 분할 기법은 회사에서 꽤나 자주 사용하는 방법이다. 아무래도 각 팀마다 관리하는 MS가 나뉘어져 있고, 다른 팀에 의존되지 않게 설계를 진행하다 보면, 결국에는 각 MS마다 별도로 관리하는 테이블을 만들어서 관리하는 경우가 많다. 그림 9-5처럼 설계할 경우에는 굳이 동기 통신을 하진 않아도 될 것 같다. 카탈로그 서비스의 책임은 메뉴를 CRUD 하는 것이고, 재고 서비스는 이 CRUD 이벤트에 의존한다. 카탈로그는 메뉴 CRUD 이벤트 발행까지가 책임인 것이고, 재고 서비스에서 정상적으로 처리되었는지 여부는 크게 중요하지 않기 때문에, 비동기 파이어 앤드 포겟 통신으로 처리하고, SNS+SQS로 메시지가 유실되지 않도록만 설계하면, 문제가 없을 것 같다 + - 데이터 도메인 기법의 경우, 앞장에서 테이블을 공유하지 않는다고 했던 것과 같은 맥락에서, 일반적이지 않은 접근으로 보인다 + - 위의 데이터 도메인보다는 대리자 기법이 일반적으로 많이 쓰이는 방식이고, 데이터 도메인 기법의 단점을 커버할 수 있다고 생각한다. 문제라면, event 혹은 API 통신 등 서비스 간 네트워크 통신이 반드시 필요하게 되는데, 이 절차가 데이터 도메인 기법을 선호하는 사람의 입장에서는 좀 귀찮을 수 있을 것 같다. + - 서비스 통합 기법은 다시 모놀리스로 돌아가는 방법이라고 볼 수 있다. 이를 통해서, 얻는 이득이 더 크다면, 이 방법도 적극적으로 고민해 보고 적용해 볼 수 있다고 생각한다. 카탈로그 관리와 재고 관리의 경우는 서비스를 나누는 방법도 나쁘지 않지만, 서비스 통합 기법을 통해서, 트랜잭션을 활용하는 것도 나쁘지 않다고 생각한다. 어떤 트레이드오프를 받아들일 수 있을지에 대한 것은 각 팀의 상황에 따라 다를 것 같다 + - 분산 트랜잭션 파트는 DB 트랜잭션을 전체 서비스끼리 통신하는 형태에서는 완벽히 보장할 수 없기 때문에, 최종적 일관성을 어떻게 잘 도입해서 해결할지에 대한 얘기로 볼 수 있다 + - 최종 일관성 패턴 3가지가 나오는데, 현재 회사에서 진행한 방식은 이벤트 기반 패턴이다. + - 일단, 백그라운드 동기화 패턴은 제약 사항이 많다. 그래서 특정 상황에서만 사용할 수밖에 없다. + - 오케스트레이티드 요청 기반의 핵심은 트랜잭션을 관리하는 오케스트레이터가 있고, 분산 트랜잭션을 관리한다. 이론적으로, 트랜잭션 관리의 복잡성을 오케스트레이터가 잘 관리해줄 것을 기대한다. 하지만, 현실적으로는 서비스가 커질수록, 오케스트레이터 내부 코드 복잡도도 커지고, 장애 발생 시에 SPOF로서, 큰 문제가 발생할 수 있다고 생각한다. + - 이벤트 기반은 이해하기 어렵지 않고, 최종 일관성이 맞춰지는 시간이 보통 짧게 되므로, 사용하는 이득이 분명히 있다. 다만 책에서도 나온 것처럼, 에러 처리에 대해서, 특정 MS의 장애가 발생해서, 이벤트 메시지를 받지 못할 때, 어쩔 수 없이 수기로 다시 메시지를 발행한다든지 수기 처리를 통해서 분산 트랜잭션 동기화를 맞춰줘야 하는 경우가 있긴 했는데, 장애 때마다 힘들었던 기억이 난다.