Angeliot

마이크로서비스 시대의 클래스 설계원칙

August 24, 2018 | 2 Minute Read

Principle 는 소프트웨어 디자인에서 소프트웨어를 바라보는 뷰와 구현 방법을 제시하는 중요한 개념입니다. Monolithtic 아키텍처에서는 한곳에 수많은 소스코드가 모이기 때문에 클래스 설계원칙이 매우 중요합니다. 마이크로서비스 시대에서도 이 개념은 여전히 적용됩니다. 단위가 클래스에서 마이크로서비스로 변경된것뿐입니다. 단일책임, 인터페이스 분리, 개방폐쇄는 하나의 개념으로 이해하는것이 좋습니다. 서로 밀접하게 연관됐습니다.

단일책임의 원칙: Single Responsibility Principle

객체는 오직 하나의 책임을 가져야 한다.

마이크로서비스는 하나의 대상을 다루게 설계해야합니다. API 콜 방식에서는 지키기 어려운 원칙입니다.

https://baramnemse.github.io/blog/1/

저의 이전 블로그 내용을 보면 가입자에서 쿠폰을 발행하는 시나리오가 나오는데 이벤트 기간이 끝나면 API 콜 방식에서는 계정 서비스를 수정해야합니다. 이벤트 기간이 끝났나도 계정 서비스를 수정해서는 안됩니다. 이벤트는 이벤트 서비스가 담당하고 계정 서비스는 계정에 대한 서비스만 해야합니다. 아마도 계정 서비스는 URI가 /accounts일것이고 이벤트는 /events일것입니다. accounts 서비스의 이름에서 개발자가 “이 서비스는 accounts만 다루겠다”라는것을 알수있게하고 확신을 줘야합니다.

인터페이스 분리의 원칙: Interface Segregation Principle

하나의 일반적인 인터페이스 보다는 구체적인 인터페이스로 나눠야한다.

마이크로서비스는 일반적으로 단일 명사(엔티티)를 다룹니다. 사용자 계정, 상품, 주문 … 이런 명사만으로는 서비스를 구성할 수 없습니다. 이 때문에 관계적인 요소가 마이크로서비스에 포함되거나 별도의 서비스로 분리가됩니다. 예를 들어 주문이라면 주문에 사용자 계정을 필드로 둘수도 있고 Relation이라는 추상적인 서비스를 만들어서 사용자 계정과 주문을 연결할 수도 있습니다. 문제는 Relation이라는 추상적인 서비스를 만들 경우입니다. 서비스 특성상 거의 모든것의 관계를 정의할 수 가 있습니다. URI 2개를 인풋으로 받는다면 마이크로서비스의 모든것에 대해아 사용할 수 있기 때문입니다.

이렇게 추상적인 서비스를 만들어서 사용할 경우 특정 서비스 때문에 수정해야하는 경우가 발생합니다. 단일책임과 개발폐쇄 원칙을 위반하게 됩니다.

개방폐쇄의 원칙: Open Close Principle

객체는 확장에 대해서는 개방적이고 수정에 대해서는 폐쇄적이어야 한다는 원칙이다. 즉, 객체 기능의 확장을 허용하고 스스로의 변경은 피해야 한다.

인터페이스 분리 원칙과 연결되는 원칙입니다. 서비스가 수정되면 서비스를 사용하는 모든 서비스들에 영향을 주기 때문에 서비스를 수정하는것이 아닌 확장형태로 사용합니다. 예를들어 사용자중에 딜러(오픈마켓에서 판매자)가 있다면 accounts 서비스에 딜러 프로퍼티를 추가하는것이 아니라 dealer라는 accounts 서비스를 확장하여 dealer라는 서비스를 제공합니다.

의존성역전의 원칙: Dependency Inversion Principle

추상성이 높고 안정적인 고수준의 클래스는 구체적이고 불안정한 저수준의 클래스에 의존해서는 안된다는 원칙으로서, 일반적으로 객체지향의 인터페이스를 통해서 이 원칙을 준수할 수 있게 된다. (상대적으로 고수준인) 클라이언트는 저수준의 클래스에서 추상화한 인터페이스만을 바라보기 때문에, 이 인터페이스를 구현한 클래스는 클라이언트에 어떤 변경도 없이 얼마든지 나중에 교체될 수 있다. (전략 패턴을 떠올리면 된다)

마이크로서비스에서 의존성의 원칙은 2가지 형태로 사용됩니다.

  1. 스프링 프레임워크와 같은 컨테이너가 콜해주는 전략 패턴
  2. Kafka등을 이용한 이벤트 드리븐

마이크로서비스에서는 서비스간의 의존성이 존재합니다. 계정을 생성하면 쿠폰을 주는 시나리오에서 쿠폰은 계정에 의존적입니다. 마이크로서비스에서 의존관계를 잘 풀수 있는 방법은 이벤트 드리븐입니다. 이벤트 서비스가 계정을 생성하는것을 구독(소비)하고 계정이 생성되면 쿠폰을 생성하면됩니다.

events consume create accounts { create coupon }

리스코브 치환의 원칙: The Liskov Substitution Principle

자식 클래스는 언제나 자신의 부모 클래스를 대체할 수 있다는 원칙이다. 즉 부모 클래스가 들어갈 자리에 자식 클래스를 넣어도 계획대로 잘 작동해야 한다는 것. 상속의 본질인데, 이를 지키지 않으면 부모 클래스 본래의 의미가 변해서 is a 관계가 망가져 다형성을 지킬 수 없게 된다.

이 개념은 단일목적, 인터페이스 분리, 개발폐쇄 원칙 때문에 서비스를 확장해 나가는데 하위 서비스의 개념이 상위 서비스의 개념을 부정 또는 왜곡하게 설계하면 안된다는 개념입니다. 일반사용자 accounts 서비스와 딜러용 dealer 서비스를 분리하더라고 둘다 동일하게 계정 인증(로그인)의 목적을 가지고 있습니다. 따라서 dealer를 accounts로 치환해도 서비스의 개념이 왜곡안됩니다. 하지만 dealer 서비스에 딜러의 상품별 월 매출 현황과 같은 서비스 인터페이스를 추가한다면 dealer를 accounts로 치환했을때 월 매출 현황이라는 인터페이스를 사용할 수 없으므로 치환할 수 없습니다.

참고자료

나무위키 https://namu.wiki/w/%EA%B0%9D%EC%B2%B4%20%EC%A7%80%ED%96%A5%20%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/%EC%9B%90%EC%B9%99

넥스트리 블로그 http://www.nextree.co.kr/p6960/

마이크로서비스 아키텍처에 대해 궁금한점이 있다면 포스트 하단의 링크(페이스북, 이메일)를 통해 문의주세요.