봉봉의 개인 블로그

2017-07-14-P(IoC) 본문

학원에서 배운것들/TEA - P

2017-07-14-P(IoC)

봉봉이네 2017. 7. 14. 09:07

"역전 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)



출처: http://vandbt.tistory.com/43 [소프트웨어 디자인- Design Software by vandbt]

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



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


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()



출처: http://vandbt.tistory.com/43 [소프트웨어 디자인- Design Software by vandbt]

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



역전된 제어는 프레임워크와 라이브러리를 구분하는 열쇄 입니다. 라이브러리는 여러분이 호출할 수 있는 기능의 집합 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는 여전히 역전된 제어를 매우 많이 사용 합니다.

'학원에서 배운것들 > TEA - P' 카테고리의 다른 글

2017-07-20-P(프로세스 모델링과 CRUD 매트릭스)  (0) 2017.07.20
2017-07-13-P(의존성 주입)  (0) 2017.07.13
2017-07-07-P  (0) 2017.07.07
2017-07-06-P  (0) 2017.07.06
2017-06-27-P  (0) 2017.06.27
Comments