마이크로서비스 모델링 ① : 애자일 프로세스에서의 마이크로서비스 설계/개발 공정

Updated:

마이크로서비스 모델링 ① :마이크로서비스 구현을 위한 애자일 개발 프로세스

이전 포스팅에서도 언급했다시피 마이크로서비스를 만들기 위한 가장 효율적인 프로세스는 실제로 동작하는 프로덕트 중심반복/점진적 애자일 개발 프로세스이다. 피드백을 통한 지속적인 개선을 추구하는 애자일 프로세스는 가장 효율적인 의사소통구조와 협업체계를 가진 다기능 팀을 추구하고 그 다기능 팀이 만들어내는 결과물이 ‘마이크로서비스’ 라 볼 수 있다.

2000년대 초반의 애자일 문화의 확산과 그 중심 프랙티스(Practices)들(지속적통합,데브옵스등) 그리고 클라우드 인프라, 마이크로서비스 생태계의 발전은 그 흐름를 같이 한다고 볼 수 있다.

그동안 대표적인 애자일 방법론으로 스크럼과 XP등을 많이 사용 해 왔다. 특히 XP의 ‘지속적통합’ 프랙티스는 소프트웨어를 반복 점진적으로 개발 할 수 있게 하는 기본 토양이 된다. 또한 소프트웨어를 개발하는 생명 주기로 스크럼 프로세스가 광범위하게 대중화 되었다. 스크럼은 스크럼 팀이라는 조직구성과 스프린트라는 짧은 반복 주기를 통해 피드백과 개선작업을 촉진하여 단기간에 프로덕트를 생산하고 이를 계속 발전시킬 수 있게 해 준다.

그러나 스크럼이나 XP를 살펴보면 설계하고 개발하는 공정에 대해 자세히 언급하고 있지 않아 여러 오해를 낳고 있다. 즉 개발 문화가 성숙되지 않은 조직들에서는 애자일을 사용하면 설계나 관련 산출물을 아예 작성 하지 않고 바로 개발을 진행할 수 있다고 보는 것이다. 아마도 외국에서는 애자일문화 자체가 어느정도 소프트웨어 개발 문화의 성숙된 배경 1 에서 좋은 프랙티스들을 가속화 시키고 기존 공정의 군더더기나 낭비를 제거하는 방식에서 시작했기 때문이라고 생각된다. 그런 성숙된 개발문화에서는 시시콜콜 설계 방식, 개발 공정을 언급하지 않아도 알아서 자율적,효율적으로 진행되기 때문에 특별히 언급하지 않았던 것 같다.

그러나 안타깝게도 이러한 애자일 문화가 국내에 유입되면서 우리 특유의 빨리빨리 문화와 접목되어 설계가 불필요하고 바로 개발할 수 있는 방식으로 오해되고 있다. 그러나 설계를 하지 않고 개발을 한다는 것은 사실 불가능하다. 아무리 간단한 소프트웨어 개발을 한다고 해도 소스코드를 담을 대략의 프로그램 구조, 모듈, 명명규칙등을 정의하고 그것들 간의 호출 관계를 생각하게 된다. 문서화 하지 않아도 이런 고민, 사고 자체가 설계인 것이다. 다만 애자일에서는 이전의 개발프로세스에서 강조했던 너무 세밀하여 과하고 무거운 설계 산출물의 무용을 인식한것이다. 2

그렇다면 애자일에서의 설계는 어때야 하는가? XP에서는 Simple Design이라는 프랙티스가 있는데 이는 어느정도 개발에 들어갈 수 있는 정도의 가벼운 설계를 말한다. 설계를 단순하고 간단하게 하고 바로 개발로 들어간 뒤에 실제로 동작하는 소프트웨어를 보면서 다시 지속적으로 리팩토링(Refactoring)하는 방식이 더 효율적 이라고 말한다.

애자일에는 빨리 , 자주 실패를 경험해 보는 것이 중요하기 때문에 단순한 설계를 통해 우선 최소한의 실제 동작하는 제품(MVP: Minimum Viable Product)를 만들어 자주 배포하는 것이 중요하다. 또한 이러한 과정을 거치면서 그 개발팀에 맞는 최적의 개발 프로세스를 지속적으로 향상시킬 수 있다. 그렇지만 개발 문화가 성숙하지 않은 팀에 이 정도의 지침만 준다면 2~3주의 스프린트가 기존의 워터폴(Waterfall) 일정을 단기간으로 축소한 고된 행군의 축약 버전이 되거나 계속된 시행착오의 연속으로 중도에 다시 워터폴 방식으로 돌아갈 수 있다. 또한 그 결과물인 마이크로서비스 조차 잘 정리되지 않은 뒤죽박죽 스파게티 코드 3 구조가 될 가능성이 많다.

따라서 이렇게 되지 않기 위한 기민한 반복 주기에 적합한 군더더기를 제거하고 핵심 활동에 집중할 수 있는 마이크로서비스 설계, 개발 방법이 필요하다.

도메인 주도 설계와 마이크로서비스

