Loading...
Skip to Content

마이크로서비스 설계의 핵심 : 응집도와 결합도 이해하기

  오늘은 마이크로서비스를 설계하는 데 있어 굉장히 중요하게 다뤄지는 개념인 응집도와 결합도에 대해 알아보겠습니다.

응집도란 한 모듈 내부의 요소들이 얼마나 밀접하게 연관되어 있는지를 나타냅니다. 높은 응집도를 가진 모듈은 명확하고 집중된 목적을 가집니다.

결합도는 서로 다른 모듈 간의 상호의존성 정도를 의미합니다. 낮은 결합도는 모듈 간 독립성을 높이고, 시스템의 유연성과 확장성을 크게 향상시킵니다.

마이크로서비스 설계의 핵심 : 응집도와 결합도 이해하기

응집도가 높고 결합도가 낮게 설계된 소프트웨어효율적이며 유지보수 및 기능 확장에 용이합니다. 이를 보다 쉽게 이해하기 위해 실생활 예시를 들어 설명드리겠습니다.

샌드위치, 햄버거, 피자 등 다양한 빵 요리를 취급하는 식당이 있다고 가정하겠습니다. 대부분의 식당에서는 빵, 채소, 고기와 같은 식재료를 한 곳에 모아두고, 다양한 조리도구를 또 한 곳에 모아두는 식으로 배치를 해두죠.

이렇게 종류 별로 배치를 해두면 필요한 요소를 찾기에는 용이하지만, 주문이 들어올 때마다 해당 재료 및 조리도구를 가져와야 하는 비효율적인 구조가 됩니다. 이를 소프트웨어에 비유하면, 시스템 상에 어떠한 요청이 들어올 때마다 그것을 처리하는 데 필요한 데이터를 그 때 그 때 받아와야 하는 구조가 되는 것이죠.

마이크로서비스 설계의 핵심 : 응집도와 결합도 이해하기

위 이미지는 앞서 설명한 구조로 설계된 주방이 업무를 처리하는 모습을 표현한 이벤트스토밍 모델입니다. 재료와 도구가 데이터의 개념으로 그룹화되어 있고, 조리 단계에서 필요한 재료를 Req/Res(Request/Response, 요구/응답, 즉 동기 통신) 방식으로 각 데이터베이스에서 하나하나 가져오는 형태를 띄게 되죠.

이러한 구조를 Chatty Microservice라고 합니다. 말 그대로 마이크로서비스 간에 데이터를 참조해오는 통신(대화)이 너무 많아 대표적인 안티패턴으로 분류됩니다. 이렇듯 어떠한 행위가 이루어지기 위해 필요한 요소들이 여기 저기 흩어져있는 상황을 응집도가 낮은 경우라고 볼 수 있습니다.

 그렇다면 위 모델을 어떻게 응집도를 높이고 결합도는 낮추는 방향으로 개선할 수 있을까요?

마이크로서비스 설계의 핵심 : 응집도와 결합도 이해하기

위 이미지는 앞서 소개된 모델을 개선한 이벤트스토밍 모델입니다. 여기서는 바운디드 컨텍스트를 ‘샌드위치 제조’, ‘햄버거 제조’, ‘피자 제조’ 와 같이 각 메뉴 별로 제조 과정을 따로 구분하였습니다. 각 컨텍스트 내에 해당 음식을 제조하는 데 필요한 조리과정이 이벤트로 나열되어 있고, 어그리거트 내부에 각 음식 별로 필요한 재료가 데이터로 추가되어 있습니다. 이렇게 데이터와 기능을 통합함으로써 응집도가 높아지고 결합도가 낮아지는 설계가 가능해졌습니다.

이러한 설계 개선을 통해 소프트웨어의 유지보수성과 확장성이 크게 향상될 수 있습니다. 각 바운디드 컨텍스트가 독립적으로 작동하므로 특정 기능 변경이나 추가가 다른 영역에 미치는 영향을 최소화할 수 있습니다. 기능 및 관심사 별로 바운디드 컨텍스트를 명확히 구분하고 각 컨텍스트 내에서 필요한 데이터와 기능을 통합하는 것이 효율적이고 유지보수가 용이한 소프트웨어 설계의 핵심입니다.

 그렇다면 실생활 예제를 조금 더 심화해서 실제 서비스되는 애플리케이션을 예시로 응집도와 결합도의 중요성을 다시 한 번 알아보겠습니다.

마이크로서비스 설계의 핵심 : 응집도와 결합도 이해하기

