# SOLID
올바른 객체지향설계와 애자일한 설계를 위해서는 Martin이 제안한 5가지의 원칙(SOLID)을 준수해야 한다. 그러면 우리는 변경에 유연한 소프트웨어를 만들 수 있다. 5가지의 원칙중 SRP 단일 책임 원칙에 대해서 알아보자.
- SRP (Single Responsibility Principle) 단일 책임 원칙
- OCP (Open Closed Principle) 개방 폐쇄 원칙
- LSP (Liskov Substitution Principle) 리스코프 치환 원칙
- ISP (Interface Segregation Principle) 인터페이스 분리 원칙
- DIP (Dependency Inversion Principle) 의존 역전 원칙
# 시작하기 전
단일 책임 원칙은 5가지 원칙 중 이름만 보고 정확한 유추가 가능하다. 대신 책임이라는 것이 매우 모호하기 때문에 실제 적용하기에는 가장 까다로운게 단일 책임 원칙이다. 책임이라는 용어는 결합도(cohesion)이라는 용어를 연상케 한다.
## High Cohesion Loose Coupling
이 용어는 높은 응집력과 낮은 결합도를 가져야 한다는 용어이다. 응집력(Cohesion)은 한 모듈(클래스) 안에 같은 책임, 기능, 함수등들이 오밀조밀 뭉쳐있어야한다는 것이고, 낮은 결합도(Coupling)은 각 모듈(클래스)들이 서로에게 너무 의존적이면 안된다는 뜻이다. 의존적이면 변경에 취약해지기 때문이다.
# 단일 책임 원칙(SRP)
한클래스는 하나의 책임만을 가져야 한다. 이것이 단일 책임 원칙이다. 책임은 변경과 관련있다. 만약에 변경을 유발하는 것이 하나가 아니라면 이 클래스는 한개 이상의 책임을 지고 있는 것이다.
그러나 책임이라는 단어는 상대적이기에 너무나 모호하다. 책임은 클래스내에서 함수를 뜻하는 것은 당연히 아니다. 함수가 여러개라고 책임이 여러개라는 오해는 접어두자. 책임은 묶일 수 있다. 즉 여러 기능을 하더라도 변경을 유발하는 것 단위로 묶을 수 있고 이렇게 묶인게 하나의 책임이 될 수 있는 것이다.
## 예제
클린 소프트 웨어에서 소개한 모뎀(Modem)예제를 살펴보자.
우리가 객체지향을 사용하면서 하나의 클래스를 하나의 명사로 생각하여 여러개의 책임을 넣는 것은 허다하게 일어나는 일이다. 책임을 묶어서 생각하는 데에 익숙하다는 말이다. 우리가 한 클래스에 부여한 책임을 다시한번 보면서 진정한 하나의 책임인지 살펴봐야 할 필요가 있다. 아마 책임이 분리 될 수 있을 것이다.
interface Modem {
public void dial(Stringpno); // 연걸합니다.
public void hangup(); // 끊습니다.
public void send(char c); // 통신을 보냅니다.
public void recv(); // 통신을 받습니다.
}
얼핏 보면 Modem에서 정의한 4가지의 기능은 Modem이 가져야할 하나의 책임이라고 생각 할 수 있다. 우리의 모뎀은 연결하고 끊고, 통신을 보내고 받는 기능을 수행하기 때문이다. 그러나 통신의 방법을 변경하는 유발이 일어 났을 때를 생각해보면 이 책임들은 분리 할 수 있다고 생각이 들 것이다.
dial과 hangup은 모뎀의 연결을 관리하고, send와 recv는 데이터를 주고받으며 통신을 담당하도록 말이다. 그렇다면 이 책임을 분리시켜야만 경직성을 피할 수 있을 것이다.
interface DataChannel {
public void send(char c); // 통신을 보냅니다.
public void recv(); // 통신을 받습니다.
}
interface Connection {
public void dial(Stringpno); // 연걸합니다.
public void hangup(); // 끊습니다.
}
interface Modem implements DataChannel,Connection {
public void dial(Stringpno);
public void hangup();
public void send(char c);
public void recv();
}
이렇게 책임을 분리하였기 때문에 DataChannel을 바뀔 경우 DataChannel을 상속받아 구현하는 구현체로 구현시켜 사용 할 수 있다. Modem은 DataChannel이 어떻게 구현됐는지도 알 필요가 없다. 의존이 생기지 않게 되는 것이다.
### 책임의 분리는 변경이 일어날 때만
그러나 가장 중요한 것은, 이러한 변경의 축은 실제로 변경을 일어날때만 적용되어야 한다는 것이다. 내가 만든 서비스에서는 DataChannel과 Connection이 하나의 책임일 수도 있는 것이다. 이것을 변경해야하는 사유가 전혀 존재 하지 않는다면 또 변경이 일어나 지않았다면 구태어 분리할 필요가 없다. 이런경우 분리한다면 오히려 불필요한 복잡성을 유발할 수 있다.
# 참고
'• 독서 > Design Pattern' 카테고리의 다른 글
[클린소프트웨어#6] SOLID-리스코프 치환원칙(Liskov Substitution Principle) (0) | 2022.10.20 |
---|---|
[클린소프트웨어#5] SOLID-개방 폐쇄 원칙(Open Closed Principle) (0) | 2022.10.19 |
[클린소프트웨어#3] 애자일한(Agile)설계를 위한 방법과 7가지 부패한 특성 (1) | 2022.10.18 |
[클린소프트웨어#2] 익스트림프로그래밍(XP)에 대해서 (0) | 2022.10.18 |
[클린소프트웨어#1] 애자일(Agile) 방법론과 4가지 가치와 12개의 원칙 (0) | 2022.10.18 |