프로그래밍 패러다임과 구조적 프로그래밍
구조적 프로그래밍(Structed Programming)
구조적 프로그래밍은 제어흐름의 직접적인 전환에 대해 규칙을 부과한다.
최초로 적용된 패러다임이다. 데이크스트라는 무분별한 점프(goto
)는 프로그램 구조에 해롭다는 사실을 제시했다. 이러한 점프문들을 if/then/else와 do/while/until과 같은 구조로 대체했다.
객체 지향 프로그래밍(Object-oriented Programming)
객체 지향 프로그래밍은 제어흐름의 간접적인 전환에 대해 규칙을 부과한다.
알골(ALGOL) 언어의 함수 호출 stack frame을 heap으로 옮기면, 함수 호출이 반환된 이후에도 함수에서 선언된 지역 변수가 오랫동안 유지될 수 있음을 발견했다. 이런 함수가 클래스의 생성자가 되었고, 지역 변수는 인스턴스 변수, 중첩 함수는 메서드가 되었다.
함수 포인터를 특정 규칙에 따라 사용하는 과정을 통해 필연적으로 다형성이 등장했다.
함수형 프로그래밍(Functional Programming)
함수형 프로그래밍은 할당문에 대해 규칙을 부과한다.
알론조 처치(Alonzo Church)가 발명한 람다(lambda) 계산법이 LISP 언어의 근간이 되었다. 람다 계산법의 기초가 되는 개념은 불변성(immutability)으로, 심볼의 값이 변경되지 않는다는 개념이다.
생각할 거리
각 패러다임은 무엇을 해야 할지를 말하기보다, 무엇을 해서는 안 되는지를 말해준다.
- 구조적 프로그래밍 : goto문
- 객체 지향 프로그래밍 : 함수 포인터
- 함수형 프로그래밍 : 할당문 프로그래밍 패러다임은 앞으로도 위의 세 가지밖에 없을 것이다.
구조적 프로그래밍
데이크스트라가 초기에 인식한 문제는 프로그래밍은 어렵고, 프로그램은 인간의 두뇌로 감당하기에는 너무 많은 세부사항을 담고 있다는 것이다. 데이크스트라는 증명(proof)이라는 수학적인 원리를 적용하여 해결하고자 했다. 그는 공리, 정리, 따름정리, 보조정리로 구성되는 유클리드 계층구조 방식을 프로그래머도 사용할 수 있다고 믿었다.
이 연구를 진행하면서 goto 문장이 재귀적으로 분해하는 과정에서 방해가 된는 경우가 있다는 것을 발견했다. goto 문장이 문제가 되지 않는 경우도 있었는데, 이는 if/then/else와 do/while과 같은 분기와 반복으로 바꿀 수 있다는 것을 발견했다.
뵘과 야코피니는 모든 프로그램을 순차(sequence), 분기(selection), 반복(iteration) 구조로 표현할 수 있다는 사실을 증명했다. 데이크스트라는 제어 구조를 아래와 같이 입증했다.
- 순차 : 단순한 열거법을 이용해 순차 구문이 올바름을 입증
- 분기 : 열거법을 재적용하는 방식으로 입증(분기를 통한 각 경로를 열거)
- 반복 : 귀납법 사용, 반복의 시작 조건과 종료 조건에는 열거법을 통해 증명
1968년 3월에 CACM에 실린 데이크스트라의 “goto문의 해로움” 서한은 많은 논쟁을 일으켰고, 10년 이상 지속되었다. 하지만 컴퓨터 언어가 진화하면서 goto 문장은 거의 사라졌고, 데이크스트라가 승리했다. 현재의 우리 모두는 구조적 프로그래머이다. 선택의 여지가 없다.
구조적 프로그래밍을 통해 모듈을 증명 가능한 더 작은 단위로 재귀적으로 분해할 수 있게 되었다. 이를 이용하여 대규모 시스템을 모듈과 컴포넌트로 나눌 수 있고, 더 나아가 입증할 수 있는 아주 작은 기능들로 세분화할 수 있다.
하지만 끝내 프로그램 관점에서 정리한 유클리드 계층구조는 만들어지지 않았다. 오늘날 고품질의 소프트웨어를 생산하기 위해 엄밀한 증명이 적절한 방법이라고 믿는 프로그래머는 거의 없다.
무언가가 올바른지 입증할 때 사용하는 또 다른 전략으로는 과학적 방법(scientific method)가 있다. 과학과 수학은 근본적으로 다른데, 과학 이론과 법칙은 그 올바름을 절대 증명할 수 없기 때문이다. F=ma를 증명할 수 없다. 언젠가는 다른 실험을 통해 이 법칙이 잘못되었음이 밝혀질 가능성이 항상 열려 있다.
과학은 각고의 노력으로도 반례를 찾을 수 없다면 그 서술은 참이라고 본다. 데이크스트라는 “테스트는 버그가 있음을 보여줄 뿐, 버그가 없음을 보여줄 수는 없다”라고 말했다. 테스트에 충분한 노력을 들였다면, 그 프로그램이 충분히 참이라고 여기는 것이 전부다.
소프트웨어는 과학과 같고, 따라서 반증 가능성에 의해 주도된다. 소프트웨어 아키텍트는 모듈, 컴포넌트, 서비스가 쉽게 반증 가능하도록(테스트하기 쉽도록) 만들기 위해 노력해야 한다.
Clean Architecture Chapter 3, 4