리파지터리 패턴은 그 복합성 때문에 완벽히 이해하고 적용할 수 있기까지 매우 어려운 패턴이라 생각됩니다. 여러번에 걸쳐 이 주제를 포스팅 하는 이유가 바로 그 때문입니다. 여러 문서를 학습하거나 구현에 적용할 때에는 관련된 해결해야 하는 문제들이 등장하게 되죠. 패턴이 잘못 사용되지 않도록 하기위해서는 그 패턴이 가지는 정확한 목적을 이해하는 것이 가장 우선시 되는 것이죠.

리파지터리 패턴은 그 역할과 구현이 명확한 개발언어로 스펙으로 정의 된것이 아닌, 일반언어(plain text)로 정의 되어 있음은 많은 개발자들이 정확한 의미를 파악하기 어려울 수 있습니다. MSDN 에 리파지터리 패턴에 잘 정의된 문서가 있어 [문맥] 과 [목표] 문단을 중심으로 번역 포스트 합니다.

이 문서는 리파지터리 구현시에 발생하는 [데이터 조회 로직]가 리파지터리에 들어가려는 현상이 있는데 이렇게 하는 것이 맞느냐 틀리느냐에 대한 근거 수집 차원에서 접근 했으며, 리파지터리의 세부 성격으로 보았을때 조회 로직 자체도 리파지터리로 부터 분리하는 것이 옳다라는 결론을 얻게 되었습니다.  이 결론이 틀리다 생각되시면 의견을 주시어 생각을 바로 잡을 수 있도록 도와 주시기 바랍니다.

Repository는 저장소 라는 용어로 데이터소스에 대한 관리(CRUD)를 어떻게 추상화 하느냐에 대한 패턴입니다.





문맥:

많은 어플리케이션에서 비즈니스 로직은 데이터베이스, 쉐어포인트, 웹서비스와 같은 데이터저장소의 데이터에 접근합니다. 직접접근은 다음과 같은 부작용을 초래할 수 있습니다.

중복된 코드
프로그래밍 에러가 발생할 높은 잠재성
비즈니스 데이터에 대한 오타
캐싱과 같은 데이터-관계 정책 중심화하기 어려움
외부 의존으로 부터 비즈니스 로직을 분리하기 어려움에 따른 테스트 불가능성


목표:

리파지터리 패턴을 사용하는 것은 다음의 목표를 하나 이상 달성합니다.

당신의 수 많은 코드를 테스트 자동화를 극대화하고, 유닛 테스트를 지원하기 위해 데이터 레이어로 부터 분리 시키기를 원한다.
당신은 여러 곳에서 데이터소스에 접근 하고 있으며, 중앙에서 관리되는 일관성 있는 접근 룰과 로직을 적용기를 원한다.
데이터 소스를 위한  캐싱 caching 전략을 중앙화 centralize 하기를 원한다.
데이터 또는 서비스 엑세스 로직으로 부터 비즈니스 로직을 분리함으로써 코드의 유지관리성 maintainability과 가독성 readability  을 향상 시키기를 원한다.
문제를 런타임이 아닌 컴파일 타임에 구분해 낼 수 있도록 비즈니스 엔터티를 강-타입 strongly typed 으로 사용하기를 원한다.
연결된 데이터와 작업하기를 원한다. 예를들어 필드를 계산하기를 원하거나 복합관계를 강제하거나 엔터티의 데이터 엘리먼트 사이의 비즈니스 룰과 작업하기를 원한다.
복잡한 비즈니스 로직을 단순화 시키기 위해 도메인 모델을 적용하기를 원한다.


솔루션:

비즈니스 로직이 모델에 대해서 동작하도록 함으로써 데이터를 조회하는 로직을 분리하기 위해 리파지터리를 사용한다. 비즈니스 로직은 데이터소스 레이어의 데이터 타입에 대해서 자연스러워야 하며, 데이터소스는 데이터베이스, 쉐어포인트 또는 웹서비스가 될 수 있습니다.

리파지터리는 어플리케이션에서 데이터 소스 레이어와 비즈니스 로직 레이어 사이를 중재 mediates 한다. 리파지터리는 데이터소스에 대해 데이터를 질의하고 데이터 소스와 비즈니스 엔터티 사이의 데이터를 매핑한다. 비즈니스 엔터티의 변경을 데이터 소스에 저장한다. 리파지터리는 데이터소스, 웹서비스에 의존적인 상호작용을 비즈니스 로직으로 부터 분리 시킨다. 데이터와 비즈니스 티어의 분리는 다음의 3가지 잇점을 얻게합니다.

1. 데이터로직 또는 웹서비스 접근 로직을 중앙화 한다.
2. 유닛 테스트를 위한 대안을 제공한다.
3. 어플리케이션 진화 될 수 있는 디자인을 채택할 수 있도록 유연한 아키텍처를 제공한다.

