아키텍처 패턴은 소프트웨어 시스템을 위한 검증된 구조적 도해(a pictorial, an illustrated)입니다.
아키텍처 패턴(표준 아키텍처)는 패턴보다 덜 정제된 컨셉으로서 사용됩니다.
여러 패턴은 동일한 아키텍처 스타일에 속할 수 있습니다.
패턴은 서브 시스템과 그들의 역할을 사전 정의해 놓은 하나의 Set입니다.
Client-server pattern의 시스템 구조에 의하면 두 개의 서브 시스템이 식별되는데 클라이언트와 서버가 이에 해당합니다.
클라이언트 시스템의 주요 역할은 사용자에게 UI를 보여주는 역할일 수 있으며, 서버의 역할은 여러 질의를 프로세싱하고, 결과를 클라이언트에 제공함에 있을 것이다.
패턴은 시스템들 사이의 관계를 정리하기 위한 규칙과 지침을 설명합니다.
클라이언트와 서버 사이의 관계는 클라이언트가 질문을 하고 이를 서버가 응답한다는 것입니다.
패턴은 한 사람에 의해 구성되지 않고, 많은 개발자들의 경험의 산물로 이러한 명세화는 다른 사람에게 그 경험을 배울 수 있게 도와줍니다.
이는 소프트웨어 개발에서 기존의 잘 검증된 솔루션을 선택하고, 좋은 디자인 사례를 전파할 수 있게 해줍니다.
아키텍처는 본래 건설, 건축 분야에서 가져온 단어로 소프트웨어 분야에서 사용되는 의미와 차이가 있습니다.
그럼 소프트웨어 분야에서 사용되는 "architecture(아키텍처)"는 어떤 의미로 해석할 수 있을까요?
먼저 아키텍처의 사전적 정의는 다음과 같습니다. (from Wikipedia)
Software architecture is the set of structures needed to reason about a software system and the discipline of creating such structures and systems. Each structure comprises software elements, relations among them, and properties of both elements and relations.
아키텍처는 소프트웨어 시스템의 구성, 구조적 엘리먼트와 시스템을 구성할 인터페이스의 선택, 그러한 엘리먼트들간 협업에 지정된 것으로서 작동과 함께, 그러한 엘리먼트를 점진적으로 더 큰 하위 시스템으로의 구성, 이러한 조직을 이끄는 아키텍처 스타일, 이러한 엘리먼트와 인터페이스, 협업, 구성에 대한 중요한 결정 세트이다.
아키텍처를 컴포넌트로 구체화된 시스템의 기본적인 조직이며, 환경에 대한 관계이며, 디자인과 진화를 이끄는 원리라고 정의하고 있습니다. 시스템은 특정 기능이나 기능 세트를 달성하도록 조직된 컴포넌트의 컬렉션으로 이 환경에서 한 개 이상의 미션을 수행하기 위해 존재한다고 설명합니다.
Martin Fowler(마틴 파울러)와 Ralph Johnson(랄프 존슨)은 아키텍처를 아래와 같은 결론을 내립니다.
두 사람이 내린 아키텍처에 대한 정의은 "아키텍처가 무엇이든 간에 어쨌든 중요한 것"이란 거였습니다.
그럼 아키텍처는 왜 중요한 것일까요?
이 질문에 대한 답을 내리려면 경제 개념을 도입해와야 합니다.
"quality(품질)과 cost(비용)"
품질이란 내가 비용을 지불할 수 있는 어떤 것이라는 생각에 근거한 개념으로 우리는 뭔가를 구매할 때마다 품질과 비용의 상관관계를 분석합니다. 하지만 소프트웨어에서의 품질은 의미가 조금 다르게 적용됩니다. 가장 큰 차이점은 품질의 평가자가 외부 사람들(이용자, users, clients)이라는 것입니다.
그럼 이용자들은 어떻게 품질 평가를 할 수 있을까요?
하지만 그들은 눈으로 볼 수 없기 때문에 내부 소프트웨어가 좋은 아키텍처를 갖고 있는지 혹은 좋은 모듈 디자인을 갖고 있는지에 대한 여부를 알 수 없습니다.
따라서 소프트웨어에서의 품질은 이용자들에게 외부적으로 보여지는 품질과 내부적인 품질로 나눌 수 있습니다.
소프트웨어에서의 내부 품질은 어떻게 평가할 수 있을까요?
예를 들어서 완전히 같은 기능을 하는 소프트웨어 두 개 중 높은 품질과 낮은 품질의 제품의 가격 차이가 $100라고 가정해봅시다.
여기서 $100가 더 비싼 소프트웨어를 구매해야 하는 이유는 무엇일까요?
같은 기능을 하는 제품을 더 비싸게 구매해야할 필요가 있을까요?
소프트웨어의 내부 품질은 장기적인 관점에서 중요합니다.
저품질의 소프트웨어는 미래에 새로운 기능을 추가할 때마다 어려움을 겪게 될 것입니다. 기능을 추가할 때마다 이미 존재하는 소스코드들을 변경하는데 시간이 다소 소요되기 때문입니다.
향후 기능을 추가하는 등의 버전 관리를 좀 더 용이하고 빠르게 하기 위해서 개발자는 좋은 아키텍처를 가져가기 위해 관심을 기울이고 소스코드를 리팩터링하면서 더 나은 방향으로 나아가려고 노력해야 합니다.
컴포넌트화가 잘 된 소스코드는 개발 속도를 감소시켜 결과적으로 개발 비용을 절약시켜줄 수 있습니다.
현재 비슷한 기능을 하고 있는 사이트나 에플리케이션이 너무나 많습니다. 이러한 소프트웨어 시장 속에서 빠르게 기능을 개선하고 개발하기 위해서는 반드시 좋은 아키텍처를 기반으로 해야할 것입니다.
소프트웨어 아키텍처란 유연성, 확장성, 실행가능성, 재사용성, 보안성과 같은 소프트웨어의 특성들을 기술적, 사업적 기대에 부응하는 구조화된 해법으로 바꾸는 과정입니다. 좋은 아키텍처는 확장성 있고, 모듈화를 통한 유지보수가 용이하며 실행 가능성이 있어야 합니다.
그렇다면 내가 설계한 아키텍처가 좋은 아키텍처인지는 어떻게 알 수 있을까요?
이때 판단 기준이 되어 주는 것이 바로 아키텍처 패턴입니다.
아키텍처 패턴은 주어진 상황에서의 소프트웨어 아키텍쳐에서 일반적으로 발생하는 문제점들에 대한 일반화되고 재사용 가능한 솔루션으로 소프트웨어 디자인 패턴과 유사하지만 더 큰 범주에 속한다고 볼 수 있습니다.
아래 10가지가 대표적인 소프트웨어 아키텍처 패턴입니다 :
n-티어 아키텍쳐 패턴이라고도 불리는 계층형 아키텍처는 목적이 같은 코드들을 계층으로 그룹화하는 패턴입니다.
각 계층은 바로 아래 계층에서 제공하는 기능과 서비스에만 의존하는 형태로 계층적인 접근은 시스템의 점증적 개발 지원이 가능하다는 장점이 있습니다. 계층이 수정돼도, 인접한 계층만 영향을 받게 되고 인터페이스가 변경되지 않으면, 확장 기능을 가지는 새로운 계층으로 기존의 계층 대체 가능합니다.
이렇게 관심사에 따른 분리를 하게 되면 연쇄적인 참조 관계가 되므로 각 계층은 의존성을 갖게 됩니다. 한 가지를 바꾸려면 다른 부분들도 건들이게 되므로 테스트를 하는데 어려움이 있고 유지보수하기 불편한 패턴입니다.
계층화 패턴이 갖는 의존성 문제를 보완하기 위해 나온 것이 클린 아키텍처 입니다.
아키텍처가 무엇을 보호하고 무엇에 집중해야 하는가에 대한 고민 끝에 나온 아키텍처로 이는 도메인과 업무 정책을 보호하고 집중한다는 특징을 갖고 있습니다.
기본적인 원리는 종속성 규칙(Dependency Rule)을 지키는 것입니다. 각 코드의 종속성은 외부에서 내부로 안쪽으로만 가리킬 수 있고, 고수준 정책(High level policy)이 저수준 정책(Low level policy)의 변경에 영향을 받지 않도록 하는 것입니다. 안쪽에 위치할수록 고수준 정책이며, 바깥쪽에 위치할 수록 저수준 정책을 의미합니다. 단방향의 의존성은 서로에게 주는 영향을 감소시킴으로써 유지보수의 용이성이 향상되어 덕분에 낮은 비용으로 새로운 기능을 추가할 수 있게 됩니다.
클린 아키텍처를 좀 더 구체화한 버전인 헥사고날 아키텍처도 있습니다. 헥사고날 아키텍처는 포트와 어댑터아키텍처라고도 불리며 외부의 변화로부터 저수준의 정책을 보호하기 위한 구조로 외부를 인터페이스가 보호하는 형태를 띄고 있습니다.
도메인 코드가 바깥쪽 코드에 의존하지 않게 함으로써 외부로 부터의 도메인 로직의 결합을 제거하기 때문에 변경할 사항이 적을수록 유지보수성이 높은 코드가 됩니다.
클라이언트 : 서버에 서비스를 요청하는 객체
서버 : 클라이언트에 서비스를 제공하는 객체
C-S 패턴은 다수의 클라이언트와 하나의 서버로 구성됩니다. 서버는 클라이언트에 서비스를 제공하며 데이터를 관리하는 역할을 합니다.
- 이메일, 문서 공유 등 온라인 애플리케이션
- 일반적인 웹 프로그램 등
이 패턴은 마스터 컴포넌트가 동등한 구조의 슬레이브 컴포넌트로 작업을 분산하고, 슬레이브가 결과값을 반환하면 최종 결과값을 계산하는 구조입니다.
- 컴퓨터 시스템에서 버스와 연결된 주변장치
데이터 스트림을 생성하고 처리하는 시스템에서 사용할 수 있습니다.
필터 컴포넌트에서 각 처리과정을 실행하며, 처리된 데이터는 파이프를 통해 전송됩니다.
파이프는 버퍼링 또는 동기화 목적으로도 사용될 수 있습니다.
- Unix의 쉘 방식
- 컴파일러의 어휘 분석, 파싱, 의미 분석
분리된 컴포넌트로 구성된 분산 시스템에서 사용되는 패턴입니다.
각 컴포넌트들은 원격 서비스를 통해 서로 상호작용을 할 수 있으며 브로커 컴포넌트가 컴포넌트 간의 통신을 조절합니다.
서버가 자신의 서비스를 브로커에 넘기고(publish), 클라이언트가 브로커에 서비스를 요청하면 브로커가 자신의 레지스트리에 있는 적합한 서비스로 리디렉션 합니다.
- 메시지 브로커 소프트웨어
피어라 부르는 각 컴포넌트 간에 서비스를 주고 받는 패턴입니다.
피어는 클라이언트로서 각 피어에게 서비스를 요청할 수 있고, 서버로서 각 피어에게 서비스를 제공할 수도 있습니다.
피어 객체 하나가 클라이언트, 서버의 역할을 모두 수행하는 구조입니다.
- 파일 공유 네트워크(P2P)
- 멀티미디어 애플리케이션
이벤트 소스 : 이벤트 버스를 통해 특정 채널로 메시지를 발행(publish)
이벤트 리스너 : 특정 채널에서 메시지를 구독(subscribe)
이벤트 소스(event source), 이벤트 리스너(~ listener), 채널(channel), 이벤트 버스(~ bus) 4가지 컴포넌트를 갖는 패턴입니다.
리스너가 구독한 채널에 소스가 서비스를 제공하면 채널이 리스너에게 서비스를 제공해 주는 구조입니다.
- 안드로이드 개발
- 알림 서비스
모델 : 도메인의 기능과 자료를 저장, 보관
뷰 : 사용자에게 결과를 표시(하나 이상 정의 가능)
컨트롤러 : 사용자로부터 입력과 상호작용을 처리
3개의 각 컴포넌트는 각자의 역할을 갖고 사용자에게 서비스를 제공합니다.
기능마다 컴포넌트를 나눈 이유는 사용자 인터페이스(뷰)가 모델과 컨트롤러 보다 더욱 자주 변경되기 때문입니다.
또한 자료의 저장, 제어 기능과 표현 기능을 분리하여 재사용을 증진시키기 위함입니다.
블랙보드 : 중앙 데이터 저장소
지식 소스(knowledge source) : 특수한 문제를 해결하는 독립 서브시스템
제어 컴포넌트(control component) : 변경을 모니터링하고, 다음 동작을 결정
명확히 정의된 해결 전략이 알려지지 않은 문제에 대해서 유용한 패턴입니다.
부분적인 해법, 대략적인 해법을 수립하기 위한 서브시스템의 지식을 조합하는 방법입니다.
모든 컴포넌트는 블랙보드에 접근하여 새로운 데이터 객체를 생성할 수 있습니다.
공유 데이터 구조 위에서 종합적으로 동작하는 독립적인 프로그램을 모은 방법입니다.
각 프로그램은 전체 중 특정한 부분을 해결하기 위해 특수화 되어있습니다.
제어 컴포넌트는 현재 처리 과정을 평과하여 특수화 된 프로그램을 조율합니다.
특정 언어로 작성된 프로그램을 해석하는 컴포넌트를 설계할 때 사용되는 패턴입니다.
Layer 패턴
Broker 패턴
MVC 패턴
State-Logic-Display(3-tier) 패턴
Sense-Compute-Control 패턴
reference