Architecture

[클린 아키텍처] 구조적 프로그래밍

tenacy 2021. 8. 9. 10:16

증명

프로그래밍이라는 개념이 등장한 초기에는 프로그래밍이 예상 외의 방식으로 실패하곤 했습니다.

 

데이크스트라는 사람이 증명이라는 수학적인 원리를 적용해 이 문제를 해결하고자 했습니다.

 

연구를 진행하면서 goto 문장이 모듈을 더 작은 단위로 재귀적으로 분해하는 과정에 방해가 되는 경우가 있다는 사실을 발견했습니다. 만약 모듈을 분해할 수 없다면, 합리적으로 증명할 때 필수적인 기법인 분할 정복 접근법을 사용할 수 없게 됩니다.

 

goto 문장을 사용하더라도 모듈을 분해할 때 문제가 되지 않는 경우도 있었지만 그는 보다 더 좋은 사용 방식은 if / then / elsedo / while 과 같은 분기와 반복이라는 단순한 제어 구조에 해당한다는 사실을 발견했습니다.

 

그는 이러한 제어 구조는 순차 실행과 결합했을 때 특별하다는 사실을 깨달았고, 모든 프로그램은 순차, 분기, 반복이라는 세 가지 구조만으로 표현할 수 있다는 사실을 증명했습니다.

 

모듈을 증명 가능하게 하는 제어 구조는 모든 프로그램을 만들 수 있는 제어 구조의 최소 집합과 동일합니다. 구조적 프로그래밍은 이 사실 아래 탄생했습니다.

 

순차

단순한 열거법을 이용해 순차 구문이 올바름을 입증할 수 있습니다. 이 기법에서는 각 순차 구문의 입력을 순차 구문의 출력까지 수학적으로 추적합니다. 이 접근법은 일반적인 수학적 증명 방식과 다를 바 없습니다.

 

분기

분기의 경우 열거법을 재적용하는 방식으로 처리합니다. 먼저 분기를 통한 각 경로를 열거합니다. 결과적으로 두 경로가 수학적으로 적절한 결과를 만들어낸다면, 증명은 신뢰할 수 있게 됩니다.

 

반복

반복은 조금 다릅니다. 반복이 올바름을 증명하기 위해 귀납법을 사용합니다. 열거법에 따라 1의 경우가 올바름을 증명합니다. 그리고 N의 경우가 올바르다고 가정할 때 N+1의 경우도 올바름을 증명하며, 이 경우에도 열거법을 사용합니다. 또한 반복의 시작 조건과 종료 조건도 열거법을 통해 증명합니다.

 

해로운 성명서

현재의 우리 모두는 구조적 프로그래머이며, 여기에는 선택의 여지가 없습니다. 제어흐름을 제약 없이 직접 전환할 수 있는 선택권(예를 들어, 과거의 포트란이나 코볼 같은 언어에서의 제약 없는 goto) 자체를 언어에서 제공하지 않기 때문입니다.

 

기능적 분해

구조적 프로그래밍을 통해 모듈을 증명 가능한 더 작은 단위로 재귀적으로 분해할 수 있게 되었고, 이는 결국 모듈을 기능적으로 분해할 수 있음을 뜻했습니다. 즉, 거대한 문제 기술서를 받어라도 문제를 고수준의 기능들로 분해할 수 있습니다. 그리고 이들 각 기능은 다시 저수준의 함수들로 분해할 수 있고, 이러한 분해 과정을 끝없이 반복할 수 있습니다. 게다가 이렇게 분해한 기능들은 구조적 프로그래밍의 제한된 제어 구조를 이용하여 표현할 수 있습니다.

 

엄밀한 증명은 없었다

하지만 끝내 증명은 이루어지지 않았습니다. 프로그램 관점에서 정리에 대한 유클리드 계층구조는 끝내 만들어지지 않았습니다. 그리고 대개의 프로그래머들은 세세한 기능 하나하나를 엄밀히 증명하는 고된 작업에서 이득을 얻으리라고는 보지 않았습니다.

 

하지만 상당히 성공한 또 다른 전략으로는 과학적 방법이 있었습니다.

 

과학이 구출하다

수학은 증명 가능한 서술이 참임을 입증하는 원리인 반면, 과학은 증명 가능한 서술이 거짓임을 입증하는 원리입니다.

 

테스트

데이크스트라는 이런 말을 했습니다.

 

테스트는 버그가 있음을 보여줄 뿐, 버그가 없음을 보여줄 수는 없다.

 

다시 말해 프로그램이 잘못되었음을 테스트를 통해 증명할 수는 있지만, 프로그램이 맞다고 증명할 수는 없습니다. 테스트가 보장할 수 있는 것은 프로그램이 목표에 부합할 만큼은 충분히 참이라고 여길 수 있게 해주는 것이 전부입니다.

 

이는 소프트웨어 개발은 수학적인 시도가 아니라는 사실을 내포합니다. 오히려 소프트웨어는 과학과 같습니다. 최선을 다하더라도 올바르지 않음을 증명하는 데 실패함으로써 올바름을 보여주기 때문입니다.

 

구조적 프로그래밍은

  1. 프로그램을 증명 가능한 세부 기능 집합을 재귀적으로 분해할 것을 강요합니다.
  2. 그러고 나서 테스트를 통해 증명가능한 세부 기능들이 거짓인지를 증명하려고 시도합니다.

 

이처럼 거짓임을 증명하려는 테스트가 실패한다면, 이 기능들은 목표에 부합할 만큼은 충분히 참이라고 여기게 됩니다.

 

결론

구조적 프로그래밍이 오늘날까지 가치 있는 이유는 프로그램에서 반증 가능한 단위를 만들어 낼 수 있는 바로 이 능력 때문입니다. 또한 흔히 현대적 언어가 아무런 제약 없는 goto 문장은 지원하지 않는 이유이기도 하고, 뿐만 아니라 아키텍처 관점에서는 기능적 분해를 실천법 중 하나로 여기는 이유이기도 합니다.

 

가장 작은 기능에서부터 가장 큰 컴포넌트에 이르기까지 모든 수준에서 소프트웨어는 과학과 같고, 따라서 반증 가능성에 의해 주도됩니다. 소프트웨어 아키텍트는 모듈, 컴포넌트, 서비스가 쉽게 반증 가능하도록 즉, 테스트하기 쉽도록 만들기 위해 분주히 노력해야 합니다. 이를 위해 구조적 프로그래밍과 유사한 제한적인 규칙들을 받아들여 활용해야 합니다.

 

참고

  • 클린 아키텍처 | 로버트 C. 마틴 저/송준이 역 | 인사이트