본문 바로가기
개발 관련/설계

소프트웨어 아키텍처 10가지 정리

by lazysnack 2022. 7. 14.

요새 사내에서 서비스 분리를 하고 있습니다. 이 상황이 요즘 흔히들 말하는 MSA 라고 볼 수 있는 건지, 아니면 그 다른 어떤건지 확실치 않아서 MSA 에 대해서 알아보고 있는데요. 그러다가 아키텍처 패턴에 대한 내용이 나와서 궁금하기도 하고 정리를 해보려고 합니다.

CAZTON 이라는 사이트의 내용을 번역하여 정리한 것입니다.

1. Client-Servcer Architecture

Client-Servcer Architecture 는 서버에서 실행되는 일부 서비스가 클라이언트에 의해 엑세스가 되는 two-tier 아키텍처 라고도 합니다. Client-Servcer Architecture 에 대해 더 알아보기 전에 Tier 와 Layer 의 차이에 대해 이해하는 것이 중요합니다. Layer 는 논리적 표현과 소프트웨어 코드의 구성을 표현하는 것입니다. UI 레이어, 비즈니스 레이어, 데이터 엑세스 레이어 등을 생각하면 될 것입니다. Tier 는 이런 레이어들의 물리적인 배포를 나타냅니다. 다른 말로 하자면 서로 다른 장소에 배포되어 있는 Two-Tier, Three-Tier, n-Tier 아키텍처를 생각하면 됩니다.

Client-Servcer Architecture 에서 프레젠테이션 레이어 혹은 인터페이스는 클라이언트에서 실행되고, 데이터 레이어 혹은 데이터 서비스는 서버에서 실행되므로, 클라이언트와 서버 둘 간의 직접적인 통신이 이뤄집니다. 서로 다른 장소에서의 이런 구성 요소의 분리를 Two-Tier 아키텍처라고 합니다.

이러한 아키텍처는 작고 모놀리스한 소프트웨어에는 좋을지도 모르겠으나, 접근 방식에 몇 가지 단점이 있기에 Three-Tier, n-Tier, peer-to-peer 같은 아키텍처가 발달하는 결과를 불러왔습니다.

2. Object-Oriented Architecture

Object-Oriented Architecture (객체 지향 아키텍처) 는 소프트웨어 개발에 가장 중요하고 일반적으로 사용되는 아키텍처 중에 하나 입니다. 전체 어플리케이션은 책임이 분리되어 있으며, 시스템은 객체의 모음(collection) 으로 알려져 있습니다. 이 아키텍처는 갭슐화(Encapsulation), 상속(Inheritance), 다형성(Polymorphism), 조합(Composition), 연관(Association), 객체(Object), 클래스(Class) 등 객체 지향 컨셉을 가능케 합니다.

객체 지향 스타일은 함수적(functional) 과 절차지향적(procedural) 과는 완전히 다릅니다.

객체 지향이 엄격하게 적용된 소프트웨어는 매우 견고하고, 확장이 가능하며 재사용성, 유지보수가 용이합니다. 또한 개발시간과 비용을 줄여줍니다.

3. Domain-driven Architecture

도메인이라는 의미는 일반적으로 특정 지식의 활동 영역입니다.

이를 소프트웨어 개발과 연관시켜보면 DDD(Domain Driven Design) 는 개발을 위한 주제 영역에 초점을 둔다는 것을 알 수 있습니다. 그리고 엔터프라이즈 어플리케이션을 구축하는데에 DDD로 알려진 Domain-driven Architecture 는 널리 받아들여 지고 있습니다.

Domain-driven Architecture 는 매우 유명한 객체 지향의 분석과 디자인의 원칙을 기반으로 합니다. 그리고 비즈니스 문제 해결을 기획하는데에 초점을 둡니다. 이러한 생각은 우리가 기술보다는 도메일 모델을 중점으로 두고, 더 나은 소프트웨어를 만들 수 있게 합니다.

이러한 컨셉은 Entity, Value Object, Domain Modeling, Ubiquitous Language, Bounded context, Anti-corruption Layer 를 말하며, 이런 컨셉들은 개발자들이 요구사항 중심의 소프트웨어와 솔루션에 더 집중할 수 있도록 도와줍니다. 또한 순수한 모델 주위에 클린한 경계를 설정하여 엔터프라이즈 아키텍쳐의 요소를 잘 구성할 수 있도록 해줍니다.

