hcn1519 / TILMemo

블로그 초안 저장소
10 stars 1 forks source link

Dependency, DIP, DI #65

Open hcn1519 opened 4 years ago

hcn1519 commented 4 years ago

DI https://justhackem.wordpress.com/2016/05/13/dependency-inversion-terms/

IoC https://justhackem.wordpress.com/2016/05/14/inversion-of-control/

DIP https://martinfowler.com/articles/dipInTheWild.html

IoC Container https://www.tutorialsteacher.com/ioc/ioc-container

hcn1519 commented 4 years ago

https://martinfowler.com/bliki/InversionOfControl.html

hcn1519 commented 4 years ago

Dependency Injection

https://martinfowler.com/articles/injection.html

PlugIn

https://martinfowler.com/eaaCatalog/plugin.html

hcn1519 commented 4 years ago

Dependency Injection

Inversion of Control

의존성과 관련된 키워드 중

Inversion of Control과 관련된

what aspect of control are they inverting?

Inversion of Control은 단어의 뜻 그대로 제어 흐름이 역전되는 현상을 말합니다. 제어 흐름이 역전되는 것을 알기 위해서는 제어 흐름이 역전되지 않은 것을 이해할 필요가 있습니다. 여기에서는 전통적인 제어의 흐름이 무엇을 의미하고, 이를 역전하는 Inversion of Control에 대해 살펴보겠습니다.

1. 제어의 흐름(Flow of Control)

절차 지향 프로그래밍의 패러다임을 따르고 있는 언어의 대부분은 main이라는 함수가 앱의 시작점이 됩니다. 그래서 프로그램에 기능을 추가한다고 하였을 때, 기본적으로 main 함수에서 프로그램의 요구사항에 맞추어 기능을 추가합니다.

int main(int argc, const char * argv[]) {
    job1();
    job2();
    job3();
    return 0;
}

이 때, 프로그램의 실행 순서는 직관적으로 이해가 가능합니다.

  1. main 함수 호출
  2. main 함수에서 정의된 기능 함수 수행
  3. 프로세스 종료

이처럼 코드가 시스템에 의해 수행되는 순서 혹은 흐름을 Flow of Control(제어의 흐름)이라고 말합니다. Wikipedia에서는 Flow of Control을 expression의 evaluation, statement의 수행, 함수 호출 등의 순서라고 정의하고 있습니다.

In computer science, control flow (or flow of control) is the order in which individual statements, instructions or function calls of an imperative program are executed or evaluated.

expression과 statement에 대한 것은 이전에 제가 작성했던 Expression과 Statement을 참고하시면 좋습니다.

2. Inversion of Control

이를 구체적으로 이해하기 위해서 우선 전통적인 시스템의 흐름이 무엇인지 알아야 합니다. 전통적인 시스템의 흐름은 절차지향 프로그래밍에서의

전통적인 시스템의 흐름(Flow of Control)

전통적인 시스템의 흐름이라는

  1. 제어의 흐름이 전통적인 시스템과 어떻게 반대로 일어나게 되는가?

Inversion Of Control을 이해하기 위해서는 Flow of Control

내 코드가 프로세스의 흐름을 제어한다 - 시스템이 프로세스의 흐름을 따른다. 시스템이 프로세스의 흐름을 제어하도록 한다 - 내 코드가 흐름을 따른다.

Main Init Function call

라이브러리와 Framework의 차이

Framework에 code PlugIn을 수행하는 방법

  1. 클로저를 활용한다.
  2. Delegate를 활용한다.(event subscribing)

대표적인 예시 - UIViewController의 오버라이딩 메소드, delegation

hcn1519 commented 4 years ago

http://www.laputan.org/drc/drc.html

hcn1519 commented 4 years ago

라면을 끓이는 방법

  1. 냄비에 물을 500ml 넣고 끓인다.
  2. 면사리를 넣는다.
  3. 스프를 넣는다.
  4. 면이 다 익도록 4분간 더 끓여준다.

Step1에 무엇을 한다. Step2에 무엇을 한다.

hcn1519 commented 4 years ago

Inversion of Control Containers and the Dependency Injection Pattern

Components and Services

I use component to mean a glob of software that's intended to be used, without change, by an application that is out of the control of the writers of the component. By 'without change' I mean that the using application doesn't change the source code of the components, although they may alter the component's behavior by extending it in ways allowed by the component writers.

Inversion of Control

what aspect of control are they inverting?

Forms of Dependency Injection

  1. Constructor Injection
  2. Setter Injection
  3. Interface Injection
hcn1519 commented 4 years ago

