Layered architecture design guide


  1. Introduction

1.1.    Purpose

소프트웨어 설계시 layered 구조에 대한 가이드를 제공하기 위하여

 

1.2.    Motivation

– 논리적 계층이 어플리케이션의 주요 concerns을 분리한다.

  1. 모듈화, 낮은 결합도 – 유지보수 측면에서 유용함
  2. 공통으로 사용되는 코드(BSW layer)를 재사용할 수 있음
  3. 낮은 결합력, concerns의 분리 – 기능을 점진적으로 개발할 수 있고 시스템의 스케일을 높일 수 있으며, 새로운 기술을 적용하기에 유용함

 

1.3.    장점

  • 레이어를 재사용할 수 있다.
  • 종속성을 국지적으로 최소화한다.
  • 교환가능성이 확보된다.

 

1.4.    단점

  • 동작이 변경될 경우 단계별로 재작업을 해야 한다.
  • 효율이 낮다.
  • 불필요한 작업이 수행될 수 있다.
  • 레이어의 적절한 개수나 규모를 결정하는 것이 어렵다.

 

1.5.    Reference and related documents

  • .NET Application Architecture Guide v2, 2009

 

 

  1. Design Steps for a Layered Structure

어플리케이션을 설계하는 것을 시작할 때, 최초의 작업은 추상화의 최고 수준에 집중하여 기능을 계층으로 그룹화하는 것이다. 그 다음으로 개발자는 각각의 계층에 대한 public 인터페이스를 정의해야 하며, 이는 개발자가 설계하는 어플리케이션에 의존적이다. 일단 계층과 인터페이스를 정의했으면 어떻게 어플리케이션을 위의 계층을 이용하여 구성할 것인지를 결정해야 한다. 최종적으로 개발자는 계층간 상호작용하기 위한 통신 프로토콜을 선택한다. 비록 구조와 인터페이스가 시간에 따라 변경될 수는 있겠지만, 이런 단계를 통해 개발자는 프로세스의 시작에서 중요한 것들을 고려할 수 있을 것이다. 일반적으로 설계 단계에서 수행해야 하는 전형적인 순서는 다음과 같다.

  • Step 1 – 계층화 하기 위한 전략을 생각하라.
  • Step 2 – 당신이 필요한 계층을 결정하라.
  • Step 3 – 어떻게 계층과 컴포넌트를 분배할 것인지를 결정하라.
  • Step 4 – 계층을 없애야 할 필요가 있을 때 결정하라.
  • Step 5 – 계층간 상호작용하기 위한 규칙을 결정하라.
  • Step 6 – Cross Cutting concerns를 식별하라.
  • Step 7 – 계층간의 인터페이스를 정의하라
  • Step 8 – 이행 전략을 선택하라

 

2.1.    계층화 하기 위한 전략을 생각하라.

계층은 어플리케이션 컴포넌트의 논리적 구분으로 명백한 역할과 기능으로 표현된 그룹을 표현한다. 계층적 접근방법을 사용하는 것은 어플리케이션의 유지보수성을 증대시키고 성능을 증대시킬 필요가 있을 때 쉽게 확장할 수 있다. 기능을 계층으로 그룹화 하는 데는 여러 가지 방법이 있을 수 있다. 하지만 너무 적거나 너무 많은 계층을 만들면 확장성이 떨어지거나 복잡성이 증대되는 등 좋지 않다. 당신의 어플리케이션에 적절한 계층화의 정도를 결정하는 것이 계층화 전략을 결정하는 중요한 첫 번째 단계이다.

당신은 또한 순수하게 기능의 분리를 구현하기 위해서 계층화를 구현하고자 하는 것인지, 아니면 잠재적으로 물리적인 분리까지 고려하고 있는지를 생각해봐야 한다. 계층적 영역을 넘나드는 것은 논리적 성능상의 오버헤드를 부과하게 된다.  물리적으로 원격상의 컴포넌트에는 특별히 그렇다. 추가적으로, 계층화는 개별 계층의 성능을 인접 계층의 영향을 받지 않고 최적화시킬 수 있다.

논리적 계층화를 하고자 할 때, 어플리케이션 계층과 상호작용하는 것은 동일한 계층에 있어야 하고 동일한 프로세스 내에서 작동해야 한다. 이것은 당신이 컴포넌트 인터페이스를 통한 직접적인 호출과 같은 고성능 통신 매커니즘의 장점을 사용할 수 있도록 한다. 하지만 논리적 계층의 장점을 유지하고 미래를 위해 유연성을 보장하기 위해서 개발자는 계층간의 캡슐화 및 느슨한 결합력을 유지하도록 주의해야 한다.

물리적인 계층으로 분할하기 위한 계층에 대해서, 인접한 계층의 통신은 네트워크에 접속된 상태에서 발생할 것이고 통신 지연 및 계층간의 느슨한 결합력을 유지하도록 하기 위한 적절한 통신 매커니즘을 선택했는지를 확인해야 한다.

