27. ‘크고 작은 모든’ 서비스들
서비스 지향 ‘아키텍처’와 마이크로 서비스 ‘아키텍처’는 최근에 큰 인기를 끌고 있다.
- 서비스를 사용하면 상호 결합이 철저하게 분리되는 것처럼 보인다. 이는 일부만 맞는 말이다.
- 서비스를 사용하면 개발과 배포 독립성을 지원하는 것처럼 보인다. 이는 일부만 맞는 말이다.
서비스 아키텍처?
시스템의 아키텍처는 의존성 규칙을 준수하며 고수준의 정책을 저수준의 세부사항으로부터 분리하는 경계에 의해 정의된다.
기능을 프로세스나 플랫폼에 독립적이 되게끔 서비스들을 생성하면 의존성 규칙 준수 여부와 상관없이 큰 도움이 될 때가 많다.
함수들의 구성 형태도 이와 비슷하다.
모노리틱 시스템이나 컴포넌트 기반 시스템에서 아키텍처를 정의하는 요소는 바로 의존성 규칙을 따르며 아키텍처 경계를 넘나드는 함수 호출들이다.
서비스는 프로세스나 플랫폼 경계를 가로지르는 함수 호출에 지나지 않는다.
서비스의 이점?
결합 분리의 오류
- 큰 이점 하나는 서비스 사이의 결합이 확실히 분리된다는 점이다.
- 모든 서비스의 인터페이스는 반드시 잘 정의되어 있어야 한다.
- 서비스는 개별 변수 수준에서는 각각 결합이 분리된다.
- 네트워크 상의 공유 자원 때문에 결합될 가능성이 여전히 존재한다.
- 데이터에 의해 이들 서비스는 강력하게 결합되어버린다.
- 예를 들어 서비스 사이를 오가는 데이터 레코드에 새로운 필드를 추가한다면, 이 필드를 사용해 동작하는 모든 서비스는 반드시 변경되어야 한다.
개발 및 배포 독립성의 오류
- 전담팀이 서비스를 소유하고 운영한다는 점이 이점이다.
- 하지만 대규모 엔터프라이즈 시스템은 서비스 기반 시스템 이외에도 모노리틱 시스템이나 컴포넌트 기반 시스템으로도 구축할 수 있다는 사실은 역사적으로 증명되어 왔음.
- 결합 분리의 오류에 따르면 서비스라고 해서 항상 독립적으로 개발하고, 배포하며, 운영할 수 있는 것은 아니다.
- 데이터나 행위에서 어느 정도 결합되어 있다면 결합된 정도에 맞게 개발, 배포, 운영을 조정해야만 한다.
야옹이 문제
택시 통합 시스템
- 도시에서 운영되는 많은 택시 업체를 알고 있고, 고객은 승차 요청을 할 수 있음.
- 고객은 승차 시간, 비용, 고급 택시 여부, 운전사 경력 등등을 기준으로 택시 선택 가능.
- 이 시스템을 일 년 이상 운영했을 경우, 신규 서비스를 런칭하고 싶다고 하자.
- 야옹이 서비스는 야옹이를 원하는 목적지로 배달한다.
- 고양이 알러지가 있는 운전사가 있을수도 있고, 알러지가 있는 고객이 탑승하기 위해서는 3일정도의 간격이 필요할수도 있음.
- 이런 기능이 추가될 경우 어디를 변경해랴 할까? 전부다.
이 서비스들은 모두 결합되어 있어서 독립적으로 개발하고, 배포하거나, 유지될 수 없다.
⇒ 이게 바로 횡단 관심사가 지닌 문제다.
모든 소프트웨어 시스템은 서비스 지향이든 아니든 이 문제에 직면하게 마련이다.
객체가 구출하다
컴포넌트 기반 아키텍처에서는 이 문제를 어떻게 해결했나?
SOLID 설계 원칙을 잘 들여다보면 다형적으로 확장할 수 있는 클래스 집합을 생성해 새로운 기능을 처리하도록 함을 알 수 있다.
배차에 특화된 로직 Rides 컴포넌트와 야옹이에 대한 신규 기능은 Kittens 컴포넌트에 들어갔을 경우 이 두 컴포넌트는 기존 컴포넌트들에 있는 추상 기반 클래스를 템플릿 메서드나 전략 패턴 등을 이용해서 오버라이드 한다.
컴포넌트 기반 서비스
서비스가 반드시 소규모 단일체여야 할 이유는 없다.
서비스는 SOLID원칙대로 설계할 수 있으며 컴포넌트 구조를 갖출수도 있다.
자바의 경우 새로운 기능 배포는 기존 서비스의 jar파일을 재배포하는 문제가 아니라, 서비스를 로드하는 경로에 단순히 새로운 jar파일을 추가하는 문제가 된다.
횡단 관심사
아키텍처 경계가 서비스 사이에 있지 않다는 사실을 알 수 있었다.
오히려 서비스를 관통하며, 서비스를 컴포넌트 단위로 분할한다.
서비스 내부는 의존성 규칙도 준수하는 컴포넌트 아키텍처로 설계해야 한다.
아키텍처 경계를 정의하는 것은 서비스 내에 위치한 컴포넌트다.
결론
- 서비스는 시스템의 확장성과 개발 가능성 측면에서 유용하지만, 그 자체로는 아키텍처적으로 그리 중요한 요소는 아니다.
- 시스템의 아키텍처는 시스템 내부에 그어진 경계와 경계를 넘나드는 의존성에 의해 정의된다.
- 시스템의 구성 요소가 통신하고 실행되는 물리적인 메커니즘에 의해 아키텍처가 정의되는 것이 아니다.
- 서비스는 단 하나의 아키텍처 경계로 둘러싸인 단일 컴포넌트로 만들 수 있다.
- 혹은 여러 아키텍처 경계로 분리된 다수의 컴포넌트로 구성할 수도 있다.
- 드물게는 클라이언트와 서비스가 강하게 결합되어 아키텍처적으로 아무런 의미가 없을 때도 있다.