Dependency를 관리하는 방법
일전에 Dependency에 대한 고찰이라는 글로, Dependency의 종류와 xDepend 툴들을 소개한 적이 있습니다.
이번 POST는 윗 글의 연장선상으로 Dependency 를 해결하기 위한 올바른 설계 방법 몇가지를 소개하고자 합니다.
물론 재미난(?) 그래프로 여러분의 시스템의 Depedency를 파악하는 것을 보여드리고 싶지만.. 모든 일에는 순서가 있는 법. 여러분이 와 닿는 그림과 코드로 간단히 설명드리도록 하겠습니다.
Dependency가 없는 상태로 시스템을 구축한다는 것은 불가능합니다. 재사용의 미덕이 바로 Dependency의 또다른 이름이기도 하죠.
어떻게 하면 Dependency를 잘 관리할수 있을까? 그 해답을 제시해주신 아키텍트를 소개하고자 합니다.
그 분은 바로 Object Mentor의 Robert C. Martin 입니다. Clean Code의 저자로써 알려져 있지만, 사실 이것보다 이름을 더 크게 알리게 한 주역은 패턴의 5가지 법칙(OCP, DIP, LIP, ISP, SRP)입니다.
그런데 이 5원칙의 빛에 가려 숨겨진 Principle이 하나 있는데요. 이름하여 패키지 구조의 원칙들 (Principles of Package Architecture) 입니다.
이 논문에서 Dependency를 깨거나 완화하는 방법들을 여러분에게 소개하고자 합니다.
1단계: Circular Depedency를 무너 뜨려라
Circular Dependency는 패키지 소프트웨어를 만드는 구조에서 꼭 피해야 되는 구조입니다. 바로 Change Propagation (변화 전파)이 체인을 이루어 구성될수 있기 때문입니다.
여러분의 모듈중 일부분에 변화를 가하면, 다른 것들이 연쇄적으로 체인과 같이 묶여 변화를 한다면 어떻게 될까요? 생각만 해도 무시무시한 일이죠. 결국 그래프를 이루는 모든 모듈에 대해서 검증(테스팅)을 해야 하는 문제가 발생합니다.
Robert C. Martin은 Circular Dependency를 끊는 방법으로 완충작용을 해줄 새로운 Package 생성 또는 Interface 를 통해 변화를 상쇄시키는 방법을권하고 있습니다.
개발자라면 누구나, Try.. Catch문을 걸어서 발생한 오류를 화면에 MessageBox로 뛰워 본 경험이 있을 겁니다. 이렇게 되면 바로 위 그림과 같은 Circular Dependency가 발생하게 됩니다.
이 그림은 통신 모듈에 필요한 에러사항들을 GUI 관련 모듈을 통해 출력하다 보니, 이 세가지가 연관성을 갖게 되는 것입니다. 이러한 관계를 끊기 위해서 Robert C. Martin은 아래와 같이 새로운 Package를 만드는 것을 권고하고 있습니다.
시스템에서 사용하는 모든 메세지(Error 메세지를 포함)를 관리하는 Manager를 별도로 두어, GUI와 통신 모듈이 한 방향으로 Dependency를 구성해 Circular Dependency를 끊어 버린 경우입니다.
이런 상황에서는 Log4X (NET, J)처럼 Attribute(AOP) 이용해 기존 모듈에 영향을 최소화하거나, Listener를 이용해 IoC를 구성하는 것도 좋은 방법입니다. (IoC는 뒷부분에서 언급하도록 하죠)
또 다른 형태의 Circular Dependency를 보도록 합시다.
이 것은 두 패키지를 구성하는 내부 모듈들간에 간접적인 Circular Dependency가 생겼습니다. 하지만 Interface를 통해서 완충 장치를 두어 해결한 경우입니다. 이건 그림을 보니 다 아실것이라 생각이 들어서 패스하도록 하죠 🙂
2 단계: 무거운 Dependency를 깨뜨리는 무기, IoC (Inversion of Control)
무거운 Dependency라고 해서 읽으신 분이 의아해 하셨을 겁니다. 이 의미는 모듈간에 강력한 결합으로 인하여 쉽게 테스트하거나 확장하기 어려운 상황에 무거운(Heavy) Dependency라고 합니다.
또는 전에 언급했던 Implementation Dependency에서 특정 모듈이 없으면 아예 돌아가지도 않는 상황을 말하는 Hard Dependency라고 봐도 무방합니다.
// your API public class Tracer { MessageQueue mq = new MessageQueue(…); public void Trace(string message){ mq.Send(message); } } // your customer’s program that is hard to test Tracer tracer = new Tracer(); public void ProcessOrder(Order order){ tracer.Trace(order.Id); … }
이 소스 코드는 Tracer를 MessageQueue 로만 데이터를 추적할수 있기 때문에, Tracing이 어렵고 확장성 역시 떨어집니다. MessageQueue에서 다른 형태로 출력을 하기 위해서는 결국 Tracer를 수정해야 되는 문제가 발생하죠.
그래서 IoC (Inversion of Control)을 적용하여, 다양한 방법으로 데이터를 추적할수 잇는 TraceListner를 아래와 같이 설계를 해봅시다.
// your better API using IoC (Inversion Of Control) public abstract class TraceListener { public abstract void Trace(string message); } public class Tracer { TraceListener listener; public Tracer(TraceListener listener){ this.listener = listener; } public void Trace(string message){ listener.Trace(message); } } // Dependency Injection Tracer tracer = new Tracer(new FileListener()); public void ProcessOrder(Order order){ tracer.Trace(order.Id); … }
소스에서 보이는 IoC의 핵심 키워드인 XXXListenr(TraceListener)를 통해서 MessageQueue외에도 File, XML과 같은 다양한 형태로 출력을 할수 있을뿐만 아니라, 확장성과 테스팅이 좀더 용이 하게 되었습니다.
3단계: NINJA가 도와 드려요! 한발더 Dependency Injection (NInject)
IoC를 이용하여 좀더 변화에 유연하며 확장 가능한 소스코드가 생성되었습니다.
하지만 FileListener를 XXXListener로 변경을 위해서는 소스 코드를 변경하거나 Metadata 형식 (Component Configurator)를 직접 구축해야 합니다.
이러한 문제점들을 한방에 해결해 줄수 있는 정보들을 실시간을 삽입,삭제 변경할수 있는 Dependency Injection Container가 나왔습니다.
Container를 통해서 이제 우리는 Dependency의 제어가 한결 더 쉬워졌습니다.
위 의 예를 잠시 이용해 볼까요?
// Dependency Injection Tracer tracer = new Tracer(new FileListener()); public void ProcessOrder(Order order){ tracer.Trace(order.Id); … // 이 부분이 아래와 같이 변합니다. // Dependency Injection Container가 추가됨으로써, // 확장성과 테스팅 하기가 훨씬 좋아집니다. Tracer tracer = container.Resolve<Tracer>(); public void ProcessOrder(Order order){ tracer.Trace(order.Id); … }
마침 Open Source Container인 NInject를 사용할수 있는 데모를 찍어놓은 동영상과 샘플 소스코드에 대한 포스트, 약식 정리한 포스트가 있으니 참고하시길 바랍니다. (현재 NInject의 공식 개발자 가이드 문서가 없음)
NInject 외에도 autofac, Castle Windsor, PicoContainer.NET, Spring.NET, StructureMap, Unity 와 같이 .NET을 위한 다양한 Container가 있으니 적극 활용하시기리 권해드립니다.
추후 Package Architect를 위한 5원칙과 Dependency Injection Container에 대한 포스트를 여러분에게 해 드릴 것을 약속하며, 이번 포스트를 마무리합니다.
글 재미있게 읽었습니다. 예전에 프로젝트간 Circular Dependency 때문에 컴파일도 안돼서 고생하던 기억이 다시 나네요.
권남 님>>
재미있었다니 저역시 기쁘네요. 🙂
사실 이런 글을 재미읽게 읽어주실 분이 매우 드물거든요 🙂
ㅎㅎㅎ
건강하시고, 상쾌한 한주 되세요 !!
Spring 2판을 보면서 공부한 IoC, DI를 다시금 떠올리게 한 포스팅이네요. ^_^
닷넷 스프링도 있었군요.
쟌나비님 >>
그렇죠, 솔직히 이 개념들은 예전부터 있었지만, 잘 다듬고 만든것은 Spring이라고 생각합니다.
.NET 쪽도 그걸 흡수한 것이죠 :).
그럼 쟌나비님도 상쾌한 한주 되세요!!
제가 사용하는 Pascal에서도 초보자에겐 항상 Circular Dependency가 문제였었죠 ^^ 요즘엔 좀 극복했습니다만….
프레임웍 데이 때 강좌 잘 들었습니다.
오늘 글도 전부 이해하진 못했지만 잘 보았구요.
이래저래 감사만 드리네요.
덕분에 베타리딩 일원이 되어서 좋은 분들도 많이 뵙게 되었고!
행복한 하루 보내세요 ^^
레몬에이드 님>>
안녕하세요 아 세미나에도 오셨군요.
블로그에서 사진을 보았습니다. 🙂
저희 역시 많은 도움 부탁드립니다. 베타리딩 잘 부탁드리구요.
나중에 Framework Design Guidelines나 POSA2 때도 ㅎㅎㅎ 홍보및 베타리딩 잘 부탁 드려요.
먼길 방문해 주셔서 감사합니다. 🙂
안녕하세요~ 영수님~
좋은 글 잘보고 갑니다~
항상 건강하시구요~ 남편 2.0 화이팅입니다. 🙂
장선진 님>>
안녕하세요 선진님.
또 이렇게 방문해주시니 감사해요 🙂
이미 Java 진영에서는 DI Container가 널리 알려져 있어서, 그리 새로운 것이 아니겠지만, .NET 쪽에서는 아직 그리 알려져 있는 편이 아니라서 posting 했습니다.
부족한 글 좋게 봐 주셔서 감사해요 🙂
[…] 설명을 듣고 싶은 분은 필자의 블로그(종속성을 관리하는 방법 – https://arload.wordpress.com/2008/12/07/dependency_managment/)를 방문하길 […]
깔끔하게 정리해 주시니, 금방 이해가 갑니다. 게다가 여러 종류의 DI Container 정보도 얻고 갑니다. 감사합니다. =:)
zmeun님 방문해 주셔서 감사합니다.
부족한 글이지만 좋게 평해주셔서 정말 감사합니다.
저도 블로그에 가셔 Feature Creep이라는 재미난 글을 보았습니다.
스물 스물 추가되는 기능이라. 🙂 재미있네요.
저 역시도 스물 스물 추가되는 기능때문에 곤혹을 치르고 있습니다.
무엇이 변하는 것인지 안 변하는 것인지. 참.. 예측 하기가 힘드네요 🙂
그럼 건승을 바랍니다. 좋은 주말 되세요 🙂
넵.. arload님도 좋은 주말 보내시기 바랍니다. ^^
잘 읽었습니다~님이 직접 개발한 거 뭐 없습니까?~닌자라니요?~~일뽄 넘들보다~~차라리 중국에서 개발된거 뭐 예로 들꺼 없습니까?~~걔네들이~인터넷 뱅킹도 뚫어버릴 정도로 강력하자나요?~~
잘 읽었습니다. 닌자라? 일본쪽보다 차라리 중국쪽에서 나온 소스 없습니까 중국애들이 인터넷 뱅킹도 뚫어버릴 정도로 전자회로 자체를 잘 이해하고 있는 듯 한데
안녕하세요 🙂 현우님.
저도 우리나라에서 주가 되어 만든 공개된 범용적인 프레임워크가 없어서 안타깝습니다.
T_T
거기다 미국이 바라보는 일본이 동양의 신비한 나라로 인식되어서,
어느정도 마겟팅에도 많이 활용되고 있는 상황입니다.
문화적 마케팅 + 우리 개발자의실력이 좀더 발전하면 되지 않을까요
저도 열심히 노력해 보도록 하겠습니다.
[…] 종류를 설명한 Dependency 대한 고찰 과 Dependency를 해결하는 방법을 소개한 Dependency 를 관리하는 방법 사이에 있는 포스트로, 바로 Dependency가 어디에 있는지 […]
좋은정보 감사합니다. 🙂
[…] 종류를 설명한 Dependency 대한 고찰 과 Dependency를 해결하는 방법을 소개한 Dependency 를 관리하는 방법 사이에 있는 포스트로, 바로 Dependency가 어디에 있는지 […]
[…] of Package Architecture) 을 읽어보시거나, 또는 저의 이전 포스트인 Dependency를 관리하는 방안 을 읽어보시길 바랍니다. 그림 1. Bob 삼촌의 – Instability , Abstractness […]
[…] 의존성 깨기 : https://arload.wordpress.com/2008/12/07/dependency_managment/ […]