여느 개발에서 마주하는 문제들과 같이, 패키지 구조에 대한 설계 역시 패키지 구조를 어떻게 잡는가 에 대한 명확한 가이드 라인은 없는 것 같다.
최근(아직까지) 수행중인 인턴 프로젝트의 구조를 잡는 과정에서 우왕좌왕 하다보니 패키지 구조마저 우왕좌왕 한 구조로 만들어져 있었다.
한 눈에 들어오지 않는 구조, 새로운 클래스를 만들었을 때 어떤 패키지에 넣어야 할지 고민하게 되는 구조가 탄생 함에 따라 패키지 구조를 설계할 때 고려 해 볼 원칙들을 다시 한 번 정리해 보았다.
이런 원칙들을 정리하며, 이번 프로젝트의 패키지 구조도 어떻게 잡아 볼지에 대한 개관을 얻고자 했다.
패키지 원칙 (package principle)
(위키피디아)
- 큰 시스템에서 클래스들을 조직화 하는 방법
- 목적 : 좀 더 정돈된 시스템을 통해 관리, 유지보수하기 좋게 만들기 위함
패키지 원칙을 잘 세웠을 때 얻을 수 있는 것
- package cohesion( 패키지 응집력)
- 패키지의 응집력이 높다면, 새로운 클래스를 만들 때, 해당 클래스가 어떤 패키지에 들어가야 하는지 빠르게 이해하고 적용할 수 있다. ( 코드 응집력 같은 존재다 )
- package coupling( 패키지 결합도)
- 이 패키지들이 서로 어떤 관계를 갖는지 이해하는데 도움을 준다.
- 의존 구조 를 나타낼 수 있다. 이를 통해 전체 클래스 및 패키지 들의 전체 구조에 대한 통찰력을 가질 수 있다.
가장 대략적 이지만 중요한 이야기다.
Robert C.Marting 의 OOD 와 관련된 아티클을 통해 아주 조금만 더 한 발자국 나간 이야기를 살펴보자.
OOD 와 패키지 원칙과 관련한 밥 아저씨의 요약된 아티클 하나
( 다음은 아티클 을 그대로 번역한 이야기다 )
객체지향 디자인이란 무엇일까? 이게 뭐고 장점은 뭐고 이로 인한 비용은 얼마나 드는 것일까?
대부분의 개발자들이 객체지향 언어를 사용하고 있는 요즘 시대에 이런 질문은 바보같아 보일지도 모른다.
하지만 적어도 로버트 C 마틴 에겐 이런 질문이 중요하다 생각되었다고 한다.
객체지향 언어를 사용하면서도 “왜 사용하는지, 이걸 사용하면서 어떻게 해야 그 이점을 뽑아 낼 수 있는지” 를 모르는 사람이 많기 때문이다.
소프트웨어 산업에서 일어나온 여러 혁명들 중 이 두가지는 정말 혁명 적 이었고, 당연하게 여길 정도로 우리의 사고에 스며들었다.
- Structured Programming
- 객체지향 프로그래밍
대부분의 주류 언어들은 이 두 분야에 큰 영향을 받았다.
- 대부분의 주류 언어들은 goto 문 같은 것이 없기 때문에 , structured programming 에서 배척하는 것을 아주 잘 따르고 있는 것 처럼 보인다.
- 또한 대부분이 클래스 기반 이며 클래스 내에 있지 않은 함수나 변수를 지원하지 않으므로, 객체지향 프로그래밍을 따르는 것 처럼 보인다.
그러다보니 이런 언어들을 통해 작성된 프로그램들은 structured , 객체지향 적인 것 처럼 보인다.
보이는 모습을 그렇게.. 속이는 건 가능하다. 쉽다 쉬워~
오늘날의 개발자들은, 자기들이 사용하는 언어가 파생된 분야의 기초 원칙에 대해 알고 있지 않은 경우가 많다.
이 글에서는 객체지향 프로그래밍의 원칙들에 대해 말해 볼 것이다.
1995 년에 저자가 쓴 아티클 에서는 OOD 의 원칙들에 대해 기술 했다. 우리가 흔히들 알고 있는 SOLID 원칙이 여기에 포함된다.
이 원칙들은 “해결할 문제 에 대한 개념화(conceptualization)“ 보다는, “OOD 에서의 의존성 관리 측면” 에 대한 것이었다. (개념을 모델링 하는 것 보다는, 의존성을 관리하는 측면에 초점을 둔 원칙들이었다고 한다!!)
의존성 관리는 정말 너무나도 중요하다. 레거시 코드를 볼 때 마다 정말 엄청난… 최악의 의존성 관리 의 결과를 경험해 볼 수 있을 것이다.
형편없는 의존성 관리는, 변경하기 어렵고, 유연하지 못한 코드를 만들어낸다. 서로 얽히고 얽혀 재사용이 힘든 코드가 되는 것이다.
반면 의존성이 훌륭하게 관리 되었다면, 코드는 유연하며 재사용 가능하다.
따라서 의존성 관리를 비롯해 앞으로 보게 될 이 원칙들은 개발자들이 갈망하는 무언가를 만드는데 기반이 될 것이다.
- 먼저, 클래스 디자인에 대한 5가지 원칙이다.
- SRP : 변경할 이유는 한 가지 여야 한다.
- OCP : 클래스를 변경하지 않으면서도, 클래스의 behavior 를 확장할 수 있어야 한다.
- LSP : 파생 클래스는 , base class 를 대체 가능해야 한다.
- ISP (Interface Segregation Principle) : 클라이언트별로 세분화된 인터페이스를 만들도록 한다.
- 기능별로 인터페이스들을 분리 해 두는 것 같은 ( 어떤 기능을 추가 할 때 마다, 이 클래스가 구현하는 인터페이스를 추가하는 식으로 )
- DIP : 추상화에 의존하자. 구체적인 것에 의존하지 말자.
- 다음은, 패키지에 대한 6가지 원칙이다. (이 말은 와닿지 않아 해석이 안되었다 🥲🙄 ) In this context a package is a binary deliverable like a .jar file, or a dll as opposed to a namespace like a java package or a C++ namespace.
- 먼저 package cohesion 과 관련된 원칙 세 가지 로, 어떤 것을 패키지에 넣어야 할 지에 대한 것이다.
- REP(The Release Reuse Equivalency 원칙 ) : 재사용 단위(granule) 는 release 단위(granule) 다.
- CCR(Common Closure 원칙) : 함께 변경되는 클래스들은 함께 패키징되어야 한다.
- CRP(Common Reuse 원칙) : 함께 사용되는 클래스들은 함께 패키징 되어야 한다.
- 다음 세 원칙들은, 패키지들 사이의 결합도(coupling) 에 대한 것이다. 또한 시스템의 패키지 구조를 평가하는 metrics 에 대한 것이기도 하다.
- ADP(Acyclic Dependencies 원칙 ) : 패키지들 사이의 의존성 그래프 에는 cycle 이 존재해선 안된다.
- SDP (Stable Dependencies 원칙 ) : 의존성 방향은 안정적이어야 한다. (여기서 stability 의 의미가 무엇인지 까지는 잘 모르겠다 )
- SAP(Stable Abstractions 원칙 ) : 추상화는 안정성을 높여준다. ( 마찬가지로 stability ..)
- 먼저 package cohesion 과 관련된 원칙 세 가지 로, 어떤 것을 패키지에 넣어야 할 지에 대한 것이다.
이에 대해 좀 더 깊이 알아보려면 다음 페이지 를 좀 탐색 해 봐야 할 것 같다.
결론
무지성 으로 개발 하다가
이런 글들을 찾아 읽어보고 다시 고민해서 조금이라도 기존의 것을 변경해가는 것이 중요하다 생각된다.
글을 읽으며 OOD 에 대해서 모르고 있음을 깨닳았다. 뿐만 아니라 단순히 객체지향 원칙 SOLID 라고만 생각하던 것이 '의존성 관리' 를 위해 고안한 원칙이었다는 것도 모르고 있었다.. 시간을 내서 다음 페이지 를 좀 탐색 해 보면 좋을 것 같다.
이번 프로젝트에서는 POJO 라도 활용해보고자 시도하는 과정에서 패키지 구조가 엉망이 되었었는데 이 글을 바탕으로 조금씩 변경했다.
흔히들 많이 작성하는 프로젝트를 계층형 아키텍쳐 로 개발 하더라도, 의존성 만이라도 잘 신 경쓴 패키지 구조를 만든다면 반쯤 성공 아닌가 라는 마음으로 임하고 있다.
아키텍쳐를 바꿀 때면 패키지에 대한 고민은 더욱 최상으로 치닫지 않을까… 🥲
패키지 구조를 잡는 것도 많은 연습이 필요한 것 같다.
참조
https://en.wikipedia.org/wiki/Package_principles https://web.archive.org/web/20220121055640/butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod
https://condor.depaul.edu/dmumaugh/OOT/Design-Principles/