당신의 어플리케이션 계층의 어떤 부분을 다른 물리적 계층으로 분리할 것인지를 결정하는 것은 계층화 전략에서 매우 중요하다. 유연성을 유지하기 위해서 항상 계층간의 상호작용은 느슨한 결합력을 유지해야 한다.

계층적인 접근방식을 채택하는 것은 복잡도를 증가시킬 수 있으며 초기 개발시간을 많이 소비할 수 있다. 하지만 올바르게 구현된 제품은 매우 뛰어나게 유지관리, 확장 가능, 유연성을 제공할 수 있다. 당신은 재 사용성과 복잡성 사이의 trade-off를 고려해야 한다.

 

2.2.    당신이 필요한 계층을 결정하라.

새로운 계층을 추가하고자 할 때에는 주의하여야 하며 유지관리, 확장, 유연성을 증가시킬 관련 컴포넌트의 논리적 그룹을 제공할 수 없다면 추가해서는 안된다.

 

2.3.    어떻게 계층과 컴포넌트를 분배할 것인지를 결정하라.

당신은 계층을 분배하고 그것이 필요할 때에만 물리적인 계층으로 분할해야 한다. 분산구조를 구현하기 위한 공통적인 원인은 보안 정책, 물리적 제약, 공유 비즈니스 로직, 확장성 때문이다.

 

2.4.    계층을 없애야 할 필요가 있을 때 결정하라.

어떤 경우, 계층을 없애거나 통합하는 것이 나을 수도 있다. 간단한 어플리케이션인 경우 여러 가지 계층보다는 한 두 개의 계층이 나을 수 있다. 하지만 보편적인 규칙은 관련된 기능들을 계층으로 그룹화하는 것이다.

2.5.    계층간 상호작용하기 위한 규칙을 결정하라.

계층화 전략으로 당신은 어떻게 계층들이 서로 상호작용할 것인지에 대해 규칙을 정해야 한다. 상호작용 규칙을 명세하는 주요한 이유는 의존성을 줄이고 순환적 참조를 제거하기 위함이다. 예를 들어서 두 개의 계층이 각각의 서로 다른 계층에 의존성이 있다면 이것이 순환적 의존성이다. 그 결과로 다음의 접근법들 중 하나에 따라 계층간의 한 방향의 의존성을 허용하는 것이 공통의 규칙이다.

  • 하향식 상호작용(Top-down interaction) 높은 수준의 계층은 낮은 수준의 계층을 사용할 수 있지만, 낮은 수준의 계층은 상위 수준의 계층을 사용할 수 없다. 이 규칙은 계층간의 순환적 의존성을 회피하는데 도움이 된다. 당신은 또한 하위 계층의 변화를 이벤트를 통해 의존성 없이 상위 계층이 감지할 수 있도록 사용할 수 있다.
  • 엄격한 상호작용(Strict interaction) 각각의 계층은 자신의 계층의 바로 아래에 있는 계층과만 상호작용 할 수 있다. 이 규칙은 각각의 계층이 자신의 바로 아래 계층에 대해서만 알고 있다는 것에 대한 엄격한 전제이다. 이 규칙의 장점은 계층간의 상호작용의 변경이 바로 아래 계층에만 전파된다는 점이다. 이 접근법을 사용하면 새로운 기능을 추가할 때, 변경으로 인한 영향을 최소화시킬 수 있다.
  • 느슨한 상호작용(Loose interaction) 높은 수준의 계층은 낮은 수준의 계층을 통과하여 하위 수준의 계층과 직접적으로 상호작용할 수 있다. 이것은 성능을 증대시킬 수는 있지만 의존성을 증대시킬 수 있다. 다른 말로 표현해서, 낮은 수준의 계층에 대한 변경이 여러 상위 계층에게 영향을 끼친다.

2.6.    Cross Cutting concerns를 식별하라.

당신이 계층을 결정한 이후, 당신은 각 계층의 기능을 식별해야 한다. 이 기능은 종종 crosscutting concerns라고 불리며, logging, caching, validation, authentication, and exception management를 포함한다. 어플리케이션에서 각각의 crosscutting concerns를 식별하는 것은 중요하며 가능한 곳에서 이런 concerns를 관리하기 위해 분리된 컴포넌트를 설계한다. 이 접근법은 보다 나은 재사용 성이나 유지관리를 달성하는데 도움이 된다.

crosscutting code와 각각의 계층의 컴포넌트의 코드를 섞는 것을 피하라. 그렇게 함으로써 계층과 계층의 컴포넌트는 logging, caching, authentication과 같은 행동을 수행할 때에만 crosscutting 컴포넌트를 호출한다. 기능이 계층을 가로질러 가용해야 하기 때문에 당신은 crosscutting 컴포넌트를 모든 계층에서 접근 가능하게 해야 한다. – 심지어 분리된 물리적 계층에 위치할 경우에도.

 

2.7.    계층간의 인터페이스를 정의하라

