'마틴파울러'에 해당되는 글 2건

  1. 2011.04.07 제어의 역전 IoC Inversion of Control 이란 무엇인가? (1)
  2. 2011.04.04 Repository Pattern - in MSDN
또 등장 했습니다. "역전 inversion" 이라는 말은 용어 자체가 굉장히 어려운 말입니다. 두가지 뜻을 담고 있으니까요. "역전" 은 두가지를 알아야 이해를 할 수 있는 용어 입니다. "기존"의 상태 와 "역전" 된 상태, 그리고 역전되어야 하는 이유를 알아야 합니다. 이 포스트는 바로 마틴 파울러 martin fowler 의 "제어의 역전 IoC Inversion of Control" 의 문서를 가지고 이야기 합니다.

* IoC 와 IoC Container는 조금 다른 개념으로 다음 포스트에 다룰 예정입니다. 


프로그래밍이란 제어를 순서화 하는 일련의 과정 입니다. 하나의 프로그램은 수천, 수만개의 제어를 가질 수 있습니다. 프로그래머가 다음에 일어날 모든 제어를 알고, 관리한다는 것은 불가능에 가깝습니다. 관련이 깊은 제어와 속성들을 하나로 묶어 객체를 만들고, 객체들이 상호작용 하도록 하자는 것이 객체-지향의 개념이라고 할 수 있습니다. 단위 제어를 객체에 묶었어도 여전히 객체들을 제어 해야 합니다. 어떻게면 프로그래머가 작성하는 코드가 제어의 숫자를 줄일 수 있게 할까?에 대한 고민이 바로 "제어의 역전" 입니다.

재사용 가능한 프로그램을 작성하고 싶다고? 콘트롤을 줄여!



제어의 역전 이란 어떠한 일을  하도록 만들어진 프레임워크에 제어의 권한을 넘김으로써 클라이언트 코드가 신경 써야 할 것을 줄이는 전략입니다. 이것을 제어가 역전 되었다 라고 합니다. 일반적으로 라이브러리는 프로그래머가 작성하는 클라이언트 코드가 라이브러리의 메소드를 호출해서 사용하는 것을 의미 합니다. 프레임워크를 규정하는 특성은 프레임워크의 메소드가 사용자의 코드를 호출 한다는데 있습니다.

여기까지는 이해가 쉽지만, 의문이 생깁니다. 대체 어떻게 프레임워크가 나의 메소드를 호출하지? 전통적인 사고 방식을 가진 우리 프로그래머들은 혼란이 발생합니다.

어떻게 하면 프레임워크가 나의 코드를 호출 할 수 있을까요? 프레임워크는 내가 작성한 코드를 모르잖아!. 

제어를 역전 시키는 (프레임워크가 나의 코드를 호출 할 수 있게 하는) 가장 쉽게 생각할 수 있는 접근 방법은 프레임워크의 event, delegate 에 나의 메소드를 등록 시키는 것입니다. 전달되는 인자와 반환 형식만 일치 한다면, 프레임워크 코드는 내가 작성한 객체와 타입을 고려하지 않습니다. 등록된 메소드만 감지하여 실행 invoke 하는 것입니다.

다른 방법은 프레임워크에 정의 되어 있는 인터페이스 interface, 추상타입 abstract 을 나의 코드에서 구현, 상속 한후 프레임워크에 넘겨주는 것입니다. 프레임워크는 인터페이스와 추상을 알고 있으므로  내가 하고자 하는 일련의 작업을 처리할 수 있습니다. 이는 객체를 프레임워크에 주입하는 것이고, 이를 의존을 주입 dependency injection 한다고 합니다.


마틴 파울러는 그의 글 Inversion of Control Containers and the Dependency Injection pattern 에서 IoC 라는 용어가 너무 일반적이며 모호하므로 앞으로는 Dependency Injection 이라는 용어를 사용하겠다 라고 말하고 있습니다. 만, 이 포스트에서는 IoC 의 원래의 개념 설명에 집중하도록 하겠습니다.


좀더 깊은 이해를 위한 마틴파울러 글의 요약 및 정리는 아래에 이어 집니다.

