I. 유지보수와 확장에 용이한 시스템을 위한, 객체지향 설계 5원칙의 개요
가. 객체지향(Object-Oriented) 설계원칙의 개념
- 코드 작성시 유지보수, 유연성, 확장성을 용이하게 하기 위해 SRP, OCP, LSP, ISP, DIP로 구성된 설계 원칙
→ 시스템에 새로운 요구사항이나 변경이 있을 때 영향도를 최소화하는 설계
나. 객체지향 설계원칙의 필요성
- 잘못 관리된 의존성 때문에 Design Smell 발생하여 유지보수/확장의 어려움 ※ Spaghetti Code
→ 의존성 관리에 대한 가이드 필요
[참고] Design Smell
Rigidity (경직성) |
특정 모듈을 수정하면 다른 모듈을 계속 수정해야 함 |
Fragility (취약성) |
특정 모듈의 수정이 다른 모듈에 문제를 일으킴 |
Immobility (부동성) |
Component를 만들기 어려움, 연관성 없는 모듈과 강하게 연결되어 있음 |
Viscosity (정착성) |
Design에 맞춰 code를 집어 넣지 않고 hooking으로 추가가 더 용이함 |
Needless Complexity |
불필요한 복잡성 |
Needless Repetition |
불필요한 반복 ← Cut & Paste의 과도한 사용 |
Opacity (불투명성) |
제작자의 의도를 알기 어려움 |
[참고] Object-Oriented Design Principles
- 구현이 아닌 인터페이스에 맞춰서 프로그램해라. Program to interfaces, not implementations
- 클래스 상속보다는 구성을 활용해라. Favor object composition over class inheritance
- Application에서 달라지는 부분을 찾아 내어 분리해라. Encapsulation what varies
- 상호작용을 하는 객체 간에는 가능하면 느슨하게 결합하는 design을 사용해라.
Strive for loosely couple design between that interact
- SOLID principles by R.C. Martin
II. 객체지향 설계의 5원칙의 주요 내용 및 원칙별 상세내용
가. 객체지향 설계의 5원칙의 주요 내용
원칙 |
설명 |
역할 |
단일 책임 원칙 |
- Single Response Principle - 객체는 하나의 책임만을 맡아야 한다. - 하나의 클래스는 단일 역할 및 책임만 수행 |
변화 적응도 및 유지보수성 향상 |
개방 폐쇄 원칙 |
- Open Closed Principle - 확장에는 Open, 수정에는 Close 되어야 한다. |
기존 코드 변화없이 확장으로 코드 변경 지향 |
리스코프 치환 원칙 |
- Liskov Substitution Principle - 하위 클래스 및 타입들은 상위 타입들이 사용되는 곳에 대체 가능 - 자식들은 부모 타입들이 사용되는 곳에 대체되어 사용될 수 있어야 함 |
클래스 생성 목적에 맞게 설계하기 때문에 상/하위 클래스의 호환성 향상 |
인터페이스 분리 원칙 |
- Interface Segregation Principle - 클라이언트는 자신이 사용하지 않는 메소드에 의존 관계를 맺으면 안된다 - 클래스가 다른 클래스에 종속될 때, 최소한의 인터페이스만을 사용 |
클래스가 사용하지 않는 불필요한 기능의 구현을 방지 |
의존성 역전 원칙 |
- Dependency Inversion Principle - 추상화 된 것에 의존하게 만들고, 구체 클래스에 의존하지 않도록 한다. - 높은 레벨의 모듈은 낮은 레벨의 모듈을 의존하지 않는다는 원칙 - 낮은 레벨의 구현 클래스에 의존성을 제거하여 낮은 결함도 유지 |
추상화된 클래스에 의존하기 때문에 확장성이 높아짐 |
나. 단일책임의 원칙 (SRP : Single Responsibility Principle)
구분 |
설명 |
정의 |
- 코드를 모듈화 방법을 결정하는 핵심원칙 (높은 응집도, 낮은 결합도) - 시스템의 모든 객체는 하나의 책임만을 가지며, 객체가 제공하는 모든 서비스는 그 하나 만의 책임만을 수행해야 한다는 설계 원칙 |
목적 |
- 변경 해야할 부분을 하나의 Class로 처리하여 유지보수를 용이하게 함 1) 낮은 결합도 추구: 모듈간의 연관 관계를 낮춰 변경 시 타 모듈에 영향을 주지 않음 2) 높은 응집도 추구: 연관된 기능들을 모아 구현하여 유지보수를 용이하게 함 ※ SRP 위반 시, 변경시 해당 부분을 찾기 어렵고, 누락하고 작업하기 쉬움 |
개념도 |
다수책임 수행 단일책임 수행 |
고려 사항 |
- 책임을 억지로 나누지 말것 (책임을 수정의 단위로 해석하면 용이) ※ 산탄총 수술 (Shotgun Surgery) = 기능 산재 - 변경을 할 때 마다 많은 클래스를 조금씩 수정해야 하는 경우, 변경 시 해당 부분을 찾기 어렵고 누락하고 작업하기 쉬움. - Move Method, Move Field를 사용하여 변경해야 할 부분을 하나의 Class로 처리 필요 |
예시 |
Shopping 클래스에서 Member에 대한 책임을 분리하여 Class 생성 (Move Class) |
다. 개방 폐쇄 원칙 (OCP : Open Closed Principle)
구분 |
설명 |
|
정의 |
- 확장에 용이한 설계 원칙 (추상화가 핵심임) - 소프트웨어 Entity(Classes, Modules, Functions)는 확장에는 열려있고, 수정에는 닫혀 있어야 한다는 설계 원칙 |
|
목적 |
- 기존의 코드 변경 없이 새로운 코드를 통해 모듈 확장 (모듈은 결코 변경되지 않음) ※ OCP 위반 시, 하나의 변경이 모든 변경의 파급효과를 가져옴 (Rigidity, Fragile, Immobility) |
|
개념도 |
- 기존의 모듈을 변경하지 않고(Closed), Client Code를 추가(Open)하여 설계 - 모듈 : 변경되지 않는 핵심 요소 - 클라이언트 코드 : 모듈에서 상속받은 기능을 가지고 오버라이딩함 |
|
고려 사항 |
- 추상화(Abstraction)가 핵심임. . 변화/수정/확장되는 것은 concrete class로 만들고, 변하지 않고 다른 개발자가 사용해도 되는 class는 abstract class로 정의 - 상속을 통해 유연하게 모듈 확장 가능 . 오버라이딩 – 상속을 의미하지만, 크게 유연성 확보 차원의 원리 . 기능의 상속이 아닌 설계의 유연성을 강조 |
|
예시 (상속) |
- 계산기의 변하지 않는 부분만 Calculator로 추상화 Specific한 계산기는 상속받아서 구현. |
|
예시 (Framework) |
- framework : Application에 독립적인 부분 - customization : Application에 의존적인 부분은 비즈니스 로직 및 데이터를 반영 |
라. 리드코프 치환의 원칙(LSP : Liskov Substitution Principle)
구분 |
설명 |
|
정의 |
- 상속을 사용할지 Composition을 사용할지를 결정하는 원칙 - 자식 타입(Subtype)은 상위 타입들이 사용되는 곳에 대체 될 수 있어야 한다는 원칙 - 자식 타입은 부모 타입으로 교체할 수 있도록 설계한다는 원칙 |
|
목적 |
- 다형성(polymorphism)을 안정적으로 사용가능 하도록 하는 설계원칙 - 인터페이스만 알면 구현체를 몰라도 사용 가능함 → 구현체의 변경 및 확장이 클라이언트와 독립적으로 발생하여, 유지보수/확장 용이 ※ 위배 시, 인터페이스의 기능을 수행하는 클라이언트가 호환되지 않는 구현체를 사용하게 되는 문제 또는 오류 발생 |
|
개념도 |
||
고려 사항 |
- 상속보다는 Subtyping의 개념임. 대부분의 프로그래밍 언어가 상속 시 Subtyping도 동시에 되기 때문에 혼동이 됨. - 상속으로 설계 시, LSV 위반이 발생하는 경우는 Composition을 사용하여 Subtyping하는 것이 바람직함. |
|
예시 |
Storage 인터페이스를 구현한 하위클래스인 FileStorage와 DBStorage 클래스는 Client의 write() 인자인 Storage를 대체 가능해야 함 → Client는 어떤 Storage 사용하는지에 관계없이 Storage의 Save를 사용하여 개발. FileStorage/DBStorage의 변경, 다른 유형의 Storage 생성에 영향받지 않음 |
마. 인터페이스 분리의 원칙(ISP : Interface Segregation Principle)
구분 |
설명 |
|
정의 |
- 클라이언트별로 관련된 인터페이스만 제공해야 한다는 원칙 - 하나의 일반적인 인터페이스보다는 구체적인 여러 개의 인터페이스로 구현해야한다는 원칙 - 클라이언트는 자신이 사용하지 않는 메소드에 의존 관계를 맺으면 안됨 |
|
목적 |
Client가 사용하지 않는 Method에 대한 의존관계를 없애, 유지보수가 용이 구현 클래스에서 불필요한 Interface에 대한 기능 구현 방지 ※ 위반 시, 불필요한 coupling이 발행하여, 사용하지 않는 method 추가/수정 시, 기능 구현 및 컴파일/테스트해야 하는 등의 문제 발생 ※ Façade Design Pattern : 인터페이스의 단일 책임을 강조 하나의 인터페이스에 해당 인터페이스의 목적에 부합되지 않는 기능을 선언하지 않기 때문에 구현 클래스에서 불필요한 기능의 구현 방지 |
|
개념도 |
-각 클라이언트에 필요한 기능별로 Interface를 분리 |
|
고려 사항 |
- 모든 인터페이스를 분리하는 것이 아니라, 공통적인 인터페이스는 추상화하여 재사용을 극대화 함 → Façade Pattern |
|
예시 |
네트워크 서비스 제공 시, 클라이언트별로 사용하는 Protocol에 대한 인터페이스를 분리하여 클라이언트별로 제공 |
바. 의존성 뒤집기 원칙 (DIP : Dependancy Inversion Principle)
구분 |
설명 |
정의 |
- 상위 계층이 하위 계층에 의존하는 전통적인 의존관계를 반전시킴으로써, 상위 계층이 하위 계층의 구현으로부터 독립되게 SW 모듈을 분리하는 원칙 - 상위 수준 모듈은 하위 수준 모듈에 의존성이 없어야 하고, 서로 추상화에 의존해야 한다는 원칙 - 추상화된 것에 의존하게 만들고, 구체 클래스에 의존하도록 만들지 않도록 함. |
목적 |
- 구체클래스에 의존성을 제거하여 낮은 결합도 유지 - 추상화된 클래스에 의존하여 확장성이 높아져 유지보수성 향상 |
개념도 |
상위 클래스 A가 하위 클래스 B에 의존하지 말고, 추상화 클래서 A*에 의존하게 함. |
고려 사항 |
- 모든 클래스에 인터페이스를 생성하면 클래스가 엄청나게 증가하고 복잡해지므로 필요한 것만 생성 - OCP 와 LSP를 코드에 적용하면, DIP 또한 준수하게 됨 |
예시 |
- Copy를 Read Keyboard, Write Printer에 의존하지 않고 interface에 의존하도록 하게 함으로써, 새로운 입력장치 Scanner, 출력장치 FlashDisk를 독립적으로 추가 가능
※ MVC 패턴이 DIP의 대표적인 예임 |
[참고] 객체지향 설계 원칙 활용
* 객체지향 설계 5대 원칙 활용
(1) 개발 위한 원칙이 아닌 설계 원칙
(2) 클래스 간 낮은 의존성, 파생 클래스 활용도 극대화
(3) 부모 클래스를 상속받아 최대한 활용하도록 설계
(4) 객체지향 특징, 장단점 파악, 적절히 Trade-off
* 객체지향설계 적용 시 고려사항
항목 |
내용 |
프로젝트 착수 시 |
- 재사용에 대한 규모 산정 및 재사용 체계 구축에 대한 수립이 필요 - 재사용성 활용도 측면 고려 필요 |
프로젝트 수행 시 |
- 분석/설계 시에 클래스의 책임과 역할 분석을 위한 CRC (Candidate, Responsibility, Collaboration)카드 작성 - 재사용성을 극대화 하기 위한 Design Pattern 활용 |
유지보수 수행 시 |
- 재사용 컴포넌트 관리와 프로세스(기능)과 연계 관리가 필요 - 컴포넌트의 조립으로 결합 컴포넌트 생성 |
'정보관리기술사&컴퓨터응용시스템기술사 > SW공학과 프로젝트관리' 카테고리의 다른 글
[CI/CD 지속적통합/지속적배포], Devops 의 핵심 구성요소 (0) | 2021.01.10 |
---|---|
[객체지향 프로그래밍(OOP)], 재사용성과 객체 표현 기법 (0) | 2021.01.09 |
[Agile 방법론] 작동하는 SW 중심 (0) | 2021.01.06 |
나선형 모델(Spiral Model), 위험 최소화를 위한 진화적 프로토타이핑 (0) | 2020.12.30 |
프로토타이핑 모델(Prototyping Model), 고객의 원활한 의사소통을 위한 시제품을 통한 점진적 개발 방법 (0) | 2020.12.22 |
댓글