리파지터가 비즈니스 엔터티를 질의하는 두가지 방법이 있습니다. 클라이언트 비즈니스 로직에 대한 질의 오브젝트를 제출 하는 방법, 비즈니스 조건을 정의하는 메소드를 사용하는 방법.  후자의 경우 리파지터리는 클라이언트 행동에 대한 질의를 만듭니다. 리파지터리는 질의를 만족하는 엔터티 집합을 반환합니다. 다음의 다이어 그램은  클라이언트,데이터소스 사이에서 리파지터리의 상호작용을 보여줍니다.


리파지터리의 상호작용 다이어그램.




클라이언트는 지속화를 위해 변경되었거나 새로 생성된 엔터티를 리파지터리에 제출합니다. 더 복잡한 상황에서는 Unit of Work 패턴을 사용할 수도 있습니다. 이 패턴은 연관된 의존을 영속화하기 위해서 수행되어야 하는 여러개의 작업을 어떻게 캡슐화 할 수 있는지를 보여 줍니다. 캡슐화된 아이템은 변경/삭제 행위를 위해 리파지터리에 보내 집니다. 이 가이드는 Unit of Work 패턴의 예제를 포함하지 않습니다. 더 많은 정보를 얻길 원하시면 마틴 파울러의 웹사이트의 Unit of Work 페이지를 방문하세요. 

리파지터리는 서로 다른 도메인에서 데이터와 작업 사이의 다리 bridge 입니다. 일반적인 경우는 데이터베이스 또는 쉐어포인트의 약-타입 의 데이터와 도메인의 강-타입 오브젝트에 매핑하는 것입니다.  한가지 예로 데이터베이스는 질의를 실행하기 위해 IDBCommand 오브젝트를 사용하고 IDataReader 오브젝트를 반환합니다. 리파지터리는 데이터소스에 대한 적절한 질의를 발행합니다. 그 결과를 외부로 노출된 비즈니스 엔터티에 매핑합니다. 리파지터리는 그 표현을 번역하기 위해 Data Mapper 패턴을 사용합니다. 리파지터리는 특정 기술에 대한 의존을 클라이언트로 부터 제거합니다. 예를 들어 클라이언트가 프로덕트 데이터를 조회하기 위해 리파지터리를 호출 한다면, 오로지 카탈로그 리파지터리의 인터페이스만을 사용하면 됩니다. 클라이언트는 프로덕트의 정보를 조회하기 위해 데이터베이스의 SQL로 질의 되는지 쉐어포인트의 CAMIL 이 사용되는지 알 필요가 없습니다. 이런 종류의 의존을 분리 시키는 것은 구현에 있어 유연함을 제공합니다.


구현상세:

쉐어포인트 를 예로 든 설명인데 번역 생략합니다. 코드를 이용한 구현 설명은 아니고 개념 설명입니다.

쉐어포인트 리파지터리의 상호작용 다이어 그램.
 




고려사항:


리파지터리 패턴은 코드의 추상화 정도를 증가시킵니다. 이는 이 패턴에 익숙하지 않은 개발자가 코드를 이해하는데 있어 더욱 어렵게 만들 수 있습니다. 이 패턴을 구현하는 것이 수많은 양의 코드 중복을 감소시키지만  관리해야 하는 클래스 수를 증가 시킵니다. 

리파지터리는 서비스와 리스트에 접근하는 코드를 분리하는데 도움을 줍니다. 고립은 독립적인 서비스처럼 다루기 쉽게 만들어 줍니다. 하지만 전형적으로 리파지터리 그 자체를 테스트하는 것은 매우 어렵습니다. 

멀티 스레드 환경에서 캐싱 데이터를 사용할 때 캐쉬 오브젝트에 대한 동기화도 고려해야 합니다. 종종 ASP.NET 캐쉬와 같은 일반적인 캐쉬는 스레드로 부터 안전하지만, 멀티 스레드 환경에서 작동 되는 오브젝트 그 차제에 대해 스레드로 부터 안전하도록 확인해야 합니다.

여러분이 고부하 시스템에서 데이터를 캐싱 한다면 성능 문제가 부가될 수 있습니다. 데이터소스에 대한 동기화 접근을 고려해 보세요. 이는 데이터에 대한 단일 요청만이 수행되도록 보장합니다. 

### 끝.


참고

리파지터리 패턴 구현에는 마틴파울러의 데이터 매퍼 패턴 (Data Mapper pattern)이 함께 사용됩니다.
리파이터리 패턴 구현에는 마틴파울러의 질의객체 (Query Object) 라는 개념이 사용됩니다.
동적, 재사용가능, Single point decision 을 위해서는 명세서 패턴 (Specification pattern) 이 함께 사용됩니다.
질의의 개별 조건에는 Criteria 라는 개념이 사용됩니다.
저작자 표시
신고

이 글을 Twitter / Facebook 에 공유하기
이 글이 유익하다면 아래의 트위터 버튼을 눌러 공유해 주시거나, 페이스북 "좋아요" 버튼을 눌러 주세요.

   