Inversion of Control , 2005 june 26, by martin fowler

 제어 역행은 여러분이 프레임워크를 확장할 때 종종 만나게 되며, 프레임워크의 특성을 정의 합니다. 사용자로 부터 몇가지 정보를 얻는 커멘드라인 프로그램을 작성한다고 상상해 보세요. 다음과 같을 것입니다.

#ruby
  puts 'What is your name?'
  name = gets
  process_name(name)
  puts 'What is your quest?'
  quest = gets
  process_quest(quest)



이 상호 작용에서 코드는 제어를 하고 있습니다. : 언제 질문을 할 것인가? 응답을 언제 읽을 것인가?  이 결과들을 언제 처리할 것인가? 를 결정합니다.


그러나, 윈도윙 시스템을 위한 작업을 한다면 다음과 같을 것입니다.

require 'tk'
  root = TkRoot.new()
  name_label = TkLabel.new() {text "What is Your Name?"}
  name_label.pack
  name = TkEntry.new(root).pack
  name.bind("FocusOut") {process_name(name)}
  quest_label = TkLabel.new() {text "What is Your Quest?"}
  quest_label.pack
  quest = TkEntry.new(root).pack
  quest.bind("FocusOut") {process_quest(quest)}
  Tk.mainloop()


이 두개의 프로그램은 "제어의 흐름 flow of control" 에서 매우 큰 차이가 있습니다. 커맨드 라인 프로그램에서는 
process_name 과 process_quest  메소드를 호출 합니다. 하지만 윈도우 시스템에서는 폼을 만들 때의 바인딩을 기반으로 나의 메소드를 호출합니다. 제어는 역전 inverted 되었습니다.  내가 아니라 프레임워크가 나를 호출하는 것 입니다. 이 현상을 제어의 역전 Inversion of Control 이라고 합니다.( A.K.A Hollywood Principle - "Don't call us, we'll call you").


프레임워크의 중요한 특성은 사용자가 정의한 메소드가 사용자의 어플리케이션 코드가 호출 하기보다 종종 프레임워크로 부터 호출 되어 진다는 것이다.  프레임워크는 종종 어플리케이션의 행위를 재배치 하고, 순서를 정하는 메인프로그램의 역할을 담당한다. 역전된 제어는 프레임워크가 확장된 뼈대를 제공하는 힘을 제공한다. 사용자는 특정 어플리케이션을 위한 커스터마이즈된 알고리즘 메소드를 프레임워크에 전달한다. 

One important characteristic of a framework is that the methods defined by the user to tailor the framework will often be called from within the framework itself, rather than from the user's application code. The framework often plays the role of the main program in coordinating and sequencing application activity. This inversion of control gives frameworks the power to serve as extensible skeletons. The methods supplied by the user tailor the generic algorithms defined in the framework for a particular application.

-- Ralph Johnson and Brian Foote 


역전된 제어는 프레임워크와 라이브러리를 구분하는 열쇄 입니다. 라이브러리는 여러분이 호출할 수 있는 기능의 집합 set of functions 니다. 오늘날에는 보통 클래스들로 구성하죠.  각각의 호출은 지정된 일을 한후 클라이언트에게 제어를 반환 합니다. 

 
프레임워크는 추상화된 설계와 많은 내장된 행위를 감싸고 있습니다.  그걸 이용하기 위해서는 여러분이 작성한 클래스를 서브클래싱 또는 플러그 함으로써  행위를 프레임워크의 여러장소에 삽입해야 합니다.  그후 프레임워크는 여러분의 코드를 호출 합니다.

여러분의 코드가 호출 되도록 플러그 하는 방법은 여러가지가 있습니다. 위의 Ruby 에서 처럼 이벤트 이름과 Closure 인자를 넘김으로써 메소드를 바인딩 할 수 있습니다. text entry box 가 이벤트를 감지 했을때 clossure는 코드를 호출 합니다. 이 방법은 매우 편리하지만 모든 언어들이 지원하는 것은 아닙니다.

다른 방법으로는 프레임워크가 이벤트를 정의하고, 클라이언트 코드가 이벤트를 구독 subscribe 하게 하는 것입니다. .NET 플렛폼은 사람들이 이벤트를 정의할 수 있도록 언어에서 지원하는 좋은 예 입니다. 여러분은 delegate를 이용하여 여러분의 메소드를 event 에 바인딩 할 수 있습니다.

