본문 바로가기

emotional developer/detect-pattern

Why you should never default to Microservices

https://levelup.gitconnected.com/why-you-should-never-default-to-microservices-c952903fbcb6

 

Why you should never default to Microservices

Disclaimer: Grumpy Goose Warning

levelup.gitconnected.com

 

Complexity in Testing

소프트웨어는 99개의 기능이 올바르게 동작하고 1개의 기능이 실패했을 때, 그 99개의 성공에 대해 점수를 얻지 못하기 때문에 어렵습니다. 모든 것이 제대로 작동해야 합니다. 따라서 모든 것을 함께 테스트하거나, 테스트 범위가 넓어져야 합니다.
테스트 범위는 단일 테스트 내에서 얼마나 많은 것을 테스트할 수 있는지를 측정하는 척도입니다.
범위가 작을수록 실제 사용자 경험에서 멀어지게 됩니다. 즉, 테스트가 통과하더라도 기능이 제대로 동작한다는 의미는 덜하고, 테스트가 실패하더라도 기능이 제대로 작동하지 않는다는 의미는 덜하게 됩니다.

모놀리식 구조에서는 큰 범위를 테스트하는 것이 쉽습니다.
왜냐하면 모놀리식 구조는 모든 것을 다루기 때문입니다.

그러나 마이크로서비스에서는 같은 과정이 더 복잡해집니다.
마이크로서비스에서는 테스트 범위가 마이크로서비스의 자연적인 경계에 의해 제한됩니다.

일반적인 마이크로서비스 테스트 설정

이로 인해 우리는 동작을 모의(Mock)하거나 스텁(Stub)해야만 합니다.
이는 주문 서비스나 이행 서비스에서 변경되거나 추가된 동작이 무시된다는 의미입니다.
따라서, 테스트가 통과한다고 해서 기능이 제대로 작동할 가능성은 더 적어지고, 테스트가 실패한다고 해서 기능이 제대로 작동하지 않는다는 의미는 덜하게 됩니다.

이 수준에서 10,000개의 테스트가 통과하더라도, 여전히 아래와 같은 버그들이 발생할 수 있습니다.

  • 비즈니스 로직의 변화로 인해 발생하는 다양한 오류
  • 주문 서비스나 상품 서비스의 데이터나 계약에서 발생하는 문제

이러한 상호작용을 실제로 테스트하지 않고, 대신 이를 모의하고 있기 때문입니다.
처음에는 문제가 되지 않더라도, 프로세스가 복잡해지고 변화함에 따라 문제가 될 것입니다.
그 결과 UAT(사용자 수용 테스트)에서 더 많은 버그를 발견하게 되거나, 모의 객체들을 더 지능적으로 만들어야 할 것입니다. 이는 시간을 낭비하는 좋은 방법이죠.

이 방식은 각 개발자가 코드를 병합하기 전에 수동으로 두 가지를 함께 테스트해야 한다는 지식과 주의에 의존합니다. 제 경험상, 이것은 일관성이 없습니다.
결국, 버그는 자동화된 테스트보다는 수동 테스트를 통해 UAT에서 발견됩니다. 이는 마치 10파운드짜리 버거를 100파운드에 사는 것과 같습니다.
이러한 문제들이 놓쳐서 실제 프로덕션에 배포된다면, 이는 1000파운드를 쓰는 것과 마찬가지입니다.

모놀리식 구조에서는 이와 같은 테스트 스위트를 쉽게 가질 수 있습니다.
모의 객체(Mock), 스텁(Stub), 가짜 데이터(fake), 속임수 없이 모든 것을 테스트할 수 있는 범위를 제공하므로, 테스트가 통과하면 기능이 실제로 작동할 가능성이 더 높아지고, 테스트가 실패하면 기능이 작동하지 않는다는 의미가 더 명확해집니다.

이 방식은 훨씬 간단한 테스트 방법입니다.
이는 그날의 경험, 지식, 완벽함, 혹은 충분한 카페인이 없어도 작동합니다.
모의 객체(Mock)를 최신 상태로 유지하거나 지능적으로 만들 필요도 없습니다.
그리고 정말로 하나의 서비스를 모의하고 싶다면, 매우 간단하게 할 수 있습니다.

 

Complicating your infrastructure

복잡한 웹 시스템 안에서 서로 통신해야 하는 작업에 갇히면, 상황이 매우 빠르게 복잡해집니다.

단계 추가하기

