이론적으로만 알고 있던 SOLID에 대해서 다시 한 번 정리해볼 필요가 있다고 생각해서 정리했다.
면접 준비할 때만 개념적으로 이해하고 있던 내용도 있고,
주변에서 항상 들어왔던 이야기를 바탕으로 최대한 신경 쓰려고 하는 원칙도 있었던 것 같다.
코딩 면접을 준비하는 사람들은 최소한 아래 용어에 대해서는 알고 있어야 한다.
이 글에서는 해당 용어에 대한 설명 외에도, 다른 분의 정리와 본인의 생각을 결합하여 끄적여봤다.
SRP, Single Responsibility Principle, 단일 책임 원칙
-
한 클래스는 하나의 책임만 가져야 한다.
-
하나의 책임??
-
아무것도 모르던 시절엔 이 "책임"의 범위를 정하는 것이 가장 어려운 것 같다.
-
크고 작은 것을 어떻게 정할 것인지에 대한 기준이 필요하지 않을까?
-
-
이 책임을 정하는 기준은 변경에 초점을 두면 된다.
-
만약 어떤 부분이 변경되었을 때 그 파급 효과가 적다면, 책임의 범위를 잘 정했고, 이 원칙을 잘 따르고 있다고 보자.
- 프로젝트 경험이 많지 않은 커리어지만, 이런 개념을 전혀 고려하지 않고 처음 설계했던 학생 시절을 돌이켜 보면 클래스 하나가 모든 기능을 물고 있었다.
- 이를 생각하면 이것만 생각해도 어느정도 감을 잡을 수 있을 것 같다.
-
OCP, Open/Close Principle, 개방-폐쇄 원칙
-
소프트웨어 요소는 확장에 열려 있고 변경에는 닫혀 있어야 한다.
-
단어는 이해했는데, 뭐 어쩌란 것인지 이해하기 어려웠던 부분.
-
확장을 위해선 당연히 코드를 변경해야 하는데 변경에는 닫혀 있어야 한다는 말은, 아무것도 하지 말라는 말처럼 들릴 수 있다.
-
-
다형성 여기에 끌고온다면?
-
인터페이스를 설계하고 그것을 구현한 클래스 하나를 만들어 새로운 기능을 구현한다고 생각해보자.
-
역할(인터페이스)과 구현(클래스)이 분리된다.
-
인터페이스를 바꾸지 않고 구현한 클래스를 만들어 새로운 것을 하나 만들어낸다.
-
- 문제가 될 수 있는 상황이 있다.
public class MemberService {
// private MemberRepository memberRepository = new MemoryMemberRepository();
private MemberRepostiroy memberRepository = new JdbcMemberRepository();
}
-
구현 객체를 변경하기 위해 클라이언트 코드를 변경한다면, 결국 다형성을 사용하지만 OCP를 망친다.
-
이 문제를 해결하려면 객체 생성, 연관 관계에 있어 어떤 작업이 필요하지 않을까...?
-
LSP, Liskov Substitution Principle, 리스코프 치환 원칙
- S 타입의 객체 o1, 각각에 대응하는 T 타입 객체 o2가 있고, T 타입을 이용해 정의한 모든 프로그램 P에서 o2의 자리를 o1으로 치환해도 P의 행위가 변하지 않으면 S는 T의 하위 타입이다.
-
프로그램의 객체는 프로그램의 정확성을 깨지 않으면서 하위 타입의 인스턴스를 바꿀 수 있어야 한다.
-
다형성에서 하위 클래스는 인터페이스 규약을 다 지켜야 하고, 다형성을 지원하기 위한 원칙, 인터페이스를 구현한 구현체는 믿고 사용하려면 원칙이 필요하다.
-
ISP, Interface Segregation Principle, 인터페이스 분리 원칙
- 클라이언트가 자신이 이용하지 않는 메서드에 의존하지 않아야 한다.
-
즉, 특정 클라이언트를 위한 인터페이스 여럿이 범용적인 것 하나보다 낫다
- 인터페이스 하나를 범용적으로 짜놓고, 그것을 클래스에서 구현했다고 생각해보자.
- 어떤 동작 변화 하나가 몇몇 클래스에는 영향을 주지 않아야 하는데, 인터페이스 하나만으로 모든 것을 다 관리하게 되니, 모든 클래스에 영향을 준다.
- 당장 사용하는 코드에서 기능끼리 분리해낼 수 있다면, 그 역할을 조금 더 나눠줄 수 있다면 더 나눠주자.
DIP, Dependency Inversion Princinple, 의존성 역전 원칙
- 상위 수준 모듈은 하위 수준 모듈에 의존하지 않는다. 둘 모두 추상화에 의존한다.
-
추상화에 의존하고 구체화에 의존하지 않는다.
-
구현 클래스에 의존하지 말고, 인터페이스에 의존하게 하자. 그래야 클라이언트에 대해 유연한 변경이 가능하다.
-
public class MemberService {
// private MemberRepository memberRepository = new MemoryMemberRepository();
private MemberRepostiroy memberRepository = new JdbcMemberRepository();
}
-
아까 그 코드가 다시 등장한다. 여기서 MemberService는 인터페이스에 의존하지만, 구현 클래스에도 동시에 의존하는 상황이 된다.
-
MemberService 클라이언트가 구현 클래스를 선택하면서 DIP 위반!
-
글을 마무리하며
SOLID는 용어만 보고 이해하면 개념을 안다고 이야기하기 보다는 그냥 외웠다고 보는 것이 맞지 않을까 싶다. 확실히 이해하는 것이 쉽지는 않겠지만, 그래도 개념을 한 번씩 생각해보는 건 실전에 적용해보는 것이라고 생각한다.
Reference
'Computer Science > 기본' 카테고리의 다른 글
디스플레이 해상도 설정 (0) | 2017.02.03 |
---|---|
쇼핑몰 서비스 이용약관, 개인정보 취급 방침 (0) | 2016.11.08 |
소스 코드 변환 사이트 (0) | 2016.07.21 |
JS, CSS, HTML 오픈 소스 사이트 (0) | 2016.07.21 |
게임 사양을 체크해주는 사이트, Can You RUN it (0) | 2015.02.20 |