Posted by 반더빌트
소프트웨어 개발과 패턴은 어떤 관계가 있을까요? 초급의 개발에서는 패턴에 대한 필요성 자체를 인지하지 못합니다. 딴 세상 이야기 처럼 말이죠. 개발자들도 중요성 인지가 안되어 있으니 심지어는 '디자인 패턴 design patterns' 책이 그림 코너의 서가에 꽂혀 있던 때도 있었습니다. 책 이름이 '디자인' 이란 이유로 말이죠.  재사용 가능하며 유지관리 가능한 소프트웨어어 대해 고민하기 시작하면, 그때서야 웹어플리케이션, 클라이언트 어플리케이션, 서버 어플리케이션 영역에 관계없이 객체지향디자인과 패턴이 필요하다는 것을 인식하게 됩니다.

소프트웨어 개발은 개발 환경과 구동 환경을 이해하는 것으로 부터 시작합니다. 통합개발환경 IDE Integrated Development Environment 에서 개발하는 것이 가장 쉬운 방법입니다. 닷넷개발자라면 Visual Studio, 자바개발자라면 Eclipse 같은 환경 말이죠. 개발도중 또는 개발된 소프트웨어는 구동될 수 있는 호스트 Host 라는 환경이 필요한데, IDE의 장점은 자체적으로 호스트를 지원해서 구동 환경에 대해 걱정할 필요가 없습니다.

비개발자가 개발이라고 부르는 코딩이라는 작업을 하려면 '언어'라는 무기가 필요합니다.  언어는 칼과 같죠. 요리를 할때는 식칼을, 결투를 할 때는 긴 칼을 사용하 듯이 웹페이지의 화면을 구성할 때는 HTML을, 상호작용을 위해서는 자바스크립트 언어를, 내부 콘트롤을 위해서는 C#등의 언어를 사용합니다. 

언어를 사용하려면 언어의 능력과 특성을 알아야 겠죠. 바로 언어의 사양 specification 입니다. 글 과 문법을 알았다면 이제 시를 써야 겠지요.

프랙탈 : 혼돈 속의 규칙적인 패턴이 자연계 및 생명체를 만들어 내는 것이 소프트웨어의 패턴과 닮았다.



소프트웨어 개발의 목적은 어떠한 문제를 해결하는 것 입니다. 원래의 의도대로 정확하게 구동 되는 것이 가장 첫번째 달성해야 하는 목표라고 할 수 있습니다. 허나 소프트웨어는 구동되는 것 만이 전부가 아닙니다. 잘 개발된 객체지향 소프트웨어가 가져야 할 특성은 구획화 된 모듈성 modularity, 변경을 반영할 수 있는 유연성 flexibility, 요구 추가를 위한 확장성 extensibility, 이 요소들을 갖추고 있으면서도 소프트웨어가 생명주기동안 살아 있을 수 있도록 하는 유지관리성 maintainability 입니다.

언급한 특성들을 갖추게하는 증명된 방법 그 것이 바로 '패턴 Pattern' 입니다.


소프트웨어를 개발하다 보니 구현 코드는 달라도 유사한 문제가 발생하는데, 그 때 패턴을 사용하게 되고, 개발 관련자들 사이에 의사소통 도구로 사용됩니다. 또한 잘 구성된 패턴은 해결하려는 문제가 무엇인지 유추 가능케 합니다.


패턴이라는 것은 어떻게 공부 할 수 있는가?

패턴에는 레벨이라는 것이 존재 합니다.  코드, 클래스, 아키텍처 레벨로 구분할 수 있습니다.

코드 단위의 패턴을 공부할 수 있는 가장 좋은 책은 [켄트 벡의 구현 패턴] 입니다. 코드 단위의 문제해결에는 수많은 방법이 존재합니다. 코드는 컴퓨터, 자신 그리고 동료와의 의사소통 입니다. 정확하게 구동되어야 하고, 군더더기 없이 의도를 밝히는 코드가 좋은코드의 조건이죠. 개발자는 한땀 한땀 작성 할 때 마다 수많은 고민과 선택을 합니다. 좋은 코드의 조건을 만족시키기 위해 말이죠. 켄트 벡의 책은 코드 구현 단위에서의 고민을 덜어 줄 수 있는 패턴을 이 책에 담고 있습니다.

구현 코드를 감싸는 클래스 단위에서 그 유명한 디자인 패턴 Design Pattern 이 등장합니다. 재사용 가능한 소프트웨어 개발에 대한 고민으로 시작된 객체간의 관계 패턴으로 구조 Structural, 생성 Creational, 행위 Behavioral 의 세가지로 구분되어 있습니다. 디자인 패턴을 공부할 수 있는 책들은 다수가 존재하는데 우선 바이블 [GoF의 디자인 패턴 ] 을 빼놓을 수 없습니다. 디자인 패턴은 구현패턴에 비해 어렵습니다. 여러권의 책을 읽어야죠.  마틴 파울러의 [리팩토링]은 구현패턴과 디자인패턴을 커버합니다. 특히 구조적코드 Structural code가 객체적 코드, 디자인으로 어떻게 변경되어야 하는지 체감 수준의 책입니다. 

세번째 아키텍처 패턴입니다. 패키지, 모듈, 레이어 수준의 패턴을 의미합니다. 좋은 책으로는  마틴 파울러 [PoEAA (Patterns Of Enterprise Application Architecture)] 와 좀더 추상화된 설명으로 에릭 에반스의 [도메인-드리븐 디자인]이 있습니다. 여기서 언급되는 것들은 레이어링, 도메인 로직, 데이터베이스 매핑, 어그리게이트, 리파지터리의 개념들 입니다.