IoC, Dependency, DIP

Inversion Of Control

Inversion of Control은 단어의 뜻 그대로 제어 흐름이 역전되는 현상을 말합니다. 제어 흐름이 역전되는 것을 알기 위해서는 제어 흐름이 역전되지 않은 것을 이해할 필요가 있습니다. 따라서, 이 글에서는 역전되지 않은 제어의 흐름이 무엇인지 먼저 살펴보고, 이를 역전하는 Inversion of Control에 대해 살펴보겠습니다.

1. 제어의 흐름(Flow of Control, Control Flow)

제어의 흐름은 코드가 시스템에 의해 수행되는 순서 혹은 흐름을 의미합니다. 예시를 살펴보면 직관적으로 정의를 이해할 수 있습니다.

일반적으로 소스 코드는 위쪽 코드가 먼저 실행되고 아래쪽 코드가 나중에 실행됩니다. 이 때, 경우에 따라서 조건문/반복문을 추가하여 동작을 제어하기도 합니다. 간단한 예시를 살펴보겠습니다.

여기에서 사용하는 예시는 InversionOfControl - Martin Fowler의 예시를 약간 변형한 것임을 밝힙니다.

class ScreenPresenter {
    var name: String = ""
    var quest: String = ""

    func displayName() {
        print("Diplay User Input:", name)
    }

    func displayQuest() {
        print("Diplay User Input:", name)
    }
}

let presenter = ScreenPresenter()
presenter.name = "Hong"
presenter.displayName()
presenter.quest = "Do Something"
presenter.displayQuest()

위 코드의 실행 순서는 다음과 같습니다.

  1. ScreenPresenter 생성
  2. ScreenPresenter의 property 중 name을 설정
  3. displayName()을 호출하여 name을 출력
  4. ScreenPresenter의 property 중 quest를 설정
  5. displayQuest()을 호출하여 quest를 출력

장황하게 순서를 서술하였지만, 직관적으로 쉽게 이해가 가능한 흐름입니다. 이와 같이 시스템이 개발자가 작성한 코드를 호출하는 흐름을 제어의 흐름이라고 합니다.

제어의 흐름의 가장 큰 특징은 개발자가 작성한 코드가 시스템 동작의 제어권을 가지고 있다는 점입니다. 즉, 위의 예제에서 displayName(), displayQuest()를 호출하는 시점은 개발자가 결정합니다. 시스템은 이러한 호출에 따라서 명령을 수행합니다.

2. 제어 흐름의 역전(Inversion Of Control)

제어 흐름의 역전(Inversion Of Control)은 제어권을 가지고 있는 주체가 역전되는 현상을 의미합니다. 앞서서 제어의 흐름에서 시스템 동작의 제어권은 개발자가 가지고 시스템은 이를 따른다고 얘기하였습니다. IoC는 코드 수행의 제어권이 시스템쪽에 있는 현상을 의미합니다.

위에서 살펴 본 코드를 다르게 구현한 예시를 살펴보겠습니다.

class ScreenPresenter {
    var name: String = "" {
        didSet {
            didFinishWritingName?(name)
        }
    }

    var quest: String = "" {
        didSet {
            didFinishWritingQuest?(quest)
        }
    }

    var didFinishWritingName: ((String) -> Void)?
    var didFinishWritingQuest: ((String) -> Void)?
}

func display(value: String) {
    print("Display User Input:", value)
}

let presenter = ScreenPresenter()
presenter.didFinishWritingName = { nameInput in
    display(value: nameInput)
}
presenter.didFinishWritingQuest = { questInput in
    display(value: questInput)
}

presenter.name = "Hong"
presenter.quest = "Do Something"

위 코드의 실행 순서는 다음과 같습니다.

  1. ScreenPresenter 생성
  2. name 설정시 display(value:)가 호출되도록 설정
  3. quets 설정시 display(value:)가 호출되도록 설정
  4. ScreenPresenter의 property 중 name를 설정
  5. ScreenPresenter의 property 중 quest를 설정

이 코드와 이전 예시의 가장 큰 차이점은 display() 함수를 누가 호출하는가입니다. 앞선 예시에서는 이를 개발자가 직접 호출하였습니다. 여기에서는 시스템이 호출합니다. 즉, 개발자-시스템 사이의 제어권이 역전(invert)되는 현상이 발생하였습니다.

Ioc는 Hollywood Principle이라고도 불립니다. Hollywood Principle - Don,t call us, We will call you.

IoC를 통한 모듈의 확장

