소프트웨어 아키텍처는 코드(code)로부터 시작한다. 따라서 아키텍처에 대한 논의도 코드가 최초로 작성된 시점부터, 우리가 코드를 통해 배운 내용을 살펴보는 데서 출발하고자 한다.
코드의 탄생: 1945–1950년
1945년 앨런 튜링(Alan Turing)은 영국 국립물리연구소(NPL)에서 ACE(Automatic Computing Engine)의 설계를 제안했다. 이 설계에는 반복문, 분기문, 할당문, 서브루틴(Subroutine), 스택(Stack) 등 오늘날에도 익숙한 구조가 이미 담겨 있었다. 실제로 사람이 식별할 수 있는 형태의 프로그램이 물리적 컴퓨터에서 실행된 것은 이보다 조금 뒤인 1948–1950년, 맨체스터의 실험 기계와 NPL의 Pilot ACE(튜링의 설계를 축소 구현한 기종)에서였다. 이 초기 프로그램들은 바이너리 언어로 작성되었다.
| |
프로그래밍 언어의 진화
이때 이후로 프로그래밍에는 수많은 혁신적인 변화가 이뤄졌다.
어셈블러의 등장 (1940년대 후반)
1940년대 후반 어셈블러(Assembler)가 처음으로 등장했다. 이 ‘언어’의 등장으로, 바이너리 코드로 프로그램을 작성해야 했던 프로그래머의 단조롭고 고된 일이 줄어들었다.
| |
최초의 컴파일러: A-0 (1951년)
1951–1952년 그레이스 호퍼(Grace Hopper)는 최초의 컴파일러로 널리 알려진 A-0를 완성했다. ‘컴파일러(compiler)‘라는 용어도 그레이스가 만든 것으로 알려져 있다(다만 “최초의 컴파일러” 타이틀에는 정의에 따라 이견도 있다).
고급 언어의 홍수
포트란(Fortran)은 1954년 존 배커스(John Backus)가 이끄는 IBM 팀이 설계를 제안했고, 1957년 최초의 컴파일러가 출시되었다. 이처럼 새로운 프로그래밍 언어는 쉴 틈 없이 홍수처럼 쏟아졌다. 아래 연표는 그 흐름 중 이후 패러다임 논의와 직접 연결되는 언어들만 추려 정리한 것이다 — Fortran과 COBOL은 절차 지향의 초기 형태를, C는 구조적 프로그래밍의 정착을, C++·Java는 이후 살펴볼 객체 지향 패러다임의 주류화를 각각 대표한다.
timeline
title 프로그래밍 언어의 역사
1957 : Fortran
1959 : COBOL
1964 : PL/1
1970 : Pascal
1972 : C
1983 : C++
1995 : Java
2000 : C#
| 연도 | 언어 | 특징 |
|---|---|---|
| 1957 | Fortran | 과학 계산용 최초의 고급 언어(설계는 1954년 시작) |
| 1959 | COBOL | 비즈니스 처리용 |
| 1970 | Pascal | 교육용, 구조적 프로그래밍 |
| 1972 | C | 시스템 프로그래밍(데니스 리치, Bell Labs) |
| 1983 | C++ | 객체 지향 + C |
| 1995 | Java | 플랫폼 독립적 |
프로그래밍 패러다임의 혁명
또 다른, 아마도 더 중요한 혁신적인 변화가 프로그래밍 패러다임(Paradigm)에도 몰아쳤다.
패러다임이란?
마틴은 패러다임을 이렇게 정의한다: 패러다임이란 프로그래밍을 하는 방법으로, 대체로 언어에는 독립적이다(Martin, Clean Architecture, 2017).
패러다임은 어떤 프로그래밍 구조를 사용할지, 그리고 언제 이 구조를 사용해야 하는지를 결정한다.
세 가지 패러다임
현재까지 이러한 패러다임에는 세 가지 종류가 있다:
flowchart TB
subgraph Paradigms [세 가지 프로그래밍 패러다임]
SP[구조적 프로그래밍
1968년 데이크스트라]
OOP[객체 지향 프로그래밍
1967년 달/니가드]
FP[함수형 프로그래밍
1936년 처치]
end
subgraph Restrictions [제한하는 것]
R1[goto 문]
R2[함수 포인터]
R3[할당문]
end
SP -->|제한| R1
OOP -->|제한| R2
FP -->|제한| R3
| 패러다임 | 등장 시기 | 제한하는 것 | 아키텍처 적용 |
|---|---|---|---|
| 구조적 프로그래밍 | 1968년 | goto 문 | 모듈의 기반 알고리즘 |
| 객체 지향 프로그래밍 | 1967년 | 함수 포인터 | 경계를 넘나드는 다형성 |
| 함수형 프로그래밍 | 1936년 | 할당문 | 데이터 위치와 접근 규칙 |
패러다임과 아키텍처의 관계
각 패러다임은 아키텍처에 직접적인 영향을 미친다:
구조적 프로그래밍 → 알고리즘
구조적 프로그래밍은 goto를 없애고 순차·선택·반복 세 가지 제어 구조만 허용함으로써, 함수 내부의 알고리즘을 증명 가능하고 예측 가능한 형태로 제한한다. 아래 코드는 이 세 구조만으로 로직을 표현한 예다.
| |
객체 지향 프로그래밍 → 경계와 다형성
OOP는 함수 포인터의 위험한 사용을 다형성이라는 안전한 형태로 제한한다. 이 다형성 덕분에 고수준 코드가 저수준 구현을 몰라도 되는 경계(포트/어댑터 패턴의 기반)를 그을 수 있다.
| |
함수형 프로그래밍 → 불변성과 데이터 흐름
FP는 할당문(변수 재대입)을 제한함으로써 데이터가 어디서 변경되는지 추적할 필요를 없앤다. 아래 코드는 원본 리스트를 변경하지 않고 새 리스트를 만들어내는 방식을 보여준다.
| |
이 파트에서 다룰 내용
flowchart LR
P2[Part 2: 패러다임] --> C10[10장: 패러다임 개요]
P2 --> C11[11장: 구조적 프로그래밍]
P2 --> C12[12장: 객체 지향 프로그래밍]
P2 --> C13[13장: 함수형 프로그래밍]
이 시리즈에서는 원저 Part 2(패러다임)의 4개 챕터가 10–13장으로 이어진다.
| 장 | 제목 | 핵심 내용 |
|---|---|---|
| 10장 | 패러다임 개요 | 세 패러다임의 부정적 규칙 |
| 11장 | 구조적 프로그래밍 | goto 문 제거와 증명 가능한 프로그램 |
| 12장 | 객체 지향 프로그래밍 | 다형성과 의존성 역전 |
| 13장 | 함수형 프로그래밍 | 불변성과 동시성 |
흔한 오해
오해 1: “세 패러다임은 서로 대체 관계이므로, 최신 패러다임을 쓰면 이전 패러다임은 필요 없다.” 구조적 프로그래밍(1968)→객체 지향(1967)→함수형(1936)이라는 연대만 보면 마치 뒤의 것이 앞의 것을 대체하는 진화처럼 보이지만, 실제로는 세 패러다임이 서로 다른 축을 제한하므로 함께 쓰인다. 위 “다형성을 통한 경계 횡단” 예제의 MySqlRepository.save() 메서드 내부는 여전히 순차·선택·반복이라는 구조적 프로그래밍의 제약을 따르고, 그 위에 OOP의 다형성이 경계를 그으며, 필요하면 그 안에서 다시 FP의 불변성을 적용할 수 있다. 세 패러다임은 대체가 아니라 중첩되는 규율이다.
오해 2: “언어가 특정 패러다임을 지원하면, 그 언어로 짠 코드는 자동으로 그 패러다임을 따른다.” Java가 다형성을 문법으로 지원한다고 해서 모든 Java 코드가 저절로 OOP 원칙을 지키는 것은 아니다. if (type.equals("mysql")) { ... } else if (type.equals("mongo")) { ... }처럼 조건문으로 분기하는 코드는 Java로 작성됐어도 다형성을 전혀 활용하지 않은, OOP의 규율을 어긴 코드다. 언어의 지원 여부와 실제 코드가 그 규율을 따르는지는 별개이며, 이 구분은 아래 판단 기준 절에서 다시 다룬다.
핵심 요약
마틴은 이렇게 요약한다: 아키텍처의 벽돌은 패러다임이다. 패러다임은 무엇을 해서는 안 되는지를 알려줌으로써, 우리가 더 나은 구조를 만들도록 이끈다(Martin, Clean Architecture, 2017).
| 항목 | 설명 |
|---|---|
| 코드의 시작 | 1945년 튜링의 ACE 설계, 1948–1950년 실제 실행 |
| 패러다임의 수 | 딱 3가지 (앞으로도 추가 없음) |
| 패러다임의 본질 | 프로그래머에게서 무언가를 빼앗음 |
| 아키텍처와의 관계 | 모든 패러다임이 아키텍처에 영향 |
비판적 시각
“패러다임은 정확히 3개뿐이며 앞으로도 늘지 않는다"는 마틴의 주장은 논쟁적이다. 이는 각 패러다임이 “무엇을 금지하는가"라는 기준으로 분류했을 때 성립하는 주장이며, 실제로 논리형 프로그래밍(Prolog)이나 액터 모델(Erlang) 등은 이 3분류에 깔끔하게 들어맞지 않는다는 반론도 있다. 또한 대부분의 현대 언어(Java, Python, TypeScript 등)는 세 패러다임의 요소를 함께 지원하는 다중 패러다임 언어이므로, “언어=패러다임"으로 단순화해 이해하지 않는 것이 중요하다.
판단 기준
세 패러다임을 “언제 적용할지” 고민할 때는, 이미 사용 중인 언어가 그 규율을 문법으로 강제하는지부터 확인하는 것이 실용적이다. 예를 들어 goto가 아예 없는 언어(Java, Python 등)에서는 구조적 프로그래밍 규율을 의식적으로 지킬 필요가 없지만, 다형성(OOP)이나 불변성(FP)은 언어가 지원하더라도 강제하지 않으므로 코드 리뷰나 아키텍처 경계 설계 시 의도적으로 적용 여부를 판단해야 한다. 레거시 코드를 검토할 때도 이 3구분(“이 코드가 goto·함수포인터·할당문 중 무엇을 얼마나 규율하고 있는가”)을 체크리스트로 쓰면 어떤 패러다임 원칙이 느슨한지 빠르게 진단할 수 있다.
학습 목표
이 장을 읽은 후 다음을 할 수 있어야 한다.
- 코드→어셈블러→컴파일러→고급 언어로 이어지는 발전이 왜 아키텍처 논의의 출발점이 되는지 설명할 수 있다.
- 세 가지 패러다임이 각각 무엇을 “금지"하는지, 그리고 그 금지가 왜 아키텍처에 영향을 주는지 설명할 수 있다.
- “패러다임은 정확히 3개"라는 주장의 한계를 예를 들어 설명할 수 있다.
참고 자료
- Martin, R. C. (2017). Clean Architecture: A Craftsman’s Guide to Software Structure and Design. Prentice Hall.
다음 장에서는 이 세 가지 패러다임을 더 자세히 살펴보고, 각 패러다임이 아키텍처에 어떤 영향을 미치는지 알아본다.
![Featured image of post [Clean Architecture] 09. 프로그래밍 패러다임 서론](/post/clean-architecture/programming-paradigms-introduction/wordcloud_hu_45180fe36024232a.webp)
![[Clean Architecture] 07. 설계와 아키텍처란?](/post/clean-architecture/design-vs-architecture-definition/wordcloud_hu_c4c64caad0472102.webp)
![[Clean Architecture] 08. 두 가지 가치: 행위와 구조](/post/clean-architecture/two-values-behavior-structure/wordcloud_hu_4d168768760e9072.webp)
![[Clean Architecture] 09. 프로그래밍 패러다임 서론](/post/clean-architecture/programming-paradigms-introduction/wordcloud_hu_2ead64fb71b1382e.webp)
![[Clean Architecture] 10. 패러다임 개요: 세 가지 패러다임](/post/clean-architecture/paradigm-overview-three-types/wordcloud_hu_4a8000378ad274b.webp)
![[Clean Architecture] 11. 구조적 프로그래밍](/post/clean-architecture/structured-programming-goto-elimination/wordcloud_hu_1e5cd083abaa560f.webp)
![[Rust] Comprehensive Rust 무료 강의 정리 및 코스 구조](/post/2022-12-30-comprehensive-rust/wordcloud_hu_d1420ff38434cdb6.webp)
![[Hardware] LattePanda Alpha에 Ubuntu 16.04 LTS 설치 가이드](/post/2018-12-06-install-ubuntu-16.04-on-lattepanda/wordcloud_hu_fc536f8de2cbd4bf.webp)
![[Clean Architecture] 12. 객체 지향 프로그래밍](/post/clean-architecture/object-oriented-programming-polymorphism/wordcloud_hu_66479534e61250c6.webp)
![[Clean Architecture] 17. LSP: 리스코프 치환 원칙](/post/clean-architecture/lsp-liskov-substitution-principle/wordcloud_hu_f3cf91f896fa3ec8.webp)
![[Clean Architecture] 18. ISP: 인터페이스 분리 원칙](/post/clean-architecture/isp-interface-segregation-principle/wordcloud_hu_97294a781cdf31b4.webp)