변화에 적응하기 - AWS 규범적 지침

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

변화에 적응하기

소프트웨어 시스템은 복잡해지는 경향이 있습니다. 그 이유 중 하나는 비즈니스 요구 사항이 자주 변경되고 그에 따라 소프트웨어 아키텍처를 조정할 시간이 부족하기 때문일 수 있습니다. 또 다른 이유는 프로젝트 초기에 잦은 변화에 적응하기 위해 소프트웨어 아키텍처를 설정하기 위한 투자가 충분하지 않기 때문일 수 있습니다. 이유가 무엇이든 소프트웨어 시스템은 변경이 거의 불가능할 정도로 복잡해질 수 있습니다. 따라서 프로젝트 초기부터 유지 관리 가능한 소프트웨어 아키텍처를 구축하는 것이 중요합니다. 좋은 소프트웨어 아키텍처는 변화에 쉽게 적응할 수 있습니다.

이 섹션에서는 비기능적 요구 사항이나 비즈니스 요구 사항에 쉽게 적응하는 육각형 아키텍처를 사용하여 유지 관리 가능한 애플리케이션을 설계하는 방법을 설명합니다.

포트 및 어댑터를 사용하여 새로운 비작동 요구 사항에 적응

애플리케이션의 핵심인 도메인 모델은 비즈니스 요구 사항을 충족하기 위해 외부에서 필요한 조치를 정의합니다. 이러한 작업은 포트라고 하는 추상화를 통해 정의됩니다. 이러한 포트는 별도의 어댑터로 구현됩니다. 각 어댑터는 다른 시스템과의 상호 작용을 담당합니다. 예를 들어 데이터베이스 리포지토리용 어댑터 하나와 타사 API와 상호 작용하기 위한 다른 어댑터가 있을 수 있습니다. 도메인은 어댑터 구현을 인식하지 못하므로 한 어댑터를 다른 어댑터로 쉽게 교체할 수 있습니다. 예를 들어 애플리케이션이 SQL 데이터베이스에서 NoSQL 데이터베이스로 전환할 수 있습니다. 이 경우 도메인 모델에서 정의한 포트를 구현하려면 새 어댑터를 개발해야 합니다. 도메인은 데이터베이스 리포지토리에 대한 종속성이 없으며 추상화를 사용하여 상호 작용하므로 도메인 모델에서 아무 것도 변경할 필요가 없습니다. 따라서 육각형 아키텍처는 비기능적 요구 사항에 쉽게 적응할 수 있습니다.

명령 및 명령 처리기를 사용하여 새로운 비즈니스 요구 사항에 적응

기존 계층형 아키텍처에서 도메인은 지속성 계층에 따라 달라집니다. 도메인을 변경하려면 지속성 계층도 변경해야 합니다. 이에 비해 육각형 아키텍처에서는 도메인이 소프트웨어의 다른 모듈에 의존하지 않습니다. 도메인은 애플리케이션의 핵심이며 다른 모든 모듈 (포트 및 어댑터) 은 도메인 모델에 따라 다릅니다. 도메인은 종속성 반전 원칙을 사용하여 포트를 통해 외부 세계와 통신합니다. 종속성 반전의 이점은 코드의 다른 부분이 손상되는 것을 두려워하지 않고 도메인 모델을 자유롭게 변경할 수 있다는 것입니다. 도메인 모델은 해결하려는 비즈니스 문제를 반영하므로 변화하는 비즈니스 요구 사항에 맞게 도메인 모델을 업데이트하는 것은 문제가 되지 않습니다.

소프트웨어를 개발할 때, 관심사 분리는 따라야 할 중요한 원칙입니다. 이렇게 구분하려면 약간 수정된 명령 패턴을 사용할 수 있습니다. 이는 작업을 완료하는 데 필요한 모든 정보가 명령 개체에 캡슐화되는 동작 설계 패턴입니다. 그런 다음 명령 핸들러에서 이러한 작업을 처리합니다. 명령 처리기는 명령을 수신하고 도메인 상태를 변경한 다음 호출자에게 응답을 반환하는 메서드입니다. 동기식 API 또는 비동기 큐와 같은 다양한 클라이언트를 사용하여 명령을 실행할 수 있습니다. 도메인의 모든 작업에 명령과 명령 처리기를 사용하는 것이 좋습니다. 이 접근 방식을 따르면 기존 비즈니스 로직을 변경하지 않고도 새 명령과 명령 처리기를 도입하여 새 기능을 추가할 수 있습니다. 따라서 명령 패턴을 사용하면 새로운 비즈니스 요구 사항에 쉽게 적응할 수 있습니다.

서비스 파사드 또는 CQRS 패턴을 사용한 부품 분리

육각형 아키텍처에서 기본 어댑터는 클라이언트에서 들어오는 읽기 및 쓰기 요청을 도메인에 느슨하게 연결하는 역할을 합니다. 이러한 느슨한 결합을 달성하는 방법에는 서비스 파사드 패턴을 사용하거나 CQRS (명령 쿼리 책임 분리) 패턴을 사용하는 방법이 있습니다.

