본문 바로가기
프로그래밍 언어/설계 원칙 & 디자인 패턴

저는 SOLID가 처음이라니까요? (1편)

by 조엘 2021. 4. 14.

안녕하세요! 조엘입니다!

 

"처음이라니까요" 시리즈 네 번째 주자 바로 SOLID 원칙입니다. 🎺🎺

SOLID가 왜 중요한 개념인지 같이 공부해보도록 해요!

 

다룰 내용이 많아서, 1편에서 SRP / OCP를, 2편에서 LSP / ISP / DIP를 다루도록 하겠습니다!

 

 

*** SOLID 원칙 ***

객체 지향 프로그래밍은 각자의 책임들을 완수하는 객체들을 만들고, 이를 협력시켜 큰 문제들을 풀게 했어요.

독립성과 신뢰성이 높은 객체들로 조합된 프로그램은 절차 지향적으로 작성된 프로그램에 비해 유지 보수와 확장에 유리하다고 해요. 

 

하지만 이론은 알아도 막상 코드를 "객체 지향적"으로 작성하려면 머리가 굳어버리는데요!

대충 클래스 정의하고, 대충 조합해서, 뚝딱뚝딱 굴러가게만 짠 코드는 결코 유지 보수와 확장에 유리하지 않아요. 

 

그렇다면, 유지 보수와 확장에 유리한 객체지향 프로그램을 작성하기 위해 가이드라인이 있으면 얼마나 좋을까요?

 

"SOLID 원칙" 바로 그 가이드라인 역할을 해줄 수 있어요. 

 

위키피디아에서 정의하는 SOLID는 다음과 같아요. 

 

컴퓨터 프로그래밍에서 SOLID 로버트 마틴[1][2]이 2000년대 초반[3]에 명명한 객체 지향 프로그래밍  설계의 다섯 가지 기본 원칙을 마이클 페더스가 두문자어 기억술로 소개한 것이다. 프로그래머가 시간이 지나도 유지 보수와 확장이 쉬운 시스템을 만들고자 할 때 이 원칙들을 함께 적용할 수 있다.[3] SOLID 원칙들은 소프트웨어 작업에서 프로그래머가 소스 코드가 읽기 쉽고 확장하기 쉽게 될 때까지 소프트웨어 소스 코드를 리팩터링하여 코드 냄새를 제거하기 위해 적용할 수 있는 지침이다. 이 원칙들은 애자일 소프트웨어 개발 적응적 소프트웨어 개발의 전반적 전략의 일부다.[3]

 

SOLID는 총 5가지의 원칙으로 이루어져 있는데요! (SRP / OCP / LSP / ISP / DIP)

미리 스포를 조금 해드리자면, 

SRP / ISP를 통해 객체가 커지지 않도록 막아주고,

OCP / LSP / DIP를 통해 변화에 유연한 코드를 작성하도록 도와줘요. 

 

이제 원칙들 하나씩 살펴보도록 해요! 💪💪

 

 

*** Single Responsibility Principle (단일 책임 원칙) ***

첫 번째 원칙은 SRP, 단일 책임 원칙이에요. 정의는 다음과 같아요. 

"클래스는 단 한 개의 책임을 가져야 한다!"

 

하나의 클래스가 다양한 책임을 가지면 왜 유지 보수와 확장에 불리할까요? 🙄🙄

 

프로그램의 요구사항은 수시로 변해요.

요구사항의 변화는 해당 요구사항의 책임을 완수하는 클래스의 코드를 변경시켜야 한다는 뜻이기도 해요.

하나의 클래스가 다양한 책임을 가진다면, 더 수시로 변화가 될 것이에요.

 

객체들 간의 조합으로 이루어진 객체 지향 프로그램에서 하나의 객체가 많은 책임을 들고 있다면,

해당 클래스의 변화는 해당 클래스에 의존하고 있는 다른 클래스에게도 영향을 주게 되어요. 

어쩌면 해당 클래스의 변화로 인해 다른 클래스들을 주구장창 다 고쳐야 할 수도 있어요. 

이는 위에서 언급한 유지 보수와 확장에 유리한 프로그램이 아니에요.

절차 지향적으로 코드를 변경시키거든요.  

 

클래스가 단 한 개의 책임을 가져야 한다는 규칙에 따라 코드를 작성하게 된다면,