4. Onion Architecture

데이터 베이스 중점의 전통적인 아키텍처는 관심사의 분리와 Tight Coupling 이라는 근본적인 이슈를 제기합니다. 또한 모든 레이어 (UI, 비즈니스, 데이터 엑세스) 는 데이터의 흐름을 위해 서로 의존하므로 강력하게 Coupled 되어 있고, 어플리케이션이 커질 수록 이런 이슈 또한 꺼집니다.

Onion Architecture 는 이런 Coupling 을 제어합니다.

Onion Architecture 의 주요 컨셉은 도메인 엔티티를 코어 레이어에 남기는 것입니다. 코어 바깥쪽에는 코어 도메인 엔티티를 사용하는 레포지터리(Repository) 인터페이스를 둡니다. 레포지터리 레이어는 오직 (해당 레이어보다) 바깥 레이어에서 사용되는 인터페이스만을 정의합니다. 그리고 이 인터페이스의 구현 코드는 인프라스트럭쳐(Infrastructure) 라고 하는 가장 바깥쪽의 레이어에 있습니다. 가장 바깥쪽의 레이어에는 인프라스트럭쳐 이외에 UI, 테스트 등이 있을 수 있습니다.

이를 간단히 말하면 내부 레이어는 외부 레이어에 (의존하여서도 안되지만) 의존할 수 없고, 외부 레이어는 그 아래 레이에 의존할 수 있다는 말이 됩니다. 이 방법은 데이터 베이스가 어떤 기술을 기반으로 하는지, 어떤 ORM 을 사용하는지 코어 레이어에서는 알 필요가 없습니다.

결과적으로 관심사의 분리를 통해 유지 가능하면서 테스트가 가능한 코드를 작성할 수 있습니다.

5. Apect-Oriented Architecture

Apect-Oriented Architecture 는 다른 아키텍처가 제공하지 못한 모듈성 이슈를 해결하는데 중점을 두어 많은 관심을 끌었습니다. 기존에 존재하는 디자인 아키텍처를 완전히 대체하는 것이 아닌 강화하는 방향입니다.

개발자는 일반적으로 코드를 유지 관리하고 재사용할 수 있는 모듈형 소프트웨어를 만드는 데 집중하고, Aspect Oriented Software Design(AOSD) 또한 그에 중점을 둡니다. 즉 모든 엔터프레이즈 레벨의 소프트웨어에는 logging, persistence, security, data transfer 등의 횡단 관심사가 존재하는데, AOSD 는 비즈니스 로직에서 저런 횡단 관심사를 분리하는데 도음울 줍니다.

이는 소프트웨어 로직을 별개의 부분으로 나눔으로써 코드를 모듈화하고 크기를 줄이는데 도움을 주고, 결과적으로 소프트웨어 디자인, 개발, 유지 보수 비용의 감소에 도움을 줍니다.

6. Service-Oriented Architecture

Service-Oriented Architecture(SOA) 는 기본적으로 각자 통신하는 서비스의 모음이라고 할 수 있습니다. 이런 서비스들은 기본적으로 모듈로 되어 있으며, 특별한 목적을 위해 플러그 앤 플레이 환경을 제공합니다.

이런 서비스들은 재사용이 가능하므로, 개발자들은 같은 서비스를 다시 만들 필요가 없습니다.

또한, 이들은 느슨한 결합과 관련이 있기 때문에 인터페이스를 통해 다른 소프트웨어에서 사용될 수 있습니다. 즉 전송된 모든 요청에 대해 공통의 프로토콜을 따르는 응답이 있어 광범위한 소비자(consumer) 가 사용할 수 있습니다.

SOA 는 웹서비스로도 API로도 구현될 수 있으며 원격에서 배포, 접근할 수 있습니다. 이러한 장점은 빠른 시장 출시의 이점과 비즈니스의 민첩성을 제공할 수 있습니다.

7. Microservices Architecture

수년에 걸쳐 우리는 다른 레이어들이 하나의 어플리케이션에 함께 합쳐진 소프트웨어를 만들어왔습니다. 서로 다른 팀이 서로 다른 계층에서 작업을 하고 함께 빌드하는 것은 개발, 테스트, 배포를 쉽게 하였습니다. 이러한 작업(Practice) 을 우리는 모놀리틱 아키텍쳐라고 합니다. 하지만 이 아키텍쳐의 단점은 애플리케이션이 성장함에 따라 코드베이스가 개발자를 위협하고, 새로운 맴버가 팀에 들어왔을 때 구조를 빠르게 이해하기 어렵게 만듭니다. 또한 (타이트한 커플링으로 묶인) 거대한 어플리케이션은 배포 및 확장이 어려우며, 새로운 기술을 적용하는 것 또한 큰 도전이 됩니다.

