[23.12.12 SeSAC 수업 내용 정리]
의존성 주입 쉽게 이해하기!
브랜 주방장이 브랜 반점이라는 음식점을 열었고, 휴님은 점심 식사로 브랜 반점의 메뉴를 먹는다.
휴님 → 브랜반점 의존관계
브랜반점 → 브랜 의존관계
하위 모듈인 브랜반점에서 메서드 이름을 변경하는 순간 상위 모듈인 휴님 클래스에서 오류가 발생한다.
하위 모듈인 브랜 클래스에서 메서드 변경 시 브랜 클래스를 사용하고 있는 모든 클래스에서 오류가 발생한다.
오류를 해결하기 위해 해당 클래스를 사용하고 있는 상위 모듈에서 변경 사항을 수정해야 한다.
B가 변화했을 때, A에게 영향을 미친다. ⇒ A가 B를 의존한다.
상위 모듈에서 의존하는 인스턴스를 변경했을 때 상위 모듈 내부에서 오류가 발생한다.
휴님(상위 모듈) → 브랜반점(하위모듈) 형태로 의존관계가 형성되어 있기 때문에 브랜반점에서의 코드 변화가 휴님에게 영향을 미치는 것을 확인할 수 있다.
⇒ 하위 모듈에서의 코드 변화가 상위 모듈에게 영향을 미치는 것을 확인할 수 있다.
강한 의존 관계가 형성되면 코드를 유지보수하기 어려워진다.
하위 모듈의 변화가 상위모듈에 영향을 미치지 않게 하려면?
즉, 중국집이 바뀌어도, 중국집의 주인장이 바뀌어도 휴님 코드에는 영향이 없으려면?
⇒ 의존성 분리, 프로토콜 사용
✔️ 의존성 분리 (프로토콜)
의존성을 분리하기 위해 프로토콜을 따르도록 구성해보자.
구현체가 아닌 추상적인 형태에 의존하도록 하여 의존성을 분리한다.
브랜반점, 코종반점은 중국집 프로토콜을 따르도록 구성
상위 모듈에서 인스턴스를 변경하여도 영향을 받지 않는다.
휴님 클래스의 중국집 타입은 인스턴스에 따라 변경된다.
중국집 프로퍼티는 브랜반점 타입을 가지고 있는 것을 볼 수 있다.
=> 클래스 내부에 작성된 프로퍼티는 구현체 타입을 가지게 된다.
프로퍼티가 어떤 인스턴스를 갖는지 상관 없도록 프로토콜 타입을 받도록 설정.
⇒ 프로퍼티의 타입이 추상화타입을 따르도록 구성하여 의존 관계를 약하게 만든다.
클래스 내부 프로퍼티에 인스턴스를 생성해주는 것이 아니라 프로토콜 타입을 지정하여 어떠한 인스턴스를 사용하고 변경하여도 영향이 미치지 않도록 한다.
브랜반점과 코종반점이 중국집 프로토콜을 따르도록, 브랜과 코코종은 주방장레시피 프로토콜을 따르도록.
⇒ 구현체가 아닌 추상화에 의존하도록 변경한다.
⇒ 인터페이스(프로토콜)로 의존 관계를 추상화
프로토콜 → 추상화 형태
프로토콜을 따르는 클래스 → 콘크리트 타입
✔️ 의존성 주입
코종 반점의 생성 시점과 사용을 분리
휴님 인스턴스가 생성될 때 init구문을 통해 코종반점 인스턴스를 생성.
휴님 클래스 입장에서는 직접적으로 코종반점 인스턴스를 생성하여 가지고 있지 않게 된다.
⇒ 객체의 생성과 사용의 관심을 분리한다. 즉, 생성자를 통해서 의존성을 주입한다.
휴님 클래스를 사용해야할 때 코종반점 인스턴스를 생성하고 휴님 클래스의 생성자에 주입해준다.
코종 반점의 주인이 변경된다면… 중국집이 변경된다면…
코종반점 주인 타입이 코코종이기 때문에 다른 주인이 들어갈 수가 없다. -> 의존관계가 형성되어 있다.
변경 가능성이 있기 때문에 구체 타입 보다는 추상화된 프로토콜 타입을 지정하여 의존 관계를 추상적이게 만든다.
추상화 된 인터페이스(프로토콜)를 의존하도록 구성
✔️ DI vs DIP
- DI: Dependency Injection(의존 관계 주입)
- DIP: Dependency Inversion Principle(의존 역전 원칙)
이니셜라이저 시점에 주입을 하고, DI를 통해 객체의 생성과 사용을 분리한다.
⇒ DI를 한다고 해서 DIP를 준수하는 것은 아니다.
DIP를 구현하는 기법 중 하나로 DI를 사용할 수 있다.
DIP
객체를 참조해야 할 때 해당 클래스를 직접 참조하는 것이 아니라 그 대상의 상위 요소(프로토콜)를 참조하는 원칙
추상성이 높은 클래스와의 관계를 통해 의존 관계를 약하게 만들어야 한다.
✔️ 정리
구현체가 아닌 인터페이스 추상화에 의존한다.
하위 모듈에서의 코드 변화가 상위 모듈에게 영향을 미치는 것을 확인할 수 있다.
외부 환경에 영향을 받는 코드를 테스트하기 어려우니 Mock 데이터를 통해 프로토콜 코드를 테스트 한다.
구현체가 아닌 인터페이스 기반 추상체를 테스트 하는 것
위와 같은 이유로 테스트 코드를 작성할 때 testable한 코드를 작성해야한다.
testable한 코드를 작성하기 위해 DI를 적용하여 구현하여 추상체를 통해 테스트를 진행해야 한다.
'iOS > Swift' 카테고리의 다른 글
[iOS/Point-Free] 동시성 프로그래밍: OperationQueue, CGD와 Combine (0) | 2024.12.11 |
---|---|
[iOS/Point-Free] 동시성 프로그래밍의 과거 - 스레드 (0) | 2024.11.25 |
[iOS/Swift] 인앱에서 앱스토어 리뷰 팝업 띄우기 (0) | 2024.10.24 |
[Swift] Swift Concurrency async / await (0) | 2024.04.03 |
UserDefaults와 Sandbox System (0) | 2023.08.02 |