코드 단위 
켄트 벡의 구현 패턴, 켄트 벡저/전동환역, ISBN-10: 108960770310

클래스 단위
GoF의 디자인 패턴 : Elements of Reusable Object-Oriented Software, 에릭 감마,리처드 헬름,랄프 존슨,존 블라시디스 공저, ISBN-10:8945072144
Refactoring 리팩토링 : 나쁜 디자인의 코드를 좋은 디자인으로 바꾸는 방법, 마틴 파울러 저/윤성준,조재박 공역, ISBN-10:898793960X


패키지, 모듈, 레이어 단위
Patterns of Enterprise Application Architecture, Martin Fowler, ISBN-10: 0321127420
Domain-Driven Design : Tackling Complexity in the Heart of Software, Eric Evans, ISBN-10: 0321125215


이 블로그의 DDD & PoEAA 카테고리는 아키텍처 수준의 개념과 구현에 대한 글들의 모음 입니다.

### 끝.
저작자 표시
신고

이 글을 Twitter / Facebook 에 공유하기
이 글이 유익하다면 아래의 트위터 버튼을 눌러 공유해 주시거나, 페이스북 "좋아요" 버튼을 눌러 주세요.

   


Posted by 반더빌트


마틴 파울러 PoEAA(패턴 오브 엔터프라이즈 어플리케이션 아키텍처) 요약.

마틴 파울러의 PoEAA는 엔터프라이즈 어플리케이션의 아키텍처가 어떻게 구성되는 것인가에 대한 최고의 책입니다. 도입부의 [도메인 로직을 구성하는 패턴]은 조금은 어렵게 느껴지는 내용입니다. 전체적인 내용을 파악한 후 몇번에 걸쳐 정독 하는 것이 이 책의 내용을 이해하는 데 도움이 될 것입니다.

아래는 PoEAA 의 전체적인 요약 포스트의 번역 입니다.

엔터프라이즈 하면 역시 스타트랙.PoEAA




원문주소 : http://moshfegh.spaces.live.com/blog/cns!40F968A11C62F49A!192.entry

제목 : Summary notes from Martin Fowler's PoEAA

도메인 로직을 구성하는 패턴
1. 트랜잭션 스크립트 (Transaction Script) : 프로시저럴, 많은 중복, 모든 개발자가 이해하기 쉽고 간단합니다.
2. 테이블 모듈 (Table Module) : .NET 에서의 DataSet 처럼 트랜잭션 스크립트와 도메인 모델 사이의 중간이며, 도메인 로직을 핸들링하기가 트랜잭션 스크립트 보다 쉽습니다.
3. 도메인 모델 (Domain Model) : 복잡한 비즈니스 로직을 가지는 프로젝트에 적당합니다. 코드 중복 문제를 해결합니다.


데이터 소스로 부터 간단한 입출력만을 하는 프로젝트의 경우에는 트랜잭션 스크립트가 적합 할수 있으며, 복잡한 비즈니스 로직을 처리해야 한다면 도메인 모델이 적합합니다.


아이덴티티 맵 (Identity Map)

이름 그대로 오브젝트들을 구분할수 있는 Map, 오브젝트에 아이디를 부여 하여 메모리에 로딩 하여 맵으로 가지고 있는 형태. Look Up 하여 오브젝트를 참조할 수 있도록 지원.
메모리에 로드된 오브젝트는 상태가 변경될 수 있는데, 그 변경된 상태에 대해서도 다른 오브젝트에서 접근 가능해야 한다. 아이덴티티 맵은 세션 스코프를 가지며, 각각의 세션 내에서 인스턴스는 격리됨을 보장 받아야 합니다.
Unit of Work를  사용한다면 아이덴티티 맵이 위치할 수 있는 최적의 장소이며, Unit of work를 사용하지 않는 다면 세션에 결합된 Registry 가 적절한 장소입니다.

아이덴티티 맵의 다른 가치는 데이터베이스에 대한 캐쉬 역할을 하는 것입니다.


게이트웨이 (Gateway)
외부 시스템 또는 자원에 대한 접근을 캡슐화 하는 오브젝트. API와 같은 외부 자원을 취급하는데 좋습니다. API 코드들을 감쌈으로써 일반적인 클래스의 인터페이스로 보이게 할 수 있습니다.

 

분리된 인터페이스 (Separated Interface)
구현으로부터 분리된 인터페이스를 정의 합니다. 인터페이스 정의는 어떤 패키지에서 사용하고, 다른 패키지에서는 구현을 합니다. 이러한 구현은 클라이언트의 인터페이스에 대한 의존을 구현으로 부터 완벽히 분리할 수 있습니다.

분리된 인터페이스의 구현은 팩토리 오브젝트(Factory Object)를 이용하여 로드할 수 있습니다. 컨파일-타임(compile-time) 의존을 제거 하기 위해서 팩토리는 리플렉션(Reflection)을 이용하여 런-타임(run-time)에 구현을 로드할 수 있습니다.


