블로그 이미지
소프트웨어 개발 경험을 공유하고 싶은 재밌게 사는 소프트웨어 엔지니어입니다^^

카테고리

Chungha Story (41)
Agile Experience (22)
My Family (0)
Life Style (7)
Programming (8)
Android (2)
Total
Today
Yesterday

달력

« » 2024.3
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31

최근에 올라온 글

최근에 달린 댓글

새로운 업무를 받음

얼마전 오래된 시스템(legacy system)에 새로운 플랫폼의 부가(extension) 모듈을 이식하라는 업무를 할당 받았습니다. 쉽게 생각하면 새로운 플랫폼은 유연성을 크게 가질수 있도록 작성되었으니 쉽게 이식 될 수 있다고 오해 할 수 있습니다. 저는 먼저 오래된 시스템과 새로운 플랫폼의 의존성을 확인하였습니다. 오래된 시스템의 일부 코드를 수정(modification)하는 것은 일단 허용하기로 하였습니다. 하지만 새로운 플랫폼의 부가 모듈을 바로(쉽고 빠르게 수정없이) 이식하기에는 문제가 있었습니다. 

무엇이 문제였을까

새로운 플랫폼의 부가 모듈은 하위 모듈(base library)에 의존성(dependency)을 가지고 있었습니다. 일반적으로 계층 기반(layer based)으로 모듈을 작성할 때 하위 계층에서 상위 계층을 직접 참조하는 것은 원칙적으로 불허 하지만, 그 반대의 경우는 허 하는 경우가 많습니다. 간단히 생각해보면 이는 크게 문제가 되지 않을 수 있지만, 상위 모듈이 하위 모듈에 의존하기 때문에 상위 모듈의 유연성, 재사용성은 매우 떨어지게 됩니다.

해결 방법

이와 같은 상황을 해결하는 방법은 다음과 같습니다.
  1. 오래된 시스템에 하위 계층까지 모두 이식한다.
  2. 새로운 플랫폼의 부가모듈을 컴파일 옵션으로 시스템에 따라 다른 하위 레이어를 사용하도록 수정한다.
  3. 새로운 플랫폼의 부가모듈을 복사하여 오래된 시스템에 맞도록 수정한다.
  4. 새로운 플랫품의 부가모듈이 가지는 하위 계층에 대한 의존성을 제거한다.

의존성을 역전시키자

위의 문제에서 하위 계층에 대한 의존성을 제거하는 것(해결방법 4)을 객체지향 디자인에서는 의존성 역전 원칙(The Dependency Inversion Principal)이라고 합니다.
High level modules should not depend upon low level modules. Both should depend upon abstractions.
Abstractions should not depend upon details. Details should depend upon abstractions.
이 원칙은 상위모듈은 하위 모듈의 추상 클래스(또는 인터페이스)에만 의존함으로써 구체적인 구현에 대한 의존성은 갖지 않도록 하는 것입니다. 
위의 상황에서 의존성 문제가 되는 하위 모듈 중의 하나는 타이머입니다. 만약에 해결방법 1로 해결한다면 다음과 같은 그림처럼 작업이 이루어질 것입니다. 즉, 오래된 시스템에도 TimerB가 존재하지만, TimerA까지 이식함으로써 부가 모듈을 이식 가능하게 합니다. 이는 타이머 기능의 중복을 만들게 됩니다. 때에 따라서 TimerA의 의존성 때문에 다른 모듈들이 줄줄이 딸려가는 일이 생길수도 있습니다.
해결방법 2로 하게 되면 모듈의 구현 복잡도는 증가하게 될 것이며, 해결방법 3은 새로운 소스코드 브랜치가 생기게 되어 관리에 대한 부담이 증가하게 됩니다.
마지막으로 해결방법 4로 이 문제를 해결하면 다음과 같은 그림처럼 작업이 이루어 질 것입니다.
즉, 부가모듈은 ITimer라는 인터페이스에만 의존하게 되고 새로운 플랫폼과 오래된 시스템은 각각 해당 인터페이스를 Adapter Pattern을 이용하여 TimerA, TimerB로 구현하면 됩니다. 결과적으로 부가 모듈만 깔끔하게 이식할 수 있습니다.
저는 이 문제를 해결방법 4를 이용하여 해결했습니다. 제가 정의한 추상클래스는 다음과 같습니다.
IMpTimerListener는 타이머의 이벤트를 받기 위한 추상클래스이며, IMpTimer는 타이머 등록 및 해제를 위한 추상클래스입니다.

회고(retrospective)

사실, 이 업무를 진행하면서 모든 의존성을 위와 같은 방법으로 해결하지는 못했습니다. 기존 구현에 따라 해결방법 2를 사용한 경우도 있었습니다. (Define으로 구현되어 있어서 불가피 했음) 하지만 이러한 리팩토링을 통해 위의 부가모듈의 의존성은 상당히 사라지게 되었고 재사용성은 크게 증가하게 되었습니다. (추후 재사용 요구사항이 예상되는 모듈이었습니다.) 모든 모듈에 대해서 재사용성에 포커스를 두는 것은 over-engineering의 가능성이 있습니다. 하지만 이와 같이 재사용 이슈가 예상되는 모듈에 대해서는 의존성을 철저히 관리함으로써 추후 유지보수 업무를 줄일 수 있을 것입니다.^^ 감사합니다.

Posted by 윤청하
, |