도메인주도 설계(Domain Driven Design :DDD)는 2001년에 ‘에릭 에반스’가 쓴 책으로 이미 마이크로서비스가 대중화 되기 전에 나온 책으로 객체지향 설계/개발의 유용한 패턴을 정리한 책으로 특별히 마이크로서비스 위한 책은 아니다. 그러나 이후에 마이크서비스 개발에 활성화되며 DDD가 마이크로서비스의 설계,개발을 위한 주요가이드로써 주목되었다. 특히 마이크로서비스의 어플리케이션 개발 측면, 응집성이 있는 도메인 중심의 마이크로서비스를 도출하는 지침 및 마이크로서비스 내부의 비지니스 로직 설계의 주요한 가이드가 되고 있다. 그래서 마이크로서비스 설계의 영역에서 빈번히 언급되고 있으며 주요 오픈소스의 아키텍처 구성요소도(예를 들면 스프링부트등)에서도 DDD의 영향을 받아 내부 라이브러리의 구조 등을 정의하고 있다.

따라서 마이크로서비스를 도출하고 내부구조를 설계하는데 도메인 주도 설계 기법을 활용하는 것이 효과적이다.

기민한 설계/개발

그렇다면 마이크로 서비스를 위한 가장 단순하고, 체계적, 효율적이면서도 애자일 프로세스를 반영한 기민한 개발 프로세스는 어떠해야 하나? 그러한 프로세스를 정의해 보자. 다음은 도메인 주도 설계를 활용한 스크럼 기반의 마이크로서비스 개발 프로세스이다. 마이크로서비스를 개발하기 위한 핵심적인 설계 영역과 활동을 최소화 하였고 각 활동 별 최소한의 핵심 산출물을 정의하였다.

그림 4.1 애자일한 마이크로서비스 설계/개발 절차

기본 생명주기는 스크럼의 스프린트를 활용한다. 스프린트내의 개발 프로세스는 백 엔드와 프론트 엔드로 나누어져 진행되고 CI/CD를 통해 빌드/배포되며 매 스프린트 마다 시연/회고 과정을 거친다.

여기서 특이한 것은 설계/개발을 위한 스프린트를 들어가기 전의 작업들이 존재하는 것이다. 이전 활동은 ‘아키텍처정의’와 ‘마이크로서비스 도출’ 이다. ‘마이크로서비스 도출’은 본격적인 마이크로서비스 개발로 들어가기 위한 스크럼 팀이 개발할 전체 마이크로서비스들을 파악하는 작업이다. 모든 마이크로서비스를 하나의 스크럼팀이 개발할 수 없으므로 DDD의 ‘전략적 설계’ 기법을 활용하여 마이크로서비스를 도출하고 그것들 간의 대략적인 매핑 관계를 정의한 후에 마이크로서비스 개발 우선순위에 근거에 스크럼팀에 배분하여 스프린트를 진행하게 한다. 최종 결과물은 컨텍스트 맵(Context Map) 이다. 컨텍스트 맵은 식별된 마이크로 서비스와 그들간의 의존관계를 보여준다.

또 다른 하나의 스프린트 이전 공정은 ‘아키텍처 정의’ 이다. 이전 장에서 언급한 마이크로서비스 외부,내부 아키텍처를 정의하는 공정이다. 로버트 C, 마틴은 기술 세부사항은 늦게 결정할 수 있어야 한다고 했다. 이는 기존의 워터폴한 개발 프로세스에서 강조했던 아키텍처등의 기술결정사항이 모두 완벽하게 정의된 후 개발을 해야 한다는 말과 배치된다. 이 말을 이해해 보자면 마이크로서비스를 비즈로직 인 내부 영역과 기술 영역인 외부영역으로 구분하여 개발하면 외부 영역은 언제든지 교체될 수 있으므로 어플리케이션의 핵심인 내부 영역에 집중하고 , 외부 영역 즉 아키텍처의 결정사항들은 천천히 결정해도 된다는 말이다. 그 만큼 어플리케이션은 소프트 즉 유연해야 한다는 말로도 읽힐 수 있다.

그러나 이러한 유연성을 항상 유지해야 한다는 점을 명심하되 개발,테스트 환경을 먼저 준비하는 것은 스프린트 진행을 위해 효과적이다. 그래야지 쉽게 개발환경을 정의하고 바로 스프린트에 실제로 돌아가는 마이크로서비스를 테스트 해볼 수 있다. 또한 최근의 클라우드 Paas개발 환경은 개발환경을 어렵지 않게 빠르게 구축할 수 있도록 도와준다. 언제던지 변경 가능하되 기반은 빨리 마련하자.

따라서 스프린트 이전에 예를 들면 외부아키텍처로 도커, 쿠버네티스, 스프링부트 기반의 마이크로서비스 개발환경 정도를 결정해 놓으면 빠르게 개발환경을 구축하고 바로 개발과정으로 진입할 수 있다.

