SOLID 제대로 이해하기(1) - Dependency Inversion
객체 지향 설계의 5가지 원칙, SOLID 중에서 Dependency Inversion 에 대해 제대로 이해하기
2/20/2024, 1:01:00 AM
SOLID는 객체 지향 설계를 보다 이해하기 쉽고, 유연하며, 유지보수가 쉽도록 만들기 위한 5가지 설계 원칙을 지칭하는 약어이다. - wiki
학부생 시절부터 지겹게 봐온 용어지만 정작 이 원칙이 실제로 무엇을 하라고 하는 건지, 또 무엇을 하지 말라고 하는 건지에 대해 제대로 이해하고 있지 못하고 있다는 생각이 들어서 다시 정리해본다.
의존성을 역전… 뭐라고..?
첫 주인공은 SOLID의 마지막인 Dependency inversion principle(이하 DIP) 이다.
DIP 의 설명은 매우 간단 명료하고 이해하기 쉽다.
Depend upon abstractions, not concretes
.
그러나 이것은 SOLID 원칙까지 생각하지 않아도, OOP의 특징만으로 이미 충분히 설명되는 것 같다. (OOP라면 응당 추상화 해야지,, 상속 해야지,, 캡슐화 해야지,,)
추상화에 의존하는 것이 의존성과 어떤 관계가 있는건지, 어떻게 의존성이 역전된다는 건지 이것만으로는 이해할 수 없다.
실제로, 어떤 클래스가 추상화에 의존한다 하더라도, 그 클래스가 의존하는 대상이 구체화에서 추상화로 바뀌는 것 뿐이지, 의존하는 방향 자체가 바뀌는 것은 아니다.
DIP는 모듈간의 관계에 대한 것
결론부터 이야기하면, DIP가 하고자 하는 말은 모듈간의 관계를 재정립하라는 것이며, 이를 통해 달성하고자 하는 목표는 모듈간의 결합도를 느슨하게 하는 것이다.
이를 위한 방법이 추상화에 의존하는 것 이다.
위 다이어그램은 DIP를 적용하지 않은, 흔히 보이는 모듈 간의 의존성 관계를 보여준다.
이러한 구조에서는 최상위 모듈인 Coffee Module의 재사용성이 크게 떨어진다.
Cafe 가 Worker 모듈의 Handsome Worker 의 구현체를 직접 의존하고 있기 때문에, Worker 만 바꾼 새로운 Cafe 를 만들기 위해선 Cafe_B 를 또 다시 구현해야 한다.
상상할 수 있듯이 새로운 Coffee 를 추가할때는 더 큰 작업이 필요해진다.
안타깝게도 Cafe가 변하는 빈도보다 Coffee 가 변하는 빈도가 훨씬 잦다.
이는 이 예시에서 뿐만 아니라 많은 현실에서도 그렇다.
상위 계층보다는 하위 계층의 변화가 자주 일어난다.
상위 계층은 좀 더 목적에 가깝고, 하위 계층은 수단과 방법에 가깝다.
우리가 어플리케이션을 통해 제공하고자 하는 궁극적인 목적은 크게 변하지 않지만, 그것에 도달하는 수단과 방법은 매우 다양할 수 있다.
그러나 위와 같은 구조에서는 하위 모듈의 변화가 상위 모듈의 변화를 야기시킨다. SOLID 를 제창한 마틴은 DIP에 대해 다음과 같이 말했다.
High-level modules should not import anything from low-level modules. Both should depend on abstractions (e.g., interfaces).
자, 이제 마틴이 시키는대로 해보자! 상위 모듈에서는 하위 모듈의 그 무엇도 의존하지 않으면서, 추상화에 의존하도록 만들어보자.
드디어 의존성이 역전되는 모습을 보게 되었다.
Cafe 는 더이상 Worker 구현체를 직접 참조하지 않는다.
심지어는 Worker 모듈의 그 무엇도 참조하지 않는다.
Cafe 는 Cafe 모듈 내에 정의된 ‘How to Work in Cafe’ 인터페이스만을 참조한다.
대신 Worker 모듈에서 Cafe 모듈의 인터페이스를 구현한다.
이전 구조에서는 의존관계가 상위 계층에서 하위 계층으로, top-to-bottom 으로 형성되었다.
DIP를 충실히 따르자 이러한 의존관계는 하위 계층에서 상위 계층으로, bottom-to-top 으로 역전되었다.
주객전도를 막아라
이로써 상위 모듈은 하위 모듈의 변경으로부터 자유로워졌다.
모듈간의 참조도 훨씬 간결해졌다.
DIP는 많은 사람들이 객체 지향 프로그래밍을 하면서 가지게 되는 생각의 흐름을 역전시킨다.
상위 계층이 하위 계층의 메서드를 찾아보고 필요한 것을 호출하는게 아니다.
상위 계층은 해당 계층에서 필요한 기능에 대한 명세를 스스로 정의하여야 한다.
하위 계층이 상위 계층에서 정의된 명세에 따라 기능을 구현할 책임을 가지게 되는 것이다.
Worker가 Cafe를 지배하게 두지 말라. Cafe가 Worker들의 일하는 방식을 정의한다.
댓글
* 작성 이후에 수정/삭제 할 수 없어요!
아직 작성된 댓글이 없습니다.