그렇기 떄문에 객체지향적인 개발관점에서 유지보수에 완벽하게 대응할 수는 없지만 대규모 프로젝트에서 유지보수의 어려움을 어느정도 완하 시켜줄 수 있는 원칙을 가이드하여 해소하고 있다.
S : Single Responsiblity [단일 책임 원칙]
O : Open Closed [게빙 폐쇄 원칙]
L : Liskov Substitution [리스코프 치환 원칙]
I : Interface Segregation [인터페이스 분리 원칙]
D : Dependency Inversion[의존성 역전 원칙]
객체 지향의 solid 원칙은 각 이름의 앞글자 하나를 따서 만들게 되었다.
💨What [각 원칙의 목표와 기대효과]
각각의 원칙에 대한 목표
단일 책임 원칙
🤜🏻
하나의 클래스는 단 하나의 역할만 해야한다❗
개방 폐쇄 원칙
🤜🏻
변경에는 닫혀있고 확장에는 열려있어야만 한다 ❗
리스코프 치환 원칙
🤜🏻
하위 타입은 상위 타입으로 치환 될 수 있어야 한다 ❗
인터페이스 분리 원칙
🤜🏻
자신이 사용하지 않는 인터페이스는 구현하지 않아야 한다 ❗
의존성 역전 원칙
🤜🏻
구체화에 의존하지 말고 추상화에 의존해야 한다 ❗
각 원칙을 지킴으로써 기대 효과
단일 책임 원칙
🍯
변경의 원인이 단 하나이기 때문에 해당 대상이 명확해 지는 것이 장점이다.
대규모 프로젝트에서 원인을 찾기위해 전체 로직을 리버싱해야 하는 것과 비교하자면 엄청난 효과인 것이다.
개방 폐쇄 원칙
🍯
소프트웨어는 시대 또는 트렌트에 매우 민감하기 때문에 기존의 요구사항에서의 변경이 매우 많다. 그래서 유연하게 대처 할 수 있도록 확장에는 열려있고 변경에있어서는 다른 곳에 파급력이 없도록 해야 유지보수가 용이해지는 것이다.
리스코프 치환 원칙
🍯
확장하는데 용이함을 얻을 수 있다. 기존의 요구사항에서 조금 더 세부적인 요구사항으로 인해 스펙이 추가된 경우 쉽게 확장하여 사용이 가능해진다.
인터페이스 분리 원칙
🍯
세부적으로 인터페이스를 분리하지 않으면 역할에 대한 행동이 강제되어 결국 유지보수가 어렵게 된다. 어떤 곳에서는 empty 한 body가 될 수도 있게 되면서 … 이런 사태를 만들게 되면 컨슈머 쪽에서 의도한 것과는 다르게 액션을 취하게 되어 버그가 발생하게 된다. 인터페이스를 세부적으로 나눔으로써 행위를 강제하지 않아도 되며 변경에 대한 스코프가 줄어들게 됨으로써 유지보수를 함에 용이하게 된다.
의존성 역전 원칙
🍯
구체화에 의존하게 되면 새로운 구현체에 등장으로 인해 수시로 코드를 변경해야 한다. 이 점도 유지보수 함에 있어 얼마나 복잡한지에 따라 코드 변경이 대한 스코프가 작을 수도 클 수 있지만, 대규모 프로젝트에서는 어려운일이 될 수 있다.
❓Why [왜 지켜야 하는가]
🗣
해당 원칙을 완벽하게 준수하면서 구현하는 것은 보통일도 아니고 서비스 모델에 따라 적용이 될 수도 안될 수도 있지만 해당 제약 조건에 가깝게 따르게 되면 수시로 변화 하는 소프트웨어 세계에서 가장 큰 이슈인 유지보수에 쉽게 대응할 수 있기 때문이다.
✅How [어떻게 사용하는지]
SRP
남자는 많은 역할을 지니고 있는 것을 확인 할 수 있다.
단 하나의 책임을 갖도록 분리하게 되면 변경에 대해 단 하나만 대응함으로써 유지보수에 용이해진다.
OCP
DB의 종류가 점점 늘어나게 되도 인터페이스를 구현하도록 하면 되고 추가적인 기능을 인터페이스에 단순히 추가하게 됨으로써 변경에 유연하게 대처할 수 있게 된다.
스프링 프레임워크의 JDBC 인터페이스
LSP
하위 타입이 늘어 남에 따라 부분적으로 추가를 함으로써 변경에 쉽게 대응할 수 있게 된다.
⚠️ 객체지향에서의 상속은 조직도 계층도가 아니라 분류도 이여야 함을 기억해라 ❗
딸은 아버지의 역할을 수행할 수 없으므로 LSP를 위반한 것이다.
잘 적용된 LSP
ISP
남자의 역할이 이렇게 많은 가운데 이거보다 더 많은 역할을 받게 된다면 클래스를 따로 만드는 것 또한 큰 변경이 따를 것이다.
그러므로 쉽게 코드적으로 변경할 수 있도록 인터페이스로만 분류하게 되어 컨슈머 쪽에서는 쉽게 참조를 통해 메소드 호출에 스코프를 줄임으로써 예상치 못한 행위 자체를 차단할 수 있게 될 것이다.
DIP
자동차는 특정 타이어에 의존한다고 하면 구체 클래스가 새롭게 추가 됨에 따라 일일히 갈아 끼워줘야 한다.
그럼으로써 얻는 치명적인 단점은 휴먼 에러 .. 가 발생 할 수 있는 점이다. 그리고 메소드 명이 조금씩 달라지게 되는 것 또한 호출자 부분을 체크해야한다는 점에서 유지보수가 어렵게 되는것이다.
만약 구현체가 아닌 추상화에 의존하게 되면 객체를 조립함으로써 유연하게 갈아끼울 수 있다는 점이다.
그리고 가시적으로 확인할 수 있듯이 화살표의 방향이 구현체가 반대로 다른 무엇인가를 향하는 것을 볼수있다.