위의 예는 한가지 경우에 작동하는  접근방법입니다. 하지만 여러분은 때때로 여러개의 메소드가 호출되기를 원할 것입니다. 이 경우에 클라이언트 코드가 관련된 호출을 받을 수 있는 인터페이스 interface를  구현할 수 있도록 
 프레임워크는 인터페이스 interface를 정의 합니다.


EJB는 이런 스타일의 역전된 제어를 제공하는 좋은 예 입니다. 세션빈을 작성할 때, 여러분은 EJB 컨테이이너가 라이프사이클의 여러곳에서 호출 할 수 있도록 다양한 메소드를  구현할 수 있습니다. 예를 들어 세션빈은 (두번째 저장소를 위한) 
ejbRemoveejbPassivate 와 (대기상태에서 리스토어를 위한) ejbActivate  인터페이스를 정의 합니다. 여러분은 이 메소드들을 호출하는 제어권을 가지지 않습니다.  프레임워크가 알아서 합니다. 우리가 호출 하는 것이 아니라, 컨테이너가 우리가 작성한 코드를 호출 합니다.


이는 역전된 제어의 복잡한 예시 입니다. 이 효과를 더욱 단순하게 얻는 방법이 있습니다. template method 가 좋은 방법입니다 : 슈퍼클래스는 제어의 흐름 flow of control 을 정의하고, 서브클래스는 메소드를 오버라이드 하거나 추상메소드를 구현함으로써 확장을 얻을 수 있습니다. JUnit 프레임워크는 setUp과 tearDown 메소드를 호출 함으로써 여러분의 단위테스트를 생성하고 제거 합니다. 프레임워크는 여러분의 코드를 호출하고 반응하게 합니다. - 또 다시 제어는 역전 되었군요. 


오늘날 IoC 컨테이너의 등장으로 역전된 제어 Inversion of Control 의 의미에 몇가지 혼동이 생겼습니다. 어떤 사람들은 역전된 제어 스타일의 일반적인  원칙( 의존 주입과 같은) 에 혼란 스러워 합니다. IoC 컨테이너가 일반적으로 EJB의 경쟁자로 인식되기 때문에 그 이름이 혼란의 원인이 됩니다. EJB는 여전히 역전된 제어를 매우 많이 사용 합니다.


어원 :
내가 아는  역전된 제어 Inversion of Control  용어는 1998, Object-Oriented Programming 저널에 출판된 Johnson 과 Foote's의 논문 Designing Reusable Classes 에서 입니다. 이 논문은 15년이 지난 지금도 읽어볼 만한 가치가 있습니다. 이 용어가 무엇으로 부터 영감을 받았는지 그들도 기억하지 못하지만, 객체-지향 커뮤니티와 GoF의 책에서 살아남아 등장합니다.  더 섹시한 용어인 'Hollywood Principle' 은  1993, Mesa 의  Richard Sweet 의 논문으로 부터 기인합니다. 그가 쓴 "Don't call us, we'll call you (Hollywood's Law)"의 디자인 목적은 : 사용자가 도구에 대해 희망하는 커뮤니케이션을 도구가 고지 notify 해야 한다는 것입니다. 모델에 대한 명령 command 과 실행 execute 을 사용자가 직접 하는 대신에 말이죠. John Vlissides는 column for C++ report에 'Hollywood Principle'에 대한 매우 좋은 설명을 제공합니다. (어원에 대해 도움을 준 Brian Foote와 Ralph Johnson에게 감사합니다.)
 

### 끝.

관련 포스트 :  

 IoC 의 기반 개념을 가진 : 의존 관계 역전의 법칙(DIP) 

참조
Inversion of Control , 2005 june 26, by martin fowler
- Johnson 과 Foote's의 논문 Designing Reusable Classes 은 읽어볼 만한 굉장한 가치가 있습니다. 
저작자 표시
신고

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

   


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

리파지터리 패턴은 그 역할과 구현이 명확한 개발언어로 스펙으로 정의 된것이 아닌, 일반언어(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 반더빌트


티스토리 툴바