이제 객체는 독립성과 응집도가 높은, 단 하나의 주어진 책임을 완수하는 객체로 작성될 것이에요. 

해당 클래스의 요구사항 변경 시, 수정으로 인해 다른 클래스들이 받을 사이드 이펙트를 최소화할 수 있어요.  

물론 하나의 책임을 가진 클래스는 재사용성이 높아지는 장점도 있고요. 

 

여기서 하나 주목할 것은, "단 한 개의  책임을 가진다"라는 말이 조금 주관적일 수 있다는 것인데요. 

로버트 마틴은 책임을 "변경하려는 이유"로 정의했어요. 

하지만 저는 개인적으로 이 역시 말이 사람마다 다르게 해석될 수 있다고 생각이 들어요.

다양한 경험을 통해 많은 사람들과 이야기를 나누며 한 개의 책임에 대한 기준을 키워나가야 한다고 생각이 듭니다.  

 

 

*** Open Closed Principle (개방 폐쇄 원칙) ***

두 번째 원칙은 OCP, 개방 폐쇄 원칙이에요. 정의는 다음과 같아요.

"확장에는 열려있어야 하고, 변경에는 닫혀 있어야 한다!"

기능을 변경하거나 확장할 수는 있으면서, 그 기능을 사용하는 코드는 수정하지 않아야 한다는 것이에요.

 

기능을 바꾸면서, 그 기능을 사용하는 코드를 바꾸지 않는다니? 가능한가요?? 🤔🤔

이를 어떻게 구현할 수 있을까요? 또한 이것이 왜 유지 보수와 확장에 유리한 것일까요?

 

OCP는 추상화다형성을 통해서 구현할 수 있어요. 

 

추상화는 데이터/프로세스 등을 의미가 비슷한 개념이나 표현으로 정의해 나가는 과정이에요. 

그 과정에서 구체적인 구현 상세는 감추고요.

JAVA 언어에서는 추상 클래스, 인터페이스를 통해 추상화를 시킬 수 있어요.  

 

다형성은 프로그램 언어 각 요소(상수, 변수, 식, 객체, 메서드 등)가 다양한 자료형에 속하는 것이 허가되는 성질이라는 뜻이에요. 하나의 타입에 여러 객체를 대입할 수 있는 성질이라고 이해해도 좋을 것 같아요. 

 

추상화시킨 타입을 프로그램에서 사용하도록 코드를 작성한 후, 

추상화된 타입의 실제 구현이 담겨 있는 객체를 참조 / 주입하도록 하는 것으로 OCP를 만족시킬 수 있어요.

 

프로그램에 비슷하지만 다른 기능이 추가적으로 필요할 때, 기존의 코드를 수정하지 않고, 

추상화 된 타입을 상속 / 구현하여 새로운 기능을 만들 수 있는 것이죠. 

 

코드가 없어 와 닿지 않으시면 제 전략 패턴 포스팅을 참조해 보셔도 좋을 것 같아요!

전략 패턴이 OCP를 코드로 이해하기에 아주 좋은 디자인 패턴이라고 생각이 됩니다. 

papimon.tistory.com/75

 

저는 전략 패턴이 처음이라니까요?

안녕하세요! 조엘입니다! "처음이라니까요" 시리즈 두 번째 주자 바로 전략 패턴입니다. 자랑은 아니지만, 사실 디자인 패턴이라는 걸 우테코 들어와서 처음 들어봤어요. 😂 그래서 전략 패

papimon.tistory.com

 

OCP는 결국 "유연함"에 대한 원칙이에요.

새로운 기능을 추가하는 것에 부담이 생기면 객체 지향적인 설계가 아니란 거죠. 

기존 기능을 확장하기 위해, 기존 코드를 곧바로 수정하는 것은 결코 확장에 용이한 코드가 아니에요. 

따라서 우리는 변화되는 부분을 발견할 때마다 이를 추상화하여,

변경과 확장에 유리한 코드를 작성하도록 해야 할 것이에요. 🤞

 

 

 

참고

- woowacourse.github.io/javable/post/2020-10-27-polymorphism/

- javacan.tistory.com/entry/OO-Basic-2-AbstractionAndPolymorphism

- stackify.com/solid-design-principles/

- stackify.com/solid-design-open-closed-principle/

- 개발자가 반드시 정복해야 할 객체 지향과 디자인 패턴(최범균 | 인투북스)

 

반응형

댓글