객체 지향 프로그래밍(OOP)은 1966년에 올레 요한 달(Ole Johan Dahl)과 크리스텐 니가드(Kristen Nygaard)가 Simula 67을 개발하면서 시작되었다. 이후 Smalltalk, C++, Java를 거치며 주류 패러다임이 되었다. 하지만 OOP가 아키텍처에 제공하는 진정한 가치는 무엇일까? 로버트 마틴은 그것이 다형성을 통한 의존성 역전이라고 말한다.
객체 지향의 세 기둥
OOP를 설명할 때 흔히 세 가지 특성을 언급한다:
- 캡슐화 (Encapsulation)
- 상속 (Inheritance)
- 다형성 (Polymorphism)
그러나 마틴은 이 세 가지를 비판적으로 분석한다.
캡슐화: OOP의 독점물이 아니다
캡슐화란?
캡슐화는 데이터와 그 데이터를 조작하는 함수를 하나로 묶고, 외부에서 직접 접근하지 못하도록 숨기는 것이다.
| |
C 언어도 캡슐화할 수 있다
마틴은 지적한다: C 언어에서도 캡슐화는 가능했다.
| |
| |
사용자는 Point의 내부 구조를 알 수 없다. 헤더 파일에는 전방 선언만 있고, 실제 구조체 정의는 구현 파일에 숨겨져 있다.
OOP 언어의 약화된 캡슐화
오히려 C++과 Java에서 캡슐화가 약화되었다:
| |
사용자는 private이라 접근할 수 없지만, 변수의 존재와 타입은 알 수 있다. 이것은 C의 전방 선언보다 약한 캡슐화다.
결론: 캡슐화는 OOP의 독점물이 아니며, OOP가 오히려 약화시켰다.
상속: OOP 이전에도 있었다
상속이란?
상속은 기존 데이터 구조에 새로운 필드와 메서드를 추가하여 확장하는 것이다.
| |
C 언어의 상속 (?)
C에서도 비슷한 것이 가능했다:
| |
이것은 진짜 상속은 아니지만, 비슷한 효과를 낼 수 있었다.
결론: 상속은 OOP가 편리하게 만들었지만, 완전히 새로운 것은 아니었다.
다형성: OOP의 진정한 힘
다형성이란?
다형성은 같은 인터페이스로 다른 구현을 호출할 수 있는 능력이다.
| |
함수 포인터로도 가능했다
C에서 함수 포인터를 사용하면 다형성을 구현할 수 있었다:
| |
OOP가 다형성에 가져온 혁신
그렇다면 OOP가 가져온 것은 무엇인가?
OOP는 다형성을 안전하고 편리하게 만들었다.
C의 함수 포인터는:
- 위험하다 (잘못된 타입 캐스팅)
- 복잡하다 (직접 vtable 관리)
- 실수하기 쉽다 (초기화 누락)
OOP 언어는:
- 타입 안전성 보장
- 컴파일러가 vtable 자동 생성
- 문법적으로 명확 (
interface,virtual,override)
다형성의 진정한 힘: 의존성 역전
여기서 마틴은 핵심 통찰을 제시한다.
제어 흐름 vs 소스 코드 의존성
다형성이 없는 세계에서:
flowchart LR
subgraph WithoutPoly [다형성 없는 세계]
A[main] -->|호출| B[ML 함수]
B -->|호출| C[HL 함수]
end
- 제어 흐름: main → ML → HL
- 소스 코드 의존성: main → ML → HL
제어 흐름과 소스 코드 의존성이 같은 방향이다.
다형성이 가져온 변화
다형성을 사용하면:
flowchart LR
subgraph WithPoly [다형성 있는 세계]
A[HL]
B[Interface I]
C[ML]
A -->|사용| B
C -->|구현| B
A -->|호출| C
end
- 제어 흐름: HL → ML (HL이 ML을 호출)
- 소스 코드 의존성: ML → Interface ← HL
ML이 인터페이스를 구현하므로, 소스 코드 의존성은 HL → Interface ← ML
제어 흐름과 소스 코드 의존성이 반대 방향이 될 수 있다!
의존성 역전 (Dependency Inversion)
| |
두 번째 방식에서:
Business는Database인터페이스에 의존MySQLDatabase는Database인터페이스를 구현- 결과적으로
MySQLDatabase가Business의 요구사항에 맞춰야 함
저수준 모듈(DB)이 고수준 모듈(Business)에 의존한다!
플러그인 아키텍처
의존성 역전은 플러그인 아키텍처를 가능하게 한다.
flowchart TB
subgraph Core [비즈니스 로직 코어]
B[Business Logic]
I1[Storage Interface]
I2[UI Interface]
B --> I1
B --> I2
end
subgraph Plugins [플러그인들]
P1[MySQL Plugin]
P2[MongoDB Plugin]
P3[Web UI Plugin]
P4[Mobile UI Plugin]
end
P1 -->|구현| I1
P2 -->|구현| I1
P3 -->|구현| I2
P4 -->|구현| I2
비즈니스 로직 코어는:
- 인터페이스만 정의
- 어떤 DB가 사용되는지 모름
- 어떤 UI가 사용되는지 모름
플러그인들은:
- 인터페이스를 구현
- 코어에 의존
- 교체 가능
아키텍처에서의 OOP
독립적 배포
의존성이 역전되면, 각 컴포넌트를 독립적으로 배포할 수 있다.
flowchart TB
subgraph Deploy [배포 단위]
D1[business.jar]
D2[mysql-adapter.jar]
D3[web-ui.jar]
end
business.jar는 인터페이스만 포함mysql-adapter.jar와web-ui.jar는 인터페이스 구현- 어댑터만 교체하면 다른 DB/UI 사용 가능
독립적 개발
팀을 나눠서 독립적으로 개발할 수 있다:
- 코어 팀: 비즈니스 로직과 인터페이스
- DB 팀: 저장소 어댑터
- UI 팀: 사용자 인터페이스
각 팀은 인터페이스만 지키면 독립적으로 작업 가능하다.
OOP가 아키텍처에 주는 것
| 특성 | 아키텍처적 가치 |
|---|---|
| 캡슐화 | 모듈 경계 정의 (한정적) |
| 상속 | 코드 재사용 (한정적) |
| 다형성 | 의존성 역전, 플러그인 아키텍처 |
“OOP란 다형성을 이용하여 전체 시스템의 모든 소스 코드 의존성에 대한 절대적인 제어 권한을 획득할 수 있는 능력이다.” — Robert C. Martin
핵심 요약
다형성의 힘
flowchart LR
subgraph Before [다형성 없이]
A1[High] -->|의존| B1[Low]
end
subgraph After [다형성으로]
A2[High] -->|사용| I[Interface]
B2[Low] -->|구현| I
end
OOP의 진정한 가치
- 캡슐화: OOP의 독점물 아님
- 상속: 편리해졌지만 새로운 것 아님
- 다형성: 의존성 방향을 제어할 수 있게 함
“객체 지향 프로그래밍은 제어흐름의 간접적인 전환에 대해 규칙을 부과한다.” — Robert C. Martin
OOP는 함수 포인터를 직접 사용하는 것을 금지하고, 대신 안전하고 편리한 다형성을 제공한다. 이 제한 덕분에 아키텍트는 소스 코드 의존성을 완전히 제어할 수 있게 되었다.
다음 장에서는
다음 장에서는 함수형 프로그래밍을 다룬다. 함수형 프로그래밍은 할당문을 제한하여 불변성이라는 강력한 개념을 제공한다. 이것이 아키텍처에 어떤 의미를 가지는지 살펴본다.
![Featured image of post [Clean Architecture] 12. 객체 지향 프로그래밍](/post/cleanarchitecture/12-object-oriented-programming-polymorphism/wordcloud_hu_2f0f6940838bed25.png)
![[Clean Architecture] 10. 패러다임 개요: 세 가지 패러다임](/post/cleanarchitecture/10-paradigm-overview-three-types/wordcloud_hu_ae579d4e672596b5.png)
![[Clean Architecture] 11. 구조적 프로그래밍](/post/cleanarchitecture/11-structured-programming-goto-elimination/wordcloud_hu_8573d6dad9046112.png)
![[Clean Architecture] 12. 객체 지향 프로그래밍](/post/cleanarchitecture/12-object-oriented-programming-polymorphism/wordcloud_hu_6c2b4620fe50d548.png)
![[Clean Architecture] 13. 함수형 프로그래밍](/post/cleanarchitecture/13-functional-programming-immutability/wordcloud_hu_8239244acbc73ee6.png)
![[Clean Architecture] 14. SOLID 원칙 서론](/post/cleanarchitecture/14-solid-principles-introduction/wordcloud_hu_b40e2016719b5d89.png)
![[Clean Architecture] 09. 프로그래밍 패러다임 서론](/post/cleanarchitecture/09-programming-paradigms-introduction/wordcloud_hu_a3a14eb6c48111df.png)
![[Clean Architecture] 16. OCP: 개방-폐쇄 원칙](/post/cleanarchitecture/16-ocp-open-closed-principle/wordcloud_hu_a84054017b47f51d.png)
![[Clean Architecture] 19. DIP: 의존성 역전 원칙](/post/cleanarchitecture/19-dip-dependency-inversion-principle/wordcloud_hu_b2315221135160e2.png)
![[Design Pattern] Factory Method - 팩토리 메서드 패턴](/post/designpattern/03_factory_method/tmp_wordcloud_hu_2ce588d7bdcc9009.png)