이 패턴은 두 부분으로 구성되는 시스템에서 의존을 제거하기 위해서 필요하다. 예를 들어 도메인 코드가 데이터 매퍼(Data Mapper)를 호출하는 것 처럼 한 레이어에서 다른 레이어의 코드를 호출할 때 필요합니다.


레지스트리 (Registry)
오브젝트 또는 서비스를 다른 오브젝트들이 사용할 수 있도록 잘 알려진 공용 오브젝트.


특수 케이스 (Special Case)
특수한 경우에 특별한 행위를 제공하는 클래스. 일반 어플리케이션에서 null 값을 검사하는 패턴 등에서 이용할 수 있습니다. 다수의 경우에 매우 많은 곳에서 null 값을 검사할 필요가 있다면 이 패턴을 이용할 수 있습니다.
null 값을 반환하는 대신에 호출자가 기대하는 특별한 오브젝트를 반환할 수 있다. 단, 반환되는 오브젝트는 해로운 행위를 하지 않아야 합니다.


플러그인 (Plugin)
컴파일시가 아닌 설정(Configuration)에서 클래스를 연결 하는 것. 런타임 환경에서 다른 행위가 요구되어 질때 이 패턴을 사용 할 수 있다. 설정은(Configuration)은 리빌드 또는 재배포를 요구하지 않아야 합니다.


레이어링 (Layering)
관계 데이터를 단순히 보여주고, 입출력을 수행하는 프로젝트에서는 레이어링을 적용할 필요가 없습니다. 문제는 도메인 로직(비즈니스 규칙, 유효성 검사, 연산을 수행하는)에서 발생합니다. 클라이언트 UI에 포함된 비즈니스 코드들은 도메인이 복잡해 감에 따라 함께 일하기가 매우 어려워지고, 중복된 코드들을 양산합니다. 이 말은 작은 변경에도 수많은 화면이 문제를 일으킬수 있음을 의미합니다.

대안으로은 비즈니스 로직은 저장프로시저(Stored Procedure) 에 집어 넣는 것입니다. 저장프로시저는 서투른 코드를 유발하는 제한된 구조화된 메커니즘을 제공합니다.

교과서적인 3-Layer는 프리젠테이션, 도메인, 데이터소스 입니다.

 

레이어드 디자인

웹 어플리케이션에서의 레이어드 디자인과 Cross-Cutting Concern.


 


신고

이 글을 Twitter / Facebook 에 공유하기
이 글이 유익하다면 아래의 트위터 버튼을 눌러 공유해 주시거나, 페이스북 "좋아요" 버튼을 눌러 주세요.

   


Posted by 반더빌트

도메인-드리븐 디자인 요약의 또하나의 포스트 입니다. DDD를 설명하는 포스트의 번역인데요, 원문에서도 언급하듯이 DDD를 확실히 이해하려면 전반적인 모든 것을 알고 있어야

하고, 알고 있더라도 개인적인 경험에 의존하기 때문에 매우 어렵습니다. 다행이도 전체를 조망하는 통찰력을 가진 글을 읽음으로써 우리는 좀더 쉽게 DDD를 이해할 수 있습니다.

아래에 번역한 포스트가 바로 그런 글입니다.

번역 :

Domain-driven Design
http://powerdream5.wordpress.com/2007/10/15/domain-driven-design/

