스프링을 공부하면서,
요즘 스프링을 공부하면서 어떻게 코드를 짜야 좀 더 객체지향적으로 짤 수 있을까? 라는 생각이 많이 들었다. 그러던 중 클린코드로 유명한 로버트 마틴(Robert C. Martin's)이 정의한 좋은 객체 지향 설계의 5가지 원칙을 알게 되었다. 5가지 원칙의 앞글자를 따서 SOLID라고 부른다.
SOLID
5가지 원칙은 아래와 같다. 한 가지씩 차근차근 알아보자.
SRP(Single Responsibility Principle) : 단일 책임 원칙
OCP(Open Closed Principle) : 개방-폐쇄 원칙
LSP(Liskov Substitution Principle) : 리스코프 치환 원칙
ISP(Interface Segregation Principle) : 인터페이스 분리 원칙
DIP(Dependency Inversion Principle) : 의존관계 역전 원칙
1. 단일 책임 원칙 SRP(Single Responsibility Principle)
"클래스는 단 하나의 책임을 가져야 하며, 클래스를 변경하는 이유는 단 하나의 이유이어야 한다." (A class should have one, and only one, reason to change)
단일 책임 원칙은 좀 쉽게 느껴진다. 우리가 흔히 개발을 처음할 때는 메인 클래스에 모든 기능을 넣지만, 개발 실력이 올라가다 보면 역할을 나눠 클래스를 작성한다. 여기서 더 나아가 어떤 클래스가 변경되더라도 파급 효과가 적을 때 이것을 단일 책임 원칙을 잘 따른 것이라고 표현한다.
클래스를 잘 분리했을 때 단일 책임 원칙을 잘 따르는 것이 아닌, 변경이 일어났을 때 파급 효과가 적으면 단일 책임 원칙을 잘 따르는 것이다. 변경에 기준이 맞춰져 있다는 것을 기억하자.
2. 개방-폐쇄 원칙 OCP(Open Closed Principle)
"소프트웨어 요소는 확장에는 열려 있어야 하고 변경에는 닫혀 있어야 한다." (Software entities (classes, modules, functions, etc) should be open for extension but closed for modification)
가장 중요한 원칙이자, 이해하기 힘든 원칙이다. 이게 말이 되나...? 라는 생각이 드는 원칙이기도 하다.
개방-폐쇄 원칙을 잘 지키고 있다는 것은 기존 코드를 건들이지 않고, 새로운 기능을 추가할 수 있어야 하는 것을 뜻한다.
예를 들어 내가 Mybatis를 사용하고 있었지만, JPA로 서비스를 변경하고 싶을 때 기존 서비스 코드를 건드리게 되면 개방-폐쇄 원칙을 잘 지키지 않는 것이다. 하지만 객체를 생성하고, 연관관계를 맺어주는 별도의 조립, 설정자를 사용해서 기존 코드를 건드리지 않는다면 그것은 계방-폐쇄 원칙을 잘 지키는 것이다.
3. 리스코프 치환 원칙 LSP(Liskov Substitution Principle)
"프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다."(subtypes must be substitutable for their base types)
이해하기 쉬운 원칙이다. 하위 클래스는 인터페이스 규약을 다 지켜야 한다는 것을 뜻하는데, 예를 들어 자전거 인터페이스의 브레이크는 정지하는 기능인데, 앞으로 가게 구현한다면 LSP를 위반하는 것이다. 만약, 브레이크가 느리게 정지하더라도 정지하는 기능은 일치해야 한다.
4. 인터페이스 분리 원칙 ISP(Interface Segregation Principle)
"인터페이스는 그 인터페이스를 사용하는 클라이언트를 기준으로 분리해야 한다." (Clients should not be forced to depend on methods they do not use)
ISP는 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나 보다 낫다는 것을 뜻한다. 즉, 인터페이스를 명확하게 구분해서, 대체 가능성을 높게 하는 것이다.
"큰 덩어리보다 잘게 쪼개서 인터페이스를 설계하는 것이 낫다"라고 이해하면 될 것 같다.
5. 단일 책임 원칙 DIP(Dependency Inversion Principle)
"고수준 모듈은 저수준 모듈의 구현에 의존해서는 안된다. (high-level modules should not depend on low-level modules. Both should depend on abstractions)"
OCP와 더불어 가장 중요한 원칙으로 뽑히는 원칙이다.
쉽게 풀어서 말하면 "추상화에 의존해야지, 구체화에 의존하면 안 된다."라는 말과 똑같다. 즉, 구현 클래스에 의존하지 말고, 인터페이스에 의존하라는 뜻이다. 그래야 유연하게 구현체를 변경할 수 있다.
예를 들어, 사람이라는 인터페이스가 있을 때 "박보검"이라는 구현체 사람에 의존하면 안 되고, "사람"에 의존해야 된다는 뜻이다.
■ 참고 자료
- https://github.com/gyoogle/tech-interview-for-developer/blob/master/Design%20Pattern/SOLID.md
- https://github.com/JaeYeopHan/Interview_Question_for_Beginner/tree/master/Development_common_sense
- https://inf.run/CysL
'CS > OOP' 카테고리의 다른 글
상속(inheritance) [JAVA] (0) | 2021.03.15 |
---|---|
인터페이스(Interface)와 추상 클래스(abstract class) [JAVA] (0) | 2021.03.15 |
클래스들의 관계[JAVA] (0) | 2021.03.06 |
클래스(Class) [JAVA] (0) | 2021.02.24 |