본문 바로가기
Concepts/SW Architecture

아키텍처 - 서비스와 아키텍처

by ocwokocw 2021. 2. 10.

- 이 글은 로버트 C.마틴의 Clean Architecture를 기반으로 작성되었습니다. (가능하면 책을 읽어보는것을 추천한다.)

- 개요

서비스 지향 아키텍처(SOA - Service Oriented Architecture)나 마이크로 서비스 아키텍처(MSA - Micro Service Architecture)라는 말을 들어봤을것이다. 단어만 언급해도 뭔가 전문가가 된것 같고, 심지어 단어 자체도 멋있다.

 

흔히 이런 아키텍처들의 장점으로 상호 결합을 완벽하게 분리한다거나, 개발 및 배포 독립성을 보장해준다는 문구를 본적이 있을것이다. 하지만 이 역시 진리의 케이스 바이 케이스이다.


- 서비스 아키텍처

서비스를 분리한다는건 아키텍처측면에서 무엇인가를 하는것일까? 먼저 우리가 여태까지 "아키텍처"를 언급하면서 한일들을 돌이켜보자.

 

우선 의존성을 가지고 화살표 방향을 바꾸기 위해 많은 노력을 기울였다. 방향을 어떻게 바꾸었나?

 

우선 클래스단위에서는 SOLID 원칙을 살펴보았다. 그리고 이런 SOLID 원칙을 더 큰 단위인 컴포넌트에 적용하였다. 의존성 방향을 항상 저수준의 컴포넌트에서 고수준의 컴포넌트로 의존하게 하면서 "경계"간 횡단을 하였다. 이 "경계"가 핵심이다. 아키텍처는 무엇인가를 분리하며 "경계"를 설정하고 "의존성 규칙"을 지켜야 한다.

 

서비스는 프로세스나 플랫폼 경계간의 함수 호출이다. 아키텍처 측면에서는 프로세스나 플랫폼간에 물리적인 경계가 있다고 해서 이런 경계를 모두 의미있는 경계로 설정하지 않는다.


- 서비스의 이점

- 결합 분리: 시스템을 서비스로 분리하면 결합이 분리되긴 한다. 물리적으로 결합을 분리하면 서로 받는 영향도가 줄어들까?

 

같은 시스템내의 다른 서비스 혹은 다른 시스템 혹은 타 회사와 인터페이스를 해본 사람이라면 안다. 처음엔 서로 주고받은 데이터 포맷을 정의하고 이정도면 충분하지라는 생각으로 각자 개발을 진행한다. 논의를 하다보면 각자 추가적인 요구사항이 생기고 필드가 늘어난다. 이로인해 새로운 인터페이스 메소드가 추가되거나 변경된 필드 때문에 영향을 받는다.

 

서비스는 분리되었으니 결합이 분리되었다고 자신있게 말할 수 있을까?

 

- 개발 및 배포 독립성: 서비스를 분리하고 각 서비스마다 전담팀을 만들고 리더는 대외에 공표한다. 우리는 "최신 트렌드에 따라 데브옵스 시스템을 구축하였습니다. 개발, 배포, 유지보수를 서비스마다 독립적으로 수행합니다. 추후 확장까지 가능합니다."

하지만 인생은 실전이다. 결합 분리에서 언급한것처럼 서로 다른 두 서비스가 어떤 데이터나 정책에 의해 둘 다 영향을 받는다면 각자 배포할 수는 없다. 결합된 정도에 따라 개발, 배포를 같이 해야 한다.


- 야옹이 문제

위 다이어그램이 택시 통합 시스템이라고 해보자. Taxi UI 서비스는 서비스 이용자에게 화면을 제공한다. Taxi Finder 서비스는 Supplier(택시업체)들을 검토하여 사용자에게 후보를 제공한다. Taxi Selector 는 사용자가 설정한 조건에 따라 적합한 택시를 선택한다. 선택을 완료하면 Taxi Dispatcher는 Supplier(택시 회사들)에 배차지시를 한다.

 