당신이 계층에 대한 인터페이스를 정의하고자 할 때, 주요 목표는 계층간의 느슨한 결합력이 되도록 하는 것이다. 이것이 의미하는 바는 계층은 다른 계층이 의존할 수 있는 내부적인 상세한 것들을 노출시키지 않아야 한다는 것이다. 대신 계층에 대한 인터페이스는 계층 내의 컴포넌트의 상세한 것들을 숨기는 공용 인터페이스를 제공함으로써 의존성을 최소화하도록 설계되어야 한다. 이런 숨김은 추상화(abstraction)이라고 불리며, 추상화를 구현하기 위한 여러 가지 방법이 있다. 다음의 설계 접근법은 계층에 대한 인터페이스를 정의하기 위해 사용되는 방법이다.

  • 추상화 인터페이스(Abstract interface) 이것은 실체 클래스에 대한 타입 정의와 같은 추상화 베이스 클래스나 코드 인터페이스 클래스를 정의함으로 달성될 수 있다. 이 타입은 모든 계층의 소비자가 그 계층과 상호작용하기 위해 사용하는 공통의 인터페이스를 정의한다. 이 접근법은 또한 시험 가능성(testability)를 증대시키는데, 그 이유는 당신은 추상화 인터페이스를 구현한 테스트 객체(때로는 mock 객체라고도 한다)를 사용할 수 있기 때문이다.
  • 공통 설계 타입(Common design type) 많은 설계 패턴은 다른 계층과 인터페이스를 표현하기 위한 실체 객체 타입을 정의한다. 이런 갹채 타입은 계층과 관련된 세부사항들을 숨기는 추상화를 제공한다. 예를 들어서, Table Data Gateway 패턴은 데이터 베이스의 테이블을 표시하고 데이터와 상호작용하는데 필요한 SQL쿼리를 구현하는데 책임이 있다. 그 객체의 소비자는 SQL쿼리에 대해서는 아는 바가 없거나 어떻게 데이터베이스에 접근하고 명령을 수행하는지에 대해 모른다. 많은 설계 패턴은 추상화 인터페이스를 기반으로 하고 있으나 일부는 대신 실체 클래스를 기반으로 한다. 그리고 Table Data Gateway와 같은 대다수의 적절한 패턴들은 이런 관점에서 작성되었다. 당신이 만약 빠르고 쉽게 당신의 계층에 대한 인터페이스에 대해 구현하고자 한다면 공통의 설계 타입을 고려하라, 그렇지 않다면 당신의 계층의 인터페이스에 대해 설계 패턴을 구현하라.
  • 의존성 역전(Dependency inversion) 이것은 추상화 인터페이스가 다른 계층들에게 외부적으로, 또는 독립적으로 정의되는 프로그래밍 스타일이다. 하나의 계층이 다른 계층에 의존적이 되도록 하지 않고 각각의 계층은 공통 인터페이스에 의존한다. 의존성 삽입 패턴은 의존성 역전의 공통 구현이다. 의존성 삽입을 통해 컨테이너는 다른 컴포넌트가 의존할 수 있는 컴포넌트가 어떻게 위치해야 하는지를 명세하는 매핑을 정의하고, 컨테이너는 이런 의존성 컴포넌트를 자동으로 생성하고 삽입하나. 의존성 역전 접근법은 유연성을 제공하고 pluggable설계를 구현하는데 도움을 주는데 그 이유는 의존성이 코드보다는 설정을 통해 compose되기 때문이다. 그것은 또한 testability를 증대시키는데, 그 이유는 설계의 다른 계층에 쉽게 실제 테스트 클래스를 삽입할 수 있기 때문이다.
  • 메시지 기반(Message-based) 다른 계층과 직접적으로 호출방법 또는 이런 객체의 속성에 접근을 통해 상호작용하는 대신, 당신은 인터페이스를 구현하고 계층간 상호작용을 제공하기 위해 메시지 기반의 통신 방법을 사용할 수 있다. 물리적 및 프로세스 영역을 가로지르는 상호작용을 제공하는 Windows Communication Foundation, Web services, and Microsoft Message Queuing과 같은 메시징 솔루션이 있다. 하지만 당신은 상호작용을 위한 데이터 구조를 정의하여 사용되는 공통의 메시지 타입으로 인터페이스를 추상화시킬 수 있다. 메시지 기반 인터페이스의 큰 차이는 계층간의 상호작용이 모든 상호작용의 모든 세부내용을 숨기는 공통 구조를 사용한다는 것이다. 이 구조는 계층간의 통신과 관련된 operations, data schemas, fault contracts, security information, and many other structures들을 정의할 수 있다. Web application을 구현하고 프리젠테이션 계층과 비즈니스 계층간의 인터페이스를 정의하려고 한다면 메시지 기반의 접근법을 고려하라.

 

2.8.    이행 전략을 선택하라.

대부분의 솔루션에서 발견된 어플리케이션 이행전략을 표현하기 위한 여러 공통의 패턴이 있다. 당신의 어플리케이션을 위한 최고의 이행 솔루션을 선택하고자 할 때 공통의 패턴을 식별하는 것이 도움이 된다. 여러 다른 패턴을 이해한다면 시나리오, 요구사항, 보안 제약사항들을 고려하여 적절한 패턴을 선택할 수 있다.

Advertisements

“Layered architecture design guide”에 대한 1개의 생각

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중