앞선 두 예제만 살펴봐도 제어 흐름을 역전시킨 코드는 그렇지 않은 코드보다 상대적으로 더 복잡합니다. 이는 제어 흐름을 역전하기 위해 제어권을 위임하는 장치를 추가하였기 때문입니다. 이 장치는 delegate이라고 불리는 객체를 의미하기도 하고, 위 예제에서 사용한 클로저/콜백 등을 지칭하기도 합니다. 하지만 이렇게 코드를 복잡하게 만드는 단점에도 불구하고, IoC는 의도적으로 사용됩니다. IoC를 활용하면 모듈을 매우 유연하게 확장할 수 있기 때문입니다

IoC 현상을 활용하면, 사용하고 있는 모듈의 변경 없이 기능을 유연하게 변경할 수 있습니다. 위 예시에서 display(value:) 호출 이후에 화면을 reload하는 로직을 추가로 구현한다고 생각해보겠습니다. 첫 번째 예시는 아래와 같이 코드를 추가할 수 있습니다.

class ScreenPresenter {
    var name: String = ""

    func displayName() {
        print("Diplay User Input:", name)
    }

    func reloadScreenForName() {
        print("Reload Screen")
    }
}
let presenter = ScreenPresenter()
presenter.name = "Hong"
presenter.displayName()
presenter.reloadScreenForName()

두 번째 예시는 아래와 같이 처리할 수 있습니다.

class ScreenPresenter {
    var name: String = "" {
        didSet {
            didFinishWritingName?(name)
        }
    }
    var didFinishWritingName: ((String) -> Void)?
}

func display(value: String) {
    print("Display User Input:", value)
}

func reload(value: String) {
    print("Reload Screen")
}

let presenter = ScreenPresenter()
presenter.didFinishWritingName = { nameInput in
    display(value: nameInput)
    reload(value: nameInput)
}

presenter.name = "Hong"

두 예시에 나온 변경 사항의 가장 큰 차이점은 소스코드의 어디를 수정하였는가 입니다. 첫 번째 예시는 ScreenPresenter에 기능을 추가하였고, 두 번째 예시는 ScreenPresenter를 사용하는 사용자의 코드를 수정하였습니다. 만약 ScreenPresenter가 별도의 모듈에 포함되어 있는 코드라면 첫 번째 예시는 해당 모듈을 다시 컴파일해야 합니다. 반면, 두 번째 예시에서는 ScreenPresenter의 변경은 없기 때문에 해당 모듈을 다시 컴파일하지 않아도 됩니다.

제어권 관점에서의 Library와 Framework

라이브러리와 프레임워크는 메소드와 클래스를 묶은 바이너리 관점에서 큰 차이가 없는 용어로 사용됩니다. 하지만, 제어권 관점에서 두 가지 용어는 명확히 구분됩니다.

애플 생태계의 개발 환경에서 라이브러리와 프레임워크는 리소스 포함 여부에 따라 구분되기도 합니다. 이에 대한 자세한 내용은 Framework 이해하기에서 확인하실 수 있습니다.


Framework에 code PlugIn을 수행하는 방법

  1. 클로저를 활용한다.
  2. Delegate를 활용한다.(event subscribing)

대표적인 예시 - UIViewController의 오버라이딩 메소드, delegation

SideNote

Wikipedia에서는 Flow of Control을 expression의 evaluation, statement의 수행, 함수 호출 등의 순서라고 정의하고 있습니다.

In computer science, control flow (or flow of control) is the order in which individual statements, instructions or function calls of an imperative program are executed or evaluated.

expression과 statement에 대한 것은 이전에 제가 작성했던 Expression과 Statement을 참고하시면 좋습니다.

제어의 흐름은 조건문, 반복문을 통해서 변경됩니다. 그래서 Swift Programming Language와 같은 레퍼런스에서는 Control Flow라는 챕터명을 통해서 흔히 조건문, 반복문이라는 명칭으로 불리는 if, switch, for, while 등의 statement를 설명하기도 합니다.

Swift provides a variety of control flow statements. These include while loops to perform a task multiple times; if, guard, and switch statements to execute different branches of code based on certain conditions; and statements such as break and continue to transfer the flow of execution to another point in your code.

hcn1519 commented 3 years ago

Inversion of Control Containers and the Dependency Injection pattern

마틴 파울러

Component와 Service에 대한 정의

Component

Service

The main difference is that I expect a component to be used locally (think jar file, assembly, dll, or a source import). A service will be used remotely through some remote interface, either synchronous or asynchronous

A Naive Example

Core Problem

Inversion of Control

What aspect of control are they inverting?

Forms of Dependency Injection