이러한 한계를 해결하기 위해 등장한 것이 Microservices Architecture 입니다.

Microservices Architecture 는 Service-Oriented Architecture 의 발전된 단계 이지만, 구현 측면에서는 다릅니다. 마이크로 서비스는 캡슐화된 단일 비즈니스 능력이 있는 collection of small, self-contained, autonomous services 로 구성되어 있습니다. 이러한 서비스는 매우 작고 독립적이며 별도의 코드 기반이어서 자체 배포가 가능합니다. 또한 다른 서비스와 분리하기 위해 각 서비스마다 자신의 데이터 베이스가 있을 수 있습니다.

이러한 특징에 따라 개발자는 전체 서비스가 아닌 단일 서비스에 집중할 수 있으며, 새로운 기술로의 확장, 개발, 테스트, 배포가 매우 쉬워집니다.

현재 마이크로 서비스는 널리 채택되어 있으며, 매우 유망한 것으로 보입니다.

8. Lambda Architecture

빅데이터의 세계에서는 다른 데이터 소스에서 데이터를 수집하려는 시나리오가 있습니다. 하지만, 어떤 소스는 데이터를 일괄적으로(batch) 제공하는 반면, 어떤 소스는 스트림처럼 리얼 타임으로 데이터를 제공하기도 합니다. 이러한 시나리오에서 Lambda Architecture 는 두 방면의 데이터를 수집하는데 두각을 나타냅니다.

익히 아시듯 Lambda Architecture 의 Lambda 는 수학적 기호인 Lambda 에서 비롯되어 있습니다.

이 아키텍처는 빅데이터 업계에서 매우 유명해졌으며 Spark, Hadoop 과 같은 빅데이터 기술과 함께 사용되었습니다. 하지만, 이 두 기술에만 국한되어 있는 것이 아니며, 모든 기술에 적용될 수 있는 일반적인 아키텍처 이기도 합니다.

9. Component-based Architecture

소프트웨어 어플리케이션은 여러 구성 요소로 나눌 수 있으며, 각 구성 요소는 특정 비즈니스 기능을 캡슐화하여 모듈식으로 제공되는 재사용이 가능한 휴대용 장치로 볼 수 있습니다.

Component-based Architecture 의 주요 목표는 컴포넌트 재사용성을 확실하게 하는 것입니다. 그렇기에 이 아키텍처의 주요 특징은 재사용성, 확장성, 독립성, 캡슐화 입니다.

인터페이스가 노출되어 있기에 각 구성요소가 서로 통신할 수 있으며, 개발자에게 더 많은 제어 기능과 광범위한 사용자 정의(커스터 마이징 가능한) 옵션을 제공합니다.

10. Event-driven Architecture

이름에서 유추할 수 있듯, 서로 다른 소프트웨어 컴포넌트 간의 소비되고(consumed) 생상되는(produced) 이벤트를 다룹니다.

Component-based Architecture 는 일반적으로 3명 이상의 분리된 플레이어가 존재합니다. (producer, pipeline, consumer)

생산자(producer) 는 이벤트를 발생(emit) 하지만 발생한 후의 이벤트에 대해서는 전혀 알지 못합니다. 그리고 생산자의 입장에서는 다른 소프트웨어 구성 요소가 이벤트를 처리하거나 사용하는 방법을 알 필요 없고, 중요하지도 않습니다.

파이프라인(pipeline) 은 다양한 생산자의 모든 이벤트가 처리를 위해 대기하는 곳이며, 이벤트가 처리되면 소비자(consumer)에게 전달됩니다.

Component-based Architecture는 발행-구독 모델 (publisher-subscriber model) 을 가능하게 합니다. 그렇기에 message-driven architecture 혹은 stream-processing architecture 라고도 합니다.

이 아키텍처를 사용하면 생산자와 소비자를 완전히 분리할 수 있으며, 더 많은 생산자와 소비자를 연결할 수 있습니다. 결과적으로 확장성이 뛰어나고 분산된 어플리케이션을 만들 수 있습니다.