객체지향 설계 원칙(SOLID)
객체지향 프로그래밍(OOP)은 단순히 클래스를 사용하는 것만으로 끝나지 않습니다. 진짜 중요한 것은 "좋은 객체지향 설계"를 통해 소프트웨어를 유지보수하기 쉽고, 확장 가능하게 만드는 것입니다. 이를 위해 꼭 알아야 할 설계 원칙이 바로 SOLID입니다.
이번 글에서는 SOLID가 무엇인지, 각 원칙을 하나하나 쉽고 깊게 살펴보겠습니다.
1. SOLID란 무엇인가?
SOLID는 객체지향 프로그래밍에서 '좋은 설계'를 만들기 위해 제시된 5가지 핵심 원칙의 앞글자를 모은 약어입니다. 로버트 C. 마틴(Robert C. Martin), 일명 "아저씨(Uncle Bob)"가 제안했습니다.
- S : Single Responsibility Principle (단일 책임 원칙)
- O : Open/Closed Principle (개방-폐쇄 원칙)
- L : Liskov Substitution Principle (리스코프 치환 원칙)
- I : Interface Segregation Principle (인터페이스 분리 원칙)
- D : Dependency Inversion Principle (의존 역전 원칙)
이 원칙들은 유연하고, 확장 가능하며, 유지보수하기 좋은 소프트웨어를 만들기 위한 기본 철학입니다.
2. SOLID 5대 원칙 자세히 알아보기
a. 단일 책임 원칙 (SRP)
"클래스는 하나의 책임만 가져야 한다."
- 하나의 클래스는 오직 하나의 기능만을 담당해야 합니다.
- 여러 책임을 가진 클래스는 변경의 이유가 여러 개가 되어, 유지보수가 어려워집니다.
예시 코드 (Python)
# Bad Example: 여러 책임을 가진 클래스
class Report:
def generate_report(self):
pass
def save_to_file(self):
pass
# Good Example: 책임을 분리
class ReportGenerator:
def generate(self):
pass
class FileSaver:
def save(self, report):
pass
b. 개방-폐쇄 원칙 (OCP)
"확장에는 열려 있어야 하고, 수정에는 닫혀 있어야 한다."
- 새로운 기능 추가는 기존 코드를 수정하지 않고 확장으로 해결해야 합니다.
- 변경이 잦으면 기존 기능이 깨질 위험이 높아집니다.
예시 코드 (Python)
# 확장 가능한 형태로 구성
class Shape:
def area(self):
pass
class Rectangle(Shape):
def area(self):
return self.width * self.height
class Circle(Shape):
def area(self):
return 3.14 * self.radius * self.radius
- 새로운 도형이 추가되더라도 Shape 인터페이스만 지키면 기존 코드를 건드릴 필요가 없습니다.
c. 리스코프 치환 원칙 (LSP)
"서브타입은 언제나 기반 타입으로 교체할 수 있어야 한다."
- 부모 클래스 객체를 사용하는 곳에 자식 클래스 객체를 대신 넣어도 프로그램이 정상 동작해야 합니다.
예시 코드 (Python)
class Bird:
def fly(self):
pass
class Sparrow(Bird):
def fly(self):
print("Sparrow flies!")
class Ostrich(Bird):
def fly(self):
raise Exception("Ostrich can't fly!") # ❌ 위반 사례
- 날지 못하는 Ostrich를 Bird로 다루면 문제가 발생합니다. 설계를 다시 해야 합니다.
- 예: Flyable 인터페이스 분리
d. 인터페이스 분리 원칙 (ISP)
"클라이언트는 자신이 사용하지 않는 인터페이스에 의존하면 안 된다."
- 하나의 거대한 인터페이스를 여러 개의 구체적인 인터페이스로 나누어야 합니다.
예시 코드 (Python)
# 나쁜 예
class Worker:
def work(self):
pass
def eat(self):
pass
# 좋은 예 - 인터페이스 분리
class Workable:
def work(self):
pass
class Eatable:
def eat(self):
pass
- 로봇은 일만 하고 식사는 필요 없을 수도 있잖아요? 이렇게 필요한 것만 구현하게 합니다.
e. 의존 역전 원칙 (DIP)
"고수준 모듈은 저수준 모듈에 의존해서는 안 된다. 둘 다 추상화에 의존해야 한다."
- 구체적 구현이 아닌 추상화(인터페이스, 추상 클래스 등)에 의존해야 합니다.
예시 코드 (Python)
# DIP 위반 예
class Keyboard:
pass
class Computer:
def __init__(self):
self.keyboard = Keyboard()
# DIP 준수 예
class IKeyboard:
def input(self):
pass
class Keyboard(IKeyboard):
def input(self):
return "typing..."
class Computer:
def __init__(self, keyboard: IKeyboard):
self.keyboard = keyboard
- Computer 는 이제 IKeyboard 라는 추상화에만 의존하여 유연성이 높아집니다.
3. SOLID 원칙을 지키면 좋은 점
- 코드 재사용성 증가
- 유지보수 비용 감소
- 버그 발생 가능성 감소
- 팀 간 협업 시 명확한 규칙 제공
- 대규모 시스템 확장 시 안정성 확보
4. 마무리
SOLID는 객체지향 프로그래밍을 넘어 현대 소프트웨어 설계의 기본 원칙으로 자리 잡았습니다. 각 원칙은 독립적으로도 중요하지만, 서로 조합될 때 훨씬 더 강력한 효과를 발휘합니다. 좋은 설계는 우연히 만들어지는 것이 아니라, SOLID 같은 원칙을 체계적으로 적용하려는 노력에서 나옵니다. 초반에는 약간 번거로울 수 있지만, 프로젝트 규모가 커질수록 SOLID의 중요성은 빛을 발합니다.
함께 보면 좋은 자료
외부 사이트 :
'컴퓨터 사이언스 > 소프트웨어 개발 방법론' 카테고리의 다른 글
[요구사항 명세 기법] 프로젝트 성공을 좌우하는 명확한 요구사항 작성법 (0) | 2025.04.29 |
---|---|
[CASE] 개발 생산성을 높이는 자동화 도구 (0) | 2025.04.26 |
[럼바우 분석 기법] 객체지향 분석의 고전, 럼바우 OMT 기법 총정리 (0) | 2025.04.26 |
[TDD] 기능 구현보다 테스트가 먼저다! (0) | 2025.04.14 |
[워터폴과 애자일] 개발 프로젝트에 맞는 방법론은? (0) | 2025.04.13 |