추후 확장가능성을 고려해 위와 같이 여러 서비스들로 쪼갠 후 전담팀 및 인력을 할당하여 운영한다. 갑자기 마케팅팀이 돈될만한 아이템을 찾았다며 택시업체와 협업하여 고양이를 배달하는 서비스를 제공하겠다고 한다.

 

고양이 배달 서비스가 추가되었다고 가정하고 사용자가 이 서비스를 이용하는 시나리오를 생각해보자. 

  • Taxi UI : 서비스에 접속해서 배달받을 고양이에 관한 시간 및 장소를 고른다. 혹은 고양이 배달 서비스가 아닌 그냥 택시서비스를 이용하는 승객일 수 있다. 또한 어떤 승객은 주의사항에 자신이 고양이 알러지가 있다는 조건을 설정한다.
  • Taxi Finder : Supplier(택시업체)들의 현재 상황을 검토한다. 대부분의 택시회사들은 택시서비스에는 참여했지만 고양이 배달서비스에는 참여하지 않았을 수 있으며, 어떤 택시업체는 특히아게 고양이 배달서비스만 참여했다. 이를 따져서 후보군을 선택한다.
  • Taxi Selector : 적절한 후보택시 중 고객이 설정한 조건에 맞는 택시를 선택한다. 이를 Taxi Dispatcher에 전달하고 Taxi Dispatcher는 Supplier에게 배차지시를 한다.

영향을 받는 부분은 어디일까? 서비스로 쪼개놨으니 어떤 서비스 한나만 변경하면 될까? 보수적으로 생각해도 위에 3곳이 영향을 받고, 최악의 경우엔 Dispatch나 Supplier도 영향을 받는다. 이 요구사항을 릴리즈하려면 독립적으로 개발, 배포, 유지보수를 할 수 없다.

 

이건 횡단 관심사 문제다. 위에서는 서비스를 기능 단위의 단일체로 분류하였다. 그런데 새로운 요구사항 기능이 기존의 기능들의 행위 전체를 횡단하면서 모든 기능에 영향을 미친것이다.


- 컴포넌트 기반 아키텍처

위의 다이어그램을 보자. 기울여쓴 이탤릭체는 추상임을 나타낸다. 기존 배차로직은 Rides 컴포넌트로 추출되고, 신규 기능은 Kittens 컴포넌트로 들어갔다.

 

이 두 컴포넌트는 추상 클래스들(Finder, Supplier, Selector, Dispatcher)을 템플릿 메소드 패턴이나 전략패턴으로 오버라이드 한다. 서비스가 반드시 단일체여야할 이유는 없다. 서비스는 컴포넌트 구조를 갖출 수도 있으며, 기존 컴포넌들을 변경하지 않고 새로운 컴포넌트를 확장할 수 있다.


- 횡단 관심사

항상 서비스 단위가 아키텍처 경계여야 할 이유는 없다. 위에서 설계한 컴포넌트 기반 아키텍처를 Selector 측면에서만 보면 아래와 같은 구조를 갖는다.

 

Selector 서비스 전담팀은 기존의 단일체였던 Taxi Selector 서비스를 컴포넌트 구조로 분리하고, 의존성 규칙을 준수하도록 설계한다. 이렇게 되면 횡단 관심사 처리 과정에서 신규 기능에는 컴포넌트를 추가(확장)하고, 기존 컴포넌트에는 영향을 최소화할 수 있다.


- 결론

서비스 자체는 아키텍처의 단위가 아니다. 아키텍처 측면에서 관심사는 경계사이를 넘나드는 의존성이다. 이 경계를 식별할때에는 물리적인 경계가 기준이 아님을 명심해야 한다.

 

또한 서비스는 반드시 하나의 단일체 컴포넌트여야할 이유는 없다. 때에 따라서는 의존성 규칙을 만족하는 컴포넌트들이 모여 서비스가 된다.

댓글