물론 이렇게 정의된 아키텍처는 스프린트 과정을 통해 개선되고, 지속적으로 정제될 것이다. 아키텍처나 어플리케이션 구조가 유연하다 면 언제든지 세부사항은 변경될 수 있기 때문이다. 따라서 이 활동을 통해 초기에 정의되는 결과물은 정의된 아키텍처 외부,내부 아키텍처 및 개발환경이다. 계속 강조하지만 변경성을 염두에 둔 유연한 구조를 초기에 정의해야 한다.

스프린트 내의 공정을 살펴보면 스크럼팀 멤버인 백 엔드 개발자와 프론트 엔드 개발자의 역할 대로 공정이 나누어 진다. 두 영역은 두 영역간의 계약인 ‘API설계’ 를 같이 정의하고 각각의 설계/개발과정을 진행한다. 따라서 초기에 API설계를 해야 한다. API 설계는 각 백 엔드 마이크로서비스가 프론트에 제공할 서비스 명세이다. 다음의 백 엔드 영역의 설계는 정의된 마이크로 서비스 내부 구조에 따라 ‘도메인 모델’ 과 ‘데이터 모델’ 를 설계 하는 활동이다.

도메인 모델을 작성하는 활동을 도메인 모델링이라 하는데 이전의 OOAD(Object Oriented Analysis Design)방식과 틀린 것은 OOAD방식에서는 UML등을 활용하여 설계 모델을 작성하고 이를 소스코드로 변환하는 작업등을 진행 하였으나 DDD를 적용하게 되면 별도의 정형화된 모델을 만들지 않고, 간략히 도메인 모델 등을 화이트보드나 포스트 잇 등의 단순한 도구 등을 통해 작성 공유한 후 바로 소스코드의 도메인 모델로 개발한다.

즉 아래 그림을 보면 예전의 설계 모델의 개념은 MDD(Model Driven Devolopment)의 사례와 같이 추상적인 모델을 완벽히 만들어 놓고 특정 기술프로파일, 프레임웍(Framework)을 적용하여 구체 코드를 생성해서 모델과 코드와의 단절이 되는 구조 4 였다면 , DDD의 모델링은 코드 자체가 모델의 기본 표현 형식으로 활용되고 때때로 개발자는 개발 중에 초기에 설계한 모델의 개념 대로 개발이 되고 있는지 아니면 다른 개발자에게 핵심 도메인 모델을 이해시키기 위해 리버스 (Reverse)도구를 통해 UML 모델로 리버스 하여 공유할 수 있다. 따라서 DDD의 모델은 코드와 함께 항상 같이 숨쉬게 된다..

MDD와 DDD의 모델

프론트 엔드 영역 설계 는 UI 레이아웃을 정의하고 백 엔드의 API를 호출하여 API가 보내준 데이터를 기반으로 UI에 어떻게 표현할 것인가를 정의하는 영역이다.
또한 벡엔드와 프론트 엔드 개발이 진행되는 과정에서 지속적으로 빌드가 되고 자동으로 배포가 되도록 빌드/배포 환경을 자동화 해야 한다. 따라서 스크럼팀의 구성원은 언제라도 실제 진행된 만큼의 실제로 돌아가는 소프트웨어를 확인할 수 있어야 한다.

스프린트 마지막의 활동은 시연과 회고이다. 시연은 초기에 정의한 백로그(Backlog) 가 모두 구현되고 그 요건을 만족되었는지 확인하는 자리이다. 피드백을 받을 수 있고 다음 스프린트에 반영할 요건들을 확인할 수 있다.

회고는 팀원들이 자기 스스로를 돌아보는 과정이다. 마이크로서비스를 설계/개발하는 과정에서 좋았던 방식과 안 좋았던 방식들에 대해 논의하고 그 개선점을 찾아 다음 스프린트에 적용할 수 있다.

이번 포스트 에서는 마이크로서비스 개발을 위한 스크럼 생명주기에서의 심플하고 효율적인 설계/개발 프로세스를 간략히 정의하여 살펴보았다. 다음 포스팅부터 하나하나 상세히 살펴 보도록 하자.

  1. 북미에서 시작된 애자일 문화는 체계적인 소프트웨어 개발이 어느정도 성숙한 상태에서 발생되었다고 보는 것이 맞다. 체계적인 개발 문화가 정착되었으나 그에 따른 경직성 및 낭비를 제거하고 중요한 일에 집중하는 방식이라 볼 수 있다. 

  2. 애자일 이전의 프로세스에서 완벽한 설계를 강조하는 문화가 있었다 그러나 몇달동안 진행된 완벽하다고 판단된 설계가 개발과정에서 발생된 이슈 및 발견된 지식으로 변경되는 일들이 많았다. 따라서 설계는 개발과 동시에 지속적으로 현행하 되던지 개발 후에 리버스 되야 한다. 

  3. 보통 기술과 로직이 복잡하게 얽혀 있는 프로그램을 스파게티 소스코드라 부른다. 

  4. 물론 MDD를 통해 구현된 소스코드도 리버스 하여 UML을 확인 할 수 있다. 그러나 그런 모델은 이미 기술과 결합해 복잡하게 구체화 되어 모델이 가지는 단순함, 추상성등을 상실하여 이해 할 수 없는 수준의 모델이 되고 만다.