서비스 파사드 패턴은 프리젠테이션 계층 또는 마이크로서비스와 같은 클라이언트에 서비스를 제공하는 전면 인터페이스를 제공합니다. 서비스 파사드는 고객에게 여러 가지 읽기 및 쓰기 작업을 제공합니다. 들어오는 요청을 도메인으로 전송하고 도메인에서 받은 응답을 클라이언트에 매핑하는 역할을 합니다. 여러 작업을 한 번에 담당하는 마이크로서비스의 경우 서비스 파사드를 쉽게 사용할 수 있습니다. 그러나 서비스 파사드를 사용할 때는 단일 책임과 개방적 원칙을 따르기가 더 어렵습니다. 단일 책임 원칙은 각 모듈이 소프트웨어의 단일 기능에 대해서만 책임을 져야 한다는 것입니다. 개방-닫힘 원칙은 코드를 확장하려면 열고 수정하려면 닫아야 한다는 것입니다. 서비스 파사드가 확장됨에 따라 모든 작업이 하나의 인터페이스에 수집되고 더 많은 종속성이 여기에 캡슐화되며 더 많은 개발자가 동일한 파사드를 수정하기 시작합니다. 따라서 개발 중에 서비스가 많이 확장되지 않을 것이 분명한 경우에만 서비스 파사드를 사용하는 것이 좋습니다.

육각형 아키텍처에서 기본 어댑터를 구현하는 또 다른 방법은 쿼리와 명령을 사용하여 읽기와 쓰기 작업을 구분하는 CQRS 패턴을 사용하는 것입니다. 앞에서 설명한 것처럼 명령은 도메인 상태를 변경하는 데 필요한 모든 정보를 포함하는 개체입니다. 명령은 명령 핸들러 메서드로 수행됩니다. 반면 쿼리는 시스템 상태를 변경하지 않습니다. 유일한 목적은 데이터를 클라이언트에 반환하는 것입니다. CQRS 패턴에서는 명령과 쿼리가 별도의 모듈로 구현됩니다. 이는 이벤트 기반 아키텍처를 따르는 프로젝트에 특히 유용합니다. 명령은 비동기적으로 처리되는 이벤트로 구현될 수 있는 반면 쿼리는 API를 사용하여 동기적으로 실행될 수 있기 때문입니다. 쿼리는 해당 쿼리에 최적화된 다른 데이터베이스를 사용할 수도 있습니다. CQRS 패턴의 단점은 서비스 파사드보다 구현하는 데 더 많은 시간이 걸린다는 것입니다. 장기적으로 확장하고 유지하려는 프로젝트에는 CQRS 패턴을 사용하는 것이 좋습니다. 명령과 쿼리는 단일 책임 원칙을 적용하고 특히 대규모 프로젝트에서 느슨하게 연결된 소프트웨어를 개발하기 위한 효과적인 메커니즘을 제공합니다.

CQRS는 장기적으로 큰 이점을 제공하지만 초기 투자가 필요합니다. 이러한 이유로 CQRS 패턴을 사용하기로 결정하기 전에 프로젝트를 신중하게 평가하는 것이 좋습니다. 그러나 읽기/쓰기 작업을 구분하지 않고 처음부터 명령과 명령 처리기를 사용하여 애플리케이션을 구조화할 수 있습니다. 이렇게 하면 나중에 해당 접근 방식을 채택하기로 결정한 경우 CQRS에 맞게 프로젝트를 쉽게 리팩터링할 수 있습니다.

조직 단위

육각형 아키텍처, 도메인 기반 설계 및 (선택 사항) CQRS의 조합을 통해 조직은 제품을 신속하게 확장할 수 있습니다. Conway's Law에 따르면 소프트웨어 아키텍처는 기업의 커뮤니케이션 구조를 반영하여 진화하는 경향이 있습니다. 대규모 조직은 종종 데이터베이스, 엔터프라이즈 서비스 버스 등과 같은 기술 전문 지식을 기반으로 팀을 구성하기 때문에 이러한 관찰은 역사적으로 부정적인 의미를 지니고 있습니다. 이 접근 방식의 문제점은 제품 및 기능 개발에는 항상 보안 및 확장성과 같은 교차 문제가 수반되므로 팀 간의 지속적인 커뮤니케이션이 필요하다는 것입니다. 기술적 특징에 따라 팀을 구성하면 조직에 불필요한 사일로가 생겨 커뮤니케이션이 원활하지 않고 소유권이 부족해지며 전체적인 상황을 파악할 수 없게 됩니다. 결국 이러한 조직적 문제는 소프트웨어 아키텍처에 반영됩니다.

반면 Inverse Conway Maneuver는 소프트웨어 아키텍처를 홍보하는 영역을 기반으로 조직 구조를 정의합니다. 예를 들어, 부서 간 팀은 DDD 및 이벤트 스토밍을 사용하여 식별되는 제한된 특정 컨텍스트 세트를 담당합니다. 이러한 제한된 컨텍스트는 제품의 매우 구체적인 기능을 반영할 수 있습니다. 예를 들어 계정 팀이 결제 컨텍스트를 담당할 수 있습니다. 각각의 새로운 기능은 매우 일관되고 느슨하게 연결된 책임을 맡은 새로운 팀에 배정되므로 해당 기능 제공에만 집중하고 출시 시간을 단축할 수 있습니다. 기능의 복잡성에 따라 팀을 확장할 수 있으므로 복잡한 기능을 더 많은 엔지니어에게 할당할 수 있습니다.