Domain-Driven Design(DDD)은 제가 존경하는 전문가중의 한명인 Eric Evans(http://domainlanguage.com/)가 변론한 소프트웨어 개발 접근법입니다.  DDD의 주요 목적은 도메인과 도메인 로직에 집중하여 요구사항에서 빗나가지 않게 하는 것입니다.
 
DDD는 유용하다는 것과 전통적인 소프트웨어 개발 방법론의 문제점을 극복할 수 있음을 보여 줍니다. 불행한 점은 DDD를 완전히 이해하는 것은 매우 어렵우며, 여러분의 경험에 매우 의존적이라는 것입니다. 여러분은 또한 실제 프로젝트에 적용하고, 여러분의 경험을 반복해서 집약해야 합니다. 솔직히 말해서 저도 DDD를 조금만 알 뿐입니다. 하지만, DDD에 대한 저의 생각을 나눌것이며 여러분의  댓글을 환영합니다.

Domain-driven design Building Blocks



우리는 도메인 모델에서 그들의 책임을 기준으로 나눌수 있는 5개의 역할을 가지고 있습니다. 5개의 역할은 Enity, Value Object, Factory, Repository 그리고 Services  입니다. 이것들을 저의 지식에 근거하여 설명해 보려 합니다.

       Entity: 엔터티는 사용자와 소프트웨어 개발자 모두에게 관련이 되어 있기 때문에 도메인 모델에서 가장 중요한 부분입니다. 엔터티는 소트프웨어의 상태 변화와 관계없는 아이텐티티를 가지고 있습니다. 다른 말로 하면, 우리는 엔터티를 데이터베이스와 같은 그 어딘가에 저장해야 합니다.

       Value Object: 엔터티는 아이텐티티를 가지고 있고 아이덴티티는 변경될 수 없기 때문에 어플리케이션이 엔터티를 생성하고 추적하는 데에는 비용이 많이 듭니다. 성능을 고려해 보면 도메인 모델의 모든 명사(noun)들을 엔터티로 매핑하는 것은 비합리적 입니다.  Value object 는 아이텐터티가 없으며, 여러분의 도메인 모델의 다른 오브젝트 들이 공유할 수 있는 오브젝트 입니다.

 Domain-Driven Design의 장점을 취하려 할때  엔터티와 value object를 구별하는 것이 우리가 만나는 첫번째 장애물입니다 . 어떤 오브젝트가 아이덴터티를 가져야 할지 말아야 할

지는 전적으로 소프트웨어 개발자가 결정하며, 거기에는 어떤 직접적인 규칙이 없습니다. 저의 의견은 엔터티를 인식하는 일은 오브젝트를 테이블에 매핑하는 것과 유사합니다.

Embedded value 패턴을 기억합니까? 어떤 종류의 오브젝트가 자신의 테이블을 가지고 매핑되어야 하고, 어떤 종류의 오브젝트가 부모 테이블에 매핑되어야 할지? 이 질문에 대한

답은 여러분의 판단 능력과 경험에 달려 있습니다.

         Factory: Factory는 엔터티를 생성할 책임이 있습니다. 일반적으로, 여러분의 도메인 모델에서 엔터티는 항상 다른 오브젝트들과 관계를 가지고 있기 때문에 엔터티를 생성하

는 과정은 복잡합니다. 엔터티를 생성할 때 우리는 관계망을 초기화 해야 합니다. 그래서 엔터티를 생성하는 프로시저를 캡슐화 하는 오브젝트를 정의하는 것은 매우 훌륭합니다.

         Repository:리파지터리는 엔터티를 관리할 책임을 가집니다. 관리란 데이터베이스로 부터 엔터티를 업데이트, 저장, 로딩하는 것을 의미합니다. 리파지터리는 특정 인터페이

스와 인터페이스를 구현하는 구상클래스 집합을 가집니다. 구상 클래스들은 어플리케이션의 영속화 레이어(persistent layer)를 캡슐화 합니다.

              Service: 도메인을 기술한 후에, 명사는 엔터티/value object 로, 동사는 메소드로 매핑할 수 있습니다. 때때로 어떤 동사들은 엔터티/value object 의 메소드로 매핑하는

것은 불합리합니다. 이런 경우에  이런 메소드들을 담는 service라는 이름의 새로운 역할을 만들 수 있습니다. 서비스는 어플리케이션의 과잉을 정의 할 것입니다. 서비스는 클라이언트에 의해 접근 될 것입니다.

이 글을 읽어 주셔서 감사합니다. DDD에 대해 잘못된 이해가 있다면, 어떤 의견도 좋으니 남겨주세요, DDD에 대한 더 많은 정보를 원한다면 이 링크(http://www.infoq.com/minibooks/domain-driven-design-quickly)를 열어 보세요.

신고

이 글을 Twitter / Facebook 에 공유하기
이 글이 유익하다면 아래의 트위터 버튼을 눌러 공유해 주시거나, 페이스북 "좋아요" 버튼을 눌러 주세요.

   


Posted by 반더빌트
TAG ddd

Specification Pattern 설명과 구현의 이해

Specification Pattern 은 DDD와 PoEAA에서 동시에 다루어지는 명세서 라는 패턴입니다. 도메인 모델은 다양한 종류의 조건 쿼리를 실행시키려 할 때  DAL( Data Access Layer ) 과 같은 프로바이더에 구현한 메소드를 호출할 필요성이 발생합니다.

실행조건마다 그 명세와 일치하는 메소드가 프로파이더에 작성되고, 도메인 오브젝트와 프로바이더는 점점 강하게 연결됩니다. 명세조건만 약간씩 다른 중복 코드들이 양산되게 되죠.

Specification Pattern 은 도메인 오브젝트가 일관성있는 인터페이스로 프로바이더를 이용하게 함으로써 커플링을 느슨하게 만들며, 정확한 명세가 무엇인지를 연결된 객체의 '코드' 가 아닌 모델 자체가 설명하도록 하면서 응집성과 SoC를 달성하도록 하는 패턴 입니다.


Specification Pattern 을 비유해 설명하자면 , 내가 필요한 책을 도서관의 서가마다 돌아다니며 찾는 것이 아니라, 책의 목록을 '사서'에게 전달하고 사서로 부터 책을 받기만 하면 도서관 마다의 대출 방법과 서가의 위치 및 구조를  일일이 알고 있지 않더라도 목적을 달성 할수 있다는 아이디어를 구현하는 패턴 입니다. 책의 목록이 Specification 이며,  사서가 프로바이더의 인터페이스입니다. 나는 도서관의 구조를 알필요가 없이 목록규칙(Criteria)만 지키면 되고, 나중에 동일한 책을 빌리고 싶다면 이전에 작성해 놓은 목록을 사서에게 건네 주기만 하면 됩니다.


명세는 도메인 모델에 구현하며, 프로바이더에 Specification 인터페이스에 기준( Criteria )을 구현한 인스턴스를 전달함으로써 목적을 달성합니다.

ISpecificaton 인터페이스와 쿼리 조합 클래스 구현 다이어그램.



다른 여러 패턴에 대해 우리는 "왜 이리 공부해야 할 패턴이 많아~ 아휴 이 패턴은 그냥 넘어 갈까" 하고 지나치는 일이 많습니다. Specification Pattern 은 그 가치를 알기 전까지 가장 간과하기 쉬운 패턴 일 듯 합니다.

Specification Pattern 의 개념과 구현 설명이 매우 잘 되어 있는 블로그 포스트가 있어 번역 포스트 합니다.


번역 :

The Specification Pattern: A Primer
Posted March 25th 2005 by Matt Berther

Specification Pattern 은 클래스의 인터페이스에서 잡동사니들을 제거해주는 동시에 확장성을 증가시켜주고 커플링을 낮춰주는  매우 강력한 디자인 패턴입니다.

이것의 주된 쓰임은 어떤 기준에 기반한 개체의 부분집합을 선택하는 것과 다양한 상황에서 선택을 리프레쉬 시키는 것입니다.

예를 들어, 나는 이와 비슷한 것으로 보이는 인터페이스를 가진 클래스를 매우 많이 봤습니다.


public class User
{
    public string Company;
    public string Name;
    public string City;
}

public class UserProvider
{
    public User[] GetUserByName(string name)
    {
    }

    public User[] GetUsersByCity(string name)
    {
    }

    public User[] GetUsersByCompany(string company)
    {
    }
}


이 모델을 이용함으로써, 사용자검색을 위한 새로운 조건을 부여하고 싶을 때마다 유저프로바이더 클래스에 메소드를 추가해야 하고, 이는 인터페이스를 혼란스럽게 하는 것을 알

수 있습니다.

이제 specification pattern을 사용한 똑같은 사례를 살펴봅시다.


public class User
{
    public string Company;
    public string Name;
    public string City;
}



public class UserSpecification
{
    public virtual bool IsSatisfiedBy(User user)
    {
        return true;
    }
}

public class UserProvider
{
    public User[] GetBySpecification(UserSpecification spec)
    {
        ArrayList list = new ArrayList();

        UserCollection coll = SomeMethodToPopulateTheUserCollection();
        foreach (User user in coll)
        {
            if (spec.IsSatisfiedBy(user))
            {
                list.Add(user);
            }
        }

        return (User[])list.ToArray(typeof(User));
    }
}

class UserCompanySpecification : UserSpecification
{
    private readonly string companyName;

    public UserCompanySpecification(string companyName)
    {
        this.companyName = companyName;
    }

    public override bool IsSatisfiedBy(User user)
    {
        return user.Company.Equals(companyName);
    }
}



이 패턴을 사용함으로써, 유저프로바이더 클래스로부터 특화된 모든 메소드들을 제거합니다. 

또한, 느슨한 커플링으로 인해  검색을 위한 부가적인 조건을 언제든 추가할 수 있습니다. 우리는 기존의 인터페이스를 오염시키기 보다는 새로운 UserSpecification 을 구현하고,

GetBySpecification  메소드에 이 인스턴스를 던져주기만 하면 됩니다.

이는 프로바이더 코드가 사용자가 원하는 방법을 알고 있다고 가정하기보다는 호출하는 코드가 어떤 컬렉션이든 어떻게 필터할 것인지 정확히 결정하도록 해줍니다.

물론, API 디자이너가 소수의 잘쓰이는 Specification을 API 그 자체에  집어넣는 것은 허용됩니다.

이 패턴은 매우 강력하지만, 다른 것처럼 과용될 수 있습니다. 이 패턴을 쓰거나 쓰지 말아야 할 때에 대한 연결된 설명을 고려하여 결과를 리뷰해보는 것을 명심하십시오. 


 

신고

이 글을 Twitter / Facebook 에 공유하기
이 글이 유익하다면 아래의 트위터 버튼을 눌러 공유해 주시거나, 페이스북 "좋아요" 버튼을 눌러 주세요.

   


Posted by 반더빌트
에릭 에반스 (Eric Evans) 는 과거의 지혜와 경험들을 종합하여 도메인-드리븐 디자인 (Domain Driven Design) 이라는 방법론을 제시 했습니다.

단순 객체지향 세계에서 살던 개발자들은  이 굉장하지만 새로운 개념에 어려움을 느껴 발표된지 몇년이 지난 후에야 관심을 가지게 되었죠.

DDD가 도대체 뭔데? 어떻게 해서든지 돌아가기만 하면 되는거 아냐! 하면서 무심히 지나쳤던 것들에 대해 체계적으로 설명하는 방법론이죠. 하지만 여전히 DDD는 어렵운 것, 그저 한때 유행하는 버즈 워드로 인식되고 있는 경향이 있습니다. DDD가 무엇인지 처음 듣는 개발자도 많을 것입니다.

 DDD의 전체적인 철학을 쉽게 요약하고 있는 블로그 포스트 DDD: How to tackle complexity  번역으로 DDD 카테고리를 시작합니다. 

 
번역 : 

DDD
(Domain Driven Design) 에서는 어플리케이션 도메인을 표현하기 위한 오브젝트 모델을 만듭니다.
이 모델은 도메인의 모든 관계와 로직을 담고 있습니다. 이렇게 하는 목적은 도메인의 복잡성을 관리하기 위함 입니다. DDD 에는 매우 많은 개념과 패턴이 투입되어 있으나, 정제된 두개의 큰 그림으로 그 복잡성에 태클을 걸 수 있습니다.

1. 도메인의 개념을 명확하게 표현합니다.
2. 더욱 심도 있는 통찰을 위해 지속적인 리팩토링을 수행합니다.

복잡성이란 자체의 복잡한 정도를 의미합니다. 복잡한 것은 이해하기 어렵습니다. 이해하기 어려우면 금방 알아 들을 수 없습니다.

이것이 실제 이슈 입니다 : 복잡한 소프트웨어는 이해하기 어렵습니다. 이것이 바로 모든 사람이 업데이트 하기를 두려워 하여 아예 처음부터 다시 만드는 이유입니다. 아마 첫번째나 두번째는 해킹 하듯이 코드를 추가해서 원하는 바를 이룰 수 있을지 모르지만, 각각의 해킹은 더 이상 시도하는 것이 의미가 없을 때까지 복잡성과 추잡함을 증가시킵니다. 이것을 다른 말로 실패 라고 합니다.

그래서 우리는 이 복잡성을 극복해야 합니다. DDD의 첫번째 방법은 객체지향, 모델 과 추상화의 장점을 얻는 것 입니다. 하지만 이건 매우 광범위 하죠. 우리는 이 오브젝트와 모델들을 어떻게 구조화 해야 하는지 알아내야 합니다. 이것이 DDD가 도메인의 개념을 명시적으로 표현하자는 아이디어의 입니다.

아이디어는 간단합니다. 여러분의 도메인에 새로이 적용되는 개념이 있다면 모델에서 확인할 수 있어야 합니다. 중요한 개념을 확인하기 위해서 코드를 뒤져서는 안됩니다. 그 개념은 모델에서 오브젝트로써 표현되어야 합니다. 특정 조건에서만 발생하는 액션이 있다고 합시다, 이 조건들이 중요하지 않다면 그 액션을 수행하도록 그저 IF Statement 메소드로 처리하면 됩니다. 하지만, 그 조건들이 도메인에서 중요하다면 코드로 부터 감추는 것만으로는 부족합니다. 그 조건들을 수행하도록 Policy Object가 조건들을 표현해야 합니다. 이제 조건들은 당신의 도메인에서 명시적으로 표현됩니다.

이 아이디어 들은 Factories, Repositories, Services, Knowledge Levels 등등으로 표현될 수 있습니다. 이 것은 여러분의 시스템을 이해 가능하도록 만드는 중요한 부분입니다.

DDD가 작동하도록 만드는 두번째 아이디어는 "Deeper Insight"를 위한 지속적인 리팩토링 입니다. Deeper Insight 란 이미 가지고 있는 도메인 모델에서 새로운 어떤 것을 발견하게 된다면 대충 끼워넣지 말고 도메인에서 중요한 요소인지 반드시 알아내라는 것을 의미합니다. 만약 중요하다면 새로 이해한 것이 명확하게 표현 되도록 모델을 리팩토링 해야 합니다. 이 리팩토링은 사소할 때도 있고, 매우 중요 할 때도 있습니다.

도메인 모델이 표현성을 잃게 되면 점점 더 부서지고, 점점더 복잡해 지며 점점 더 어려워 집니다. 여러분의 모델이 단순하며  표현력과 정확성을 유지할 수 있도록 항상 싸워야 합니다. 당신이 운이 좋다면 에릭 에반스가 말하는 Break Through [전에는 불가능 했던 것이 새로운 가능성과 통찰력이 갑자기 나타나는 일] 것을 경험할  수도 있습니다. 그렇게 된다면 진짜 운이 좋은 것입니다. 당신이 운이 좋지 않더라도 리팩토링은 적어도 모델이 유연성을 요구할때 유연함을 만족 시킬 수는 있습니다. 이것은 미래에 나타날 통찰력과 리팩토링 요소를 더 쉽게 핸들링 할 수 있음을 의미합니다.

정말로 멋진 일은 이 두 개념이 서로에게 영향을 주는 싸이클을 이룬다는 것입니다.

DDD 싸이클

DDD Feed 싸이클



재조정 하면 할 수록 모델은 명시적이 되고, 모델이 명시적일 수록 재조정 하는 것이 쉬워 집니다.

참조 :
DDD: How to tackle complexity
http://moshfegh.spaces.live.com/blog/cns!40F968A11C62F49A!189.entry

용어에 대한 개념 정리 포스트 : 2011.02.11 추가됨.
신고

이 글을 Twitter / Facebook 에 공유하기
이 글이 유익하다면 아래의 트위터 버튼을 눌러 공유해 주시거나, 페이스북 "좋아요" 버튼을 눌러 주세요.

   


Posted by 반더빌트


티스토리 툴바