본문 바로가기

개발 이야기

[클린 아키텍처] 5가지 SOLID 설계원칙

좋은 소프트웨어란 깔끔한 코드(Clean Code)로 시작된다. 하지만 깔끔한 코드도 정작 시스템 아키텍처를 엉망으로 만들면 의미가 없어진다. 따라서 좋은 코드로 좋은 아키텍처를 만들기 위한 원칙이 필요하며, 객체지향 설계에서는 SOLID라고 불리는 원칙이 있다.

 

객체지향 설계의 5가지 핵심 원칙으로 불리우는 SOLID 원칙이란 (1) SRP(단일 책임 원칙), (2) OCP(개방-폐쇄 원칙)**, (3) LSP(리스코프 치환 원칙), (4) ISP(인터페이스 분리 원칙), (5) DIP(의존 역전 원칙)이다. SOLID는 이 5가지의 원칙들의 앞자를 따서 부르는 약자이다.

 

SOLID 설계원칙의 목적은 무엇일까? 결국 좋은 코드로 좋은 아키텍처를 만들기 위해서 제시된 원칙이기 때문에, 변경에 유연하고, 이해하기 쉬우며, 많은 소프트웨어 시스템에 사용될 수 있는 컴포넌트의 기반이 되는 것을 목적으로 한다. SOLID 설계원칙은 아키텍처 수준의 원칙이기 때문에 이를 통해서 코드 자체의 품질이나 가독성을 올리는 목적은 당연히 아니다.

 

특히 SOLID 설계원칙은 Software Engineer 직군에 지원하는 사람들에게는 단골 기술 면접 질문이다. 따라서 5가지 원칙이 무엇인지, 어떤 의미를 가지는지 간단하게라도 이해하고 있다면 상대방에게 좋은 인상을 얻을 수 있다.


1. SRP(단일 책임 원칙)

먼저 ‘단일 책임 원칙’이라는 용어에 주의해야 한다. 여기서 단일 책임은 ‘단 하나의 목적, 하나의 일을 수행하는 것’을 의미하지 않는다. 단일 책임 원칙은 소프트웨어 모듈은 변경의 이유가 오직 하나뿐(오직 하나의 액터actor에 의해서만 요청되어야 함)이어야 한다는 원칙이다. 즉, 2개 이상의 액터들이 의존하는 모듈은 분리해야 한다.

2. OCP(개방-폐쇄 원칙)

기존 코드를 수정하기보다 새로운 코드를 추가하는 방식으로 시스템의 행위, 기능을 변경할 수 있도록 설계해야 한다는 원칙이다. 쉽게는 소프트웨어 개체(클래스, 모듈, 함수 등)은 확장에 대해서 열려 있어야 하고, 수정에 대해서는 닫혀 있어야 한다는 원칙이다. 예를 들어서 어떤 함수의 변경이 일어나면, 그 함수를 의존하고 있는 다른 부분들의 동작이 기존처럼 동작할지 알 수 없다. 따라서 함수의 기능을 확장하거나 새롭게 생성하는 것이 좋다.

3. LSP(리스코프 치환 원칙)

상호 대체 가능한 구성요소를 이용해 소프트웨어 시스템을 만들 수 있으려면, 각 구성요소는 치환 가능해야 한다. 프로그래밍 언어 관점에서는 상속을 떠올리면 되는데, 상위 클래스 타입의 객체를 하위 클래스 타입의 객체로 치환해도 상위 클래스 타입을 사용하는 프로그램을 정상적으로 기능을 수행해야 한다. 하지만 생각보다 이 원칙을 지키기 위해선 상속 관계도 잘 고민해서 설계하지 않다면 이 원칙은 쉽게 깨질 수 있는데, 결국 LSP를 고려한다면 하위 클래스는 상위 클래스의 책임을 그대로 수행하면서 확장에만 열려있으면 된다. 이 원칙이 지켜지지 않는다면 클래스 계층 관계가 쉽게 오염될 수 있다.

4. ISP(인터페이스 분리 원칙)

소프트웨어 설계자(혹은 클라이언트)는 사용하지 않은 것(메소드 등)에 의존하면 안된다. 작은 단위의 역할 인터페이스로 분리하여 클라이언트는 꼭 필요한 메소드만 이용할 수 있게 해야한다. 특히 서로 의존하는 모듈 관계에서 불필요한 기능이 서로에게 포함된다면 예상하지 못한 문제에 빠질 수 있다.

5. DIP(의존 역전 원칙)

고수준 정책을 구현하는 코드(상위 모듈)는 저수준 세부사항(하위 모듈)을 구현하는 코드에 의존하면 안되고, 세부사항이 정책에 의존해야 한다. 즉, 상위 모듈과 하위 모듈은 추상화에 의존해야하며 추상화는 세부사항에 의존하면 안된다. 조금 어려운 내용이기 때문에 쉽게 생각하자면, 추상 클래스와 인터페이스를 잘 활용하여 하위 모듈의 변경이 상위 모듈의 변경으로 이어지지 않게 한다. 특히, Spring Framework 등의 의존성 주입이 특징인 프레임워크들에서는 매우 중요한 설계 원칙으로 적용된다.


이상 5가지 SOLID 원칙을 간단하게 정리해봤다. 사실 각 원칙은 예제 코드와 함께 이해하는 것이 가장 좋은 방법이라고 생각한다. 다음 포스팅으로 각각에 대한 예제 코드와 자세한 설명을 다시 정리해보려고 한다.