위 이벤트스토밍 모델은 우리가 실생활에서 흔히 이용하는 배달 애플리케이션의 DB 구조와 애플리케이션의 서비스 흐름을 나타내고 있습니다. 앞서 살펴본 식당의 예시와 마찬가지로 고객과 식당, 라이더의 정보를 각각의 바운디드 컨텍스트 내부에서 데이터로 관리하고 있고, 서비스가 진행됨에 따라 각 단계에서 필요한 데이터를 동기 통신으로 받아오는 Chatty Microservice의 형태를 보여줍니다.

마이크로서비스 아키텍처를 구축할 때 가장 많이 하는 실수는 관심사를 DB 관점에서 쪼갠다는 것입니다. 물론 데이터 관리 측면에서는 각 분야 별 데이터를 따로 관리하면서 서비스를 제공하는 것이 마이크로서비스 전환의 방법으로 보일 수 있지만, 이러한 형태의 설계에서는 서비스 흐름에서 이루어지는 모든 행위가 하나의 바운디드 컨텍스트에서 관리되는 Tight Coupling, 즉 높은 결합도를 야기하게 됩니다.

마이크로서비스 설계의 핵심 : 응집도와 결합도 이해하기

앞서 보여드린 안티패턴을 응집도/결합도 측면에서 개선한 모델은 위와 같습니다. 고객이 행하는 주문이라는 행위, 식당에서 그 주문 정보를 받아 음식을 준비하는 행위, 완성된 음식을 라이더가 픽업해 고객에게 배달하는 행위 등 서비스의 흐름을 행위 관점에서 3개의 관심사로 쪼갠 모습입니다.

이렇게 설계된 서비스는 도메인 이벤트, 즉 어떠한 행위로부터 발생된 결과가 다른 관심사를 가진 서비스에 Pub/Sub(Publish/Subscribe, 발행/구독, 즉 비동기 통신) 방식으로 전달되면서 진행됩니다.

이러한 형태를 띄게 되면 한 쪽의 서비스에 장애가 발생했을 때도 다른 서비스의 기능이 작동하는 데에 영향을 끼치지 않고, 각 서비스가 독립적으로 작동하는 마이크로서비스의 이상적인 형태를 띄게 됩니다.

 위처럼 응집도와 결합도를 고려하여 서비스를 개선할 수 있는 방법은 다음과 같습니다.

응집도 개선 측면

  1. 단일 책임(Single Concern) 원칙 철저히 적용하기 - 복잡한 로직을 더 작고 집중된 단위로 분해하여 각 클래스와 모듈이 오직 하나의 명확한 책임만을 가지도록 합니다.
  2. 메서드의 크기와 복잡성 관리 - 메서드는 간결하고 명확하게 작성하고, 가능하면 20-30줄 이내로 유지하는 것이 좋습니다.
  3. 논리적 그룹화 - 관련된 기능은 같은 클래스나 모듈에 배치하고 패키지와 네임스페이스를 활용해 코드의 논리적 구조를 명확히 해야 합니다.

결합도 개선 측면

  1. 의존성 주입으로 유연성 확보 - 객체 간 직접적인 의존성을 줄이고, 인터페이스를 통한 느슨한 연결을 만들어야 합니다.
  2. 추상화의 힘 - 구체적 구현보다는 코드의 변경 가능성을 극대화하고 확장성을 보장할 수 있는 인터페이스나 추상 클래스에 집중합니다.
  3. 관심사 분리 - 데이터 처리, 비즈니스 로직, UI 로직 등을 명확히 분리하여 각 모듈이 고유의 명확한 역할에 집중할 수 있도록 합니다.

 앞서 설명한 높은 응집도와 낮은 결합도를 가진 마이크로서비스 아키텍처를 설계하는 것은 쉽지 않은 과제입니다. 이러한 복잡한 과정에서 개발자들에게 실질적인 도움을 주고자 'MSA Easy’'라는 도구를 개발했습니다.

본 글에서 소개된 이벤트스토밍 모델 이미지들은 실제로 MSA Easy의 AI 기반 모델링 기능을 통해 생성되었습니다. MSA Easy는 마이크로서비스 설계부터 구현, 배포까지 전 과정을 AI의 지능적인 가이드를 받으며 진행할 수 있게 해줍니다. 특히 응집도와 결합도를 고려한 최적의 아키텍처 설계를 돕는 인텔리전트 기능을 제공합니다.

마이크로서비스 아키텍처는 단순히 기술적인 선택을 넘어 비즈니스 가치를 실현하는 전략입니다. 응집도와 결합도라는 두 가지 핵심 개념을 이해하고 적용함으로써 우리는 더욱 유연하고 확장 가능한 시스템을 설계할 수 있습니다. 완벽한 아키텍처는 존재하지 않지만, MSA Easy와 함께 지속적인 개선과 학습을 통해 여러분이 보다 나은 소프트웨어 설계를 할 수 있길 바랍니다.