예시: 새로운 엔드포인트 추가.

  • 모놀리식 구조
    1. 엔드포인트 생성
    2. 엔드포인트에 대한 권한 생성
    3. 프론트엔드에 엔드포인트 연결
  • 마이크로서비스 구조
    1. 엔드포인트 생성
    2. 엔드포인트에 대한 사용자 권한 생성
    3. 엔드포인트 인프라 생성
    4. 새로운 마이크로서비스를 위한 파이프라인 생성
    5. n — 모든 마이크로서비스가 이 엔드포인트와 통신할 수 있도록 권한 생성
    6. n — 모든 인프라 코드를 올바르게 업데이트하고, 직접 수정된 것이 없는지 확인
    7. n — 엔드포인트를 연결

이렇게 3단계에서 4 + (3 * n)단계로 바뀌었습니다.

또한 여러 가지 실패 지점을 만들었고, 테스트하기도 매우 어려워졌습니다.

 

Managing split timelines

만약 인프라가 완전히 별도의 인프라 팀에 의해 관리된다면(제가 절대 추천하지 않는 방식), 인도(배포)는 거의 확실하게 어려울 것입니다. 그들이 아무리 잘하더라도 말이죠.

당신이 답해야 하는 질문은 "다음 스프린트 내에 이 작업을 완료할 수 있을까요?"가 아닙니다.
대신에 다음과 같은 질문들을 답해야 합니다.

  • "다음 스프린트 내에 이 작업을 완료할 수 있을까요?"
  • "인프라 팀이 다음 스프린트 내에 이 작업을 끝낼 수 있을까요? 그리고 그들이 우리를 차단하지 않도록 제시간에 준비할 수 있을까요?"

역사적으로 볼 때, 첫 번째 질문에 대한 답은 "네"일지 몰라도, 두 번째 질문에 대한 답은 "아니요"일 가능성이 큽니다.
이는 인프라 팀의 잘못이 아니며, 그냥 현실입니다. 이 상황에서 그 팀을 비즈니스 팀, QA 팀, 배포 팀, 또는 다른 어떤 팀으로 대체해도 마찬가지입니다.
한 개의 타임라인이 아니라 여러 개의 타임라인을 관리하게 되면, 우선순위와 일정이 충돌하게 됩니다.

그래서 프로젝트 매니저가 "이 기간 내에 이 작업을 완료할 수 있나요?"라고 물으면, 대답이 "네/아니요"에서 "모르겠어요, 제 손에 달린 일이 아니에요"로 바뀌게 됩니다.

프로젝트에 얼굴을 내밀고, 손은 제어할 수 없는 상황에 놓이게 되면, 당신도 기분이 나빠질 것입니다.

타임라인을 분리하면 한 팀에서 할 수 있는 것에 따라 단축이나 타협을 유도할 수 있습니다. 이것은 더 나쁜 설계로 이어질 수 있으며, 이는 프로젝트에서 할 수 있는 두 번째로 비용이 많이 드는 일일 수 있습니다.

Are Microservices a terrible idea?

아니요, 그들이 그렇지는 않습니다. 그들에게는 대체할 수 없는 두 가지 장점과 대체 가능한 한 가지가 있습니다.

  1. 독립적인 배포 가능성 (147개의 파이프라인을 즐기세요) — 독립적인 개발 팀을 포함하여, 이런저런 것들.
  2. 독립적인 확장성.
  3. 관심사의 명확한 분리 — 이것은 원칙을 준수하는 강력한 개발 팀으로 대체할 수 있습니다.

하지만 그들은 많은 복잡성을 추가합니다.

만약 당신이 일을 끝내는 종류의 개발자라면 — 그리고 그래야 한다고 생각합니다 — 복잡성을 추가하는 것은 항상 강력한 이유가 필요합니다.

강력한 이유 없이 뛰어드는 것은 논리적인 것이 아닌, 교조주의적 결정에 기울어지기 쉽습니다. 그리고 그것은 아주 나쁜 생각입니다.

 

Conclusion

먼저 모놀리식 구조로 시작하세요. 큰 범위의 테스트를 잘 수행하고, 경계에 집착하세요. 모놀리식 경계를 마이크로서비스처럼 취급하며, API가 아닌 인터페이스를 통해 상호작용하도록 하세요. 경계를 나눌 필요성이 생길 때까지는 나누지 마세요. 배포성, 확장성, 독립적인 팀 작업에 대한 명확한 이유가 있을 때만 나누고, 테스트 수준을 유지할 방법을 구체적으로 문서화하세요. 좋은 이유가 있으면 진행하고, 그렇지 않으면 모놀리식 구조를 유지하세요.

빠르고 간편한 해결책을 찾는 것이 중요합니다.

 

 

 

반응형