구조적 프로그래밍
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.
1. 개요
구조적 프로그래밍은 1960년대에 발전한 프로그래밍 패러다임으로, 프로그램의 제어 흐름을 순차, 선택, 반복의 세 가지 구조로 제한하여 코드의 가독성과 유지보수성을 높이는 것을 목표로 한다. 뵘과 야코피니의 구조적 정리와 에츠허르 데이크스트라의 "Go To Statement Considered Harmful" 논문을 통해 그 중요성이 부각되었으며, 하향식 설계, 모듈화, 서브루틴 사용 등의 설계 기법을 포함한다. 구조적 프로그래밍은 프로그래밍 언어의 발전에 영향을 미쳤으며, 프로그래머의 코딩 습관을 개선하는 데 기여했다. 그러나 예외 처리, 상태 기계, 병렬 프로그래밍 등에서는 제약이 존재하며, 현대 프로그래밍에서는 다양한 방식으로 발전, 적용되고 있다.
더 읽어볼만한 페이지
- 전체론 - 색채론
- 전체론 - 피에르 테야르 드 샤르댕
피에르 테야르 드 샤르댕은 프랑스의 예수회 사제이자 철학자, 고생물학자, 지질학자로, 진화론적 관점에서 우주와 인간의 기원과 미래를 탐구하며 과학과 신학을 융합하려 했고, '노스피어'와 '오메가 포인트' 개념을 제시하여 기독교적 진화론 체계를 구축했다. - 에츠허르 데이크스트라 - 교착 상태
교착 상태는 둘 이상의 프로세스가 자원을 점유하고 서로의 자원을 요청하여 더 이상 진행할 수 없는 상태를 의미하며, 상호 배제, 점유 대기, 비선점, 순환 대기 네 가지 조건이 모두 충족되어야 발생하고, 운영 체제는 이를 예방, 회피, 무시, 발견하는 방법으로 관리한다. - 에츠허르 데이크스트라 - 세마포어
세마포어는 데이크스트라가 고안한 정수 변수로, P/V 연산을 통해 자원 접근을 제어하고 동기화 문제를 해결하며, 계수 세마포어와 이진 세마포어로 나뉘어 멀티스레드 환경에서 자원 관리 및 스레드 동기화에 기여한다. - 프로그래밍 패러다임 - 지식 표현
지식 표현은 컴퓨터가 인간의 지식을 이해하고 활용하도록 정보를 구조화하는 기술이며, 표현력과 추론 효율성의 균형, 불확실성 처리 등을 핵심 과제로 다양한 기법과 의미 웹 기술을 활용한다. - 프로그래밍 패러다임 - 의도적 프로그래밍
의도적 프로그래밍은 프로그래머의 의도를 명확히 포착하고 활용하여 소프트웨어 개발 생산성을 향상시키기 위한 프로그래밍 패러다임으로, 트리 기반 저장소를 사용해 코드 의미 구조를 보존하고, WYSIWYG 환경에서 도메인 전문가와 협업하며, 코드 상세 수준 조절 및 자동 문서화를 통해 가독성과 유지보수성을 높이는 데 중점을 둔다.
구조적 프로그래밍 | |
---|---|
개요 | |
![]() | |
정의 | 컴퓨터 프로그래밍의 한 방법으로, 프로그램의 논리적 구조를 명확하게 만드는 것을 목표로 함 |
주요 원칙 | 순차 선택 반복 구조만을 사용하여 프로그램의 제어 흐름을 단순화함 |
역사적 배경 | |
등장 배경 | 1960년대 후반, 복잡한 프로그램에서 'goto' 문의 무분별한 사용으로 인한 문제점을 해결하기 위해 등장 |
주요 인물 | 에츠허르 W. 데이크스트라 코라도 뵈 주세페 야코피니 |
데이크스트라의 주장 | 'goto' 문을 사용하지 않고도 모든 프로그램을 작성할 수 있다고 주장 |
기본 구조 | |
순차 구조 | 문장들이 순서대로 실행됨 |
선택 구조 | 조건에 따라 실행되는 문장이 달라짐 (if-then-else) |
반복 구조 | 특정 조건이 만족될 때까지 문장들이 반복됨 (while, for) |
장점 | |
가독성 향상 | 프로그램의 논리적 흐름을 쉽게 이해할 수 있음 |
유지보수성 향상 | 프로그램 수정 및 디버깅이 용이함 |
신뢰성 향상 | 오류 발생 가능성이 줄어들어 프로그램의 안정성이 높아짐 |
단점 | |
성능 저하 가능성 | 특정 경우에는 'goto' 문을 사용하는 것보다 성능이 떨어질 수 있음 |
복잡한 로직 표현의 어려움 | 복잡한 제어 흐름을 표현하기 위해 더 많은 코드가 필요할 수 있음 |
적용 | |
적용 시점 | 프로그램 설계 단계에서부터 적용하는 것이 효과적임 |
프로그래밍 언어 | C Pascal Ada 등 대부분의 현대적인 프로그래밍 언어들이 구조적 프로그래밍을 지원함 |
같이 보기 | |
관련 개념 | 모듈러 프로그래밍 객체 지향 프로그래밍 함수형 프로그래밍 |
참고 문헌 | |
참고 서적 | Comparative programming languages (Leslie B. Wilson, Robert G. Clark, 2000) |
기타 | |
관련 용어 | goto 문 프로그래밍 패러다임 |
2. 역사
구조적 프로그래밍의 등장은 1960년대부터 심각해진 소프트웨어 위기 문제와 밀접한 관련이 있다. 당시 컴퓨터 성능 발전에 따라 소프트웨어의 규모와 복잡성이 급증하면서, 정해진 기간과 예산 내에 프로그램을 개발하는 것이 점점 어려워졌다.[20] 많은 프로그램이 goto문을 남발하여 스파게티 코드처럼 얽히기 일쑤였고, 이는 유지보수를 극도로 어렵게 만들었다.[21][22] 이미 1959년 컴퓨터 과학자 하인츠 체마넥은 goto문의 과도한 사용에 대해 경고한 바 있으며, 1960년 공개된 프로그래밍 언어 ALGOL60은 `BEGIN`과 `END`로 묶인 코드 블록과 `IF` 선택문, `FOR` 반복문 같은 구조적 제어문을 처음 도입했다. 니클라우스 비르트는 이를 '구조적 문'(structured statement)이라 불렀다.[23] 1966년에는 코라드 뵈름과 주세페 야코피니가 모든 플로우차트는 순차, 선택, 반복이라는 세 가지 기본 구조만으로 표현될 수 있음을 수학적으로 증명했는데[24], 이는 이후 구조적 프로그래밍의 이론적 토대가 되었다. 컴퓨터 과학자 도널드 커누스는 이러한 초기 흐름을 구조적 프로그래밍 논의의 '제1막'으로 보았다.[22]
본격적인 논의는 1968년 컴퓨터 과학자 에츠허르 데이크스트라가 ACM 학술지에 기고한 "Go To Statement Considered Harmful"(goto문은 해롭다)이라는 도발적인 제목의 글로 촉발되었다.[25] 이 글은 프로그래밍 커뮤니티에 큰 파장을 일으키며 이른바 'goto문 논쟁'을 불러왔고[26][27], 구조적 제어문의 중요성에 대한 인식을 높이는 계기가 되었다.[28] 커누스는 이를 '제2막'이라 칭하며, 그 파급력 때문에 많은 이들이 이를 구조적 프로그래밍 논의의 시작으로 여겼다고 평가했다.[29] 1968년 NATO 소프트웨어 공학 회의에서는 소프트웨어 위기가 공식 용어로 채택되었고[30], 산업계와 학계의 공동 관심사로 부상했다.[32] 이듬해인 1969년 같은 회의에서 데이크스트라는 "Structured Programming"(구조적 프로그래밍)이라는 제목의 논문을 발표했는데[19], 이것이 '구조적 프로그래밍'이라는 용어의 공식적인 첫 등장이었다. 이 논문에서 데이크스트라는 소프트웨어 위기의 해결책으로 프로그램의 정당성 검증 기술 확립을 주장하며, 프로그램을 적절히 분할하고 추상화하여 잘 구조화하면 프로그램 규모와 관계없이 정확성을 증명할 수 있다고 역설했다. 이를 위한 구체적인 기법으로 톱다운 설계, 단계적 추상화, 계층적 모듈화 등을 제시했다.
한편, 산업계에서는 다른 방향으로 구조적 프로그래밍 개념이 퍼져나갔다. IBM의 선임 연구원 할란 밀스는 순차, 선택, 반복이라는 제어 구조를 중시하며 뉴욕 타임스의 뉴스 아카이브 시스템 구축 프로젝트를 성공적으로 이끌었다. 이 성공 사례를 바탕으로 IBM은 자사의 프로그래밍 표준인 'IPT'(Improved Programming Technologies)에 제어 구조를 핵심 요소로 포함시켰고, 기술 세미나 등을 통해 이를 널리 보급했다.[33][34] 이는 추상화와 프로그램 검증을 강조했던 데이크스트라의 원래 의도와는 다소 거리가 있는 해석이었고[39][40][41], 구조적 프로그래밍이 단순히 제어 구조를 사용하는 것으로 인식되는 경향을 낳았다.[38] 커누스는 IBM과 밀스가 주도한 이러한 제어 구조 중심의 확산을 '제3막'으로 규정하며, 이것이 구조적 프로그래밍에 대한 일반적인 인식을 형성했다고 보았다.
후일 데이크스트라는 자신이 만든 '구조적 프로그래밍'이라는 용어가 본래 의도와 달리, 단순히 생산성을 높이기 위한 실용적인 기법 정도로 변질된 것에 대해 불쾌감을 느끼고 이 용어 사용을 피하게 되었다고 술회했다.[42][31] 그는 이 용어를 만들 때 프로그래밍이 단순한 기술(수공예)을 넘어 과학으로 발전하기를 기대했지만[31], 현실에서는 단순히 생산성을 높이는 방법처럼 여겨지기도 했다.[43]
데이크스트라가 본래 구상했던 구조적 프로그래밍은 프로그램 정확성 검증을 목표로 한 포괄적인 개발 방법론이었다. 여기에는 goto문 없는 제어 흐름(1968), 하향식 설계, 추상화, 모듈화, 공동 상세화(1969), 그리고 이후 추가된 추상 데이터 구조, 정보 은닉, 계층적 프로그램 구조(1972) 등의 개념이 포함되었다.[45][39][33] 1972년 그가 올레-요한 달, 토니 호어와 함께 쓴 저서 《Structured Programming》은 데이크스트라의 구조적 프로그래밍 이론으로 시작하여, 객체 지향 프로그래밍 언어의 시초인 Simula67 개발자 중 한 명인 달의 계층적 프로그램 구조 이론으로 마무리되는데, 이는 구조적 프로그래밍이 이후 객체 지향 프로그래밍으로 이어지는 중요한 사상적 기반이 되었음을 시사한다.
2. 1. 이론적 기반
구조적 프로그램 정리는 구조적 프로그래밍의 이론적 기반을 제공한다.[2][3] 이 정리에 따르면, 프로그램을 구성하는 세 가지 기본적인 제어 구조, 즉 명령어를 순서대로 실행하는 순차(sequence), 조건에 따라 실행 경로를 바꾸는 분기(selection 또는 condition), 특정 조건이 만족될 때까지 코드 블록을 반복 실행하는 반복(repetition 또는 iteration)만으로 모든 계산가능 함수를 표현할 수 있다.이러한 구조는 중앙 처리 장치(CPU)의 명령 주기나 튜링 기계의 작동 방식을 설명하는 데에도 충분하며, 이는 프로세서가 메모리의 어느 부분에서 명령을 읽어오든 본질적으로는 항상 '구조적 프로그램'을 실행하고 있음을 의미한다.
구조적 프로그래밍의 이론적 기반은 1966년 뵘(Böhm)과 야코피니(Jacopini)가 발표한 논문[24]에서 비롯되었다고 여겨진다. 이는 데이크스트라가 이 논문을 인용하면서 널리 알려지게 되었다. 그러나 뵘과 야코피니의 증명 자체는 플로우차트로 표현될 수 있는 모든 프로그램(또는 함수, 튜링 기계 등)이 순차, 분기, 반복만으로 구성될 수 있다는 이론적 가능성을 보인 것으로, 좋은 프로그램을 어떻게 작성하고 분석해야 하는지에 대한 구체적인 방법론을 제시하지는 않았다. 이는 마치 모든 논리 회로가 NAND 소자만으로 구현될 수 있다는 사실이 실제 회로 설계 방법을 직접적으로 알려주지 않는 것과 비슷하다.
실질적으로 유용하고 구조화된 프로그램을 작성하고 분석하는 방법에 대한 연구는 1960년대 후반과 1970년대 초반에 활발히 이루어졌으며, 데이크스트라, 로버트 플로이드, 토니 호어, 데이비드 그라이스 등이 이 분야에 크게 기여했다.
1970년대 초, 컴퓨터 과학자 데이비드 하렐은 뵘과 야코피니의 증명에 '구조적 정리'(Structure theorem)라는 새로운 이름을 붙여 산업계에 소개했다. 하렐은 이 명칭이 당시 IBM의 선임 프로그래머였던 할란 밀스의 제안이었다고 후에 밝혔다.[36][37] IBM은 할란 밀스 주도로 개발한 프로그래밍 규범인 IPT(Improved Programming Technologies)를 보급하면서, 순차, 선택, 반복이라는 제어 구조의 합리성을 뒷받침하는 근거로 이 '구조적 정리'를 자주 인용했다.[33][34] 이로 인해 많은 프로그래머들 사이에서 구조적 프로그래밍이 제어 구조의 사용과 동일시되고, 심지어 IBM의 발명품처럼 여겨지기도 했다.[38] 이는 데이크스트라가 소프트웨어 위기를 극복하기 위해 강조했던 추상화, 프로그램의 정당성 증명 등과는 다소 거리가 있는 해석이었다.[39][40][41] 하렐 자신도 구조적 정리가 본래의 의미 이상으로 인용되어 일종의 '민간 전승 정리'(folk theorem)처럼 되었다고 지적했다.[36]
2. 2. 논쟁
구조적 프로그래밍이 처음 제안되었을 때 모든 프로그래머가 이를 즉시 받아들인 것은 아니었다. 구조적 프로그래밍의 초기 실천가 중 한 명인 P. J. 플로거는 당시 상황을 다음과 같이 회고했다. "우리는 이 흥미로운 소식을 어셈블리 프로그래머들에게 알려주면서 마음을 돌려보려 하였지만, 이 덜된 어셈블리 프로그래머들은 비비꼬인 로직의 비트들을 만들어내면서 계속해서 '이런 건 구조화가 안 될걸?'이라고 말하고 있다."[4] 뵘과 주세페 야코피니의 수학적 증명이나 구조적 코드를 성공적으로 작성한 사례를 보여주어도, 기존 방식에 익숙한 프로그래머들을 설득하는 것은 쉽지 않았다.본격적인 논쟁은 1968년, 컴퓨터 과학자 에츠허르 데이크스트라가 ACM의 학술지 CACM에 "goto문은 해롭다"[25]라는 제목의 글을 기고하면서 시작되었다. 이 글에서 데이크스트라는 goto문이 프로그램의 흐름을 이해하기 어렵게 만들고 오류를 유발하기 쉽다고 주장하며, 고급언어에서 GOTO 명령을 제거하면 코드의 질을 높일 수 있다고 역설했다. 그는 GOTO문 대신 `if-then-else`와 같은 선택 구조와 `while`과 같은 반복 구조를 사용할 것을 제안했다. 이 글은 프로그래밍 커뮤니티에 큰 파장을 일으키며 이른바 'GOTO문 논쟁'을 촉발했다.[26][27] 흥미롭게도, 이 자극적인 제목은 데이크스트라가 원래 붙인 "A case against the goto statement"(goto문에 대한 반론)를 당시 편집자였던 니클라우스 비르트가 수정한 것이었다.[46]
데이크스트라는 단순히 GOTO문 사용 자제를 넘어, 프로그램의 구조 자체가 중요하다고 강조했다. 그는 1969년 발표한 "Structured Programming"(구조적 프로그래밍)[19] 논문에서, 프로그램 개발 시 하향식 설계, 단계적 추상화, 모듈화를 통해 프로그램을 잘 구조화하면 프로그램의 크기가 커지더라도 정확성을 증명하기 용이해진다고 주장했다. 이는 당시 심각해지던 소프트웨어 위기 문제, 즉 프로그램의 복잡도 증가로 개발 및 유지보수가 어려워지는 문제에 대한 해결책으로 제시된 것이었다. 그는 "우리는 정확한 프로그램을 작성하는 프로그래머의 직분을 수행해야 할 뿐만 아니라, 그것의 정확성을 납득가능한 방법으로 증명하는 역할도 수행해야 한다"고 말하며, 검증 가능한 프로그램 구조의 중요성을 역설했다.
모든 프로그래머가 데이크스트라의 주장에 동의한 것은 아니었다. 저명한 컴퓨터 과학자 도널드 커누스는 프로그램의 증명 가능성 원칙에는 동의했지만, GOTO문을 완전히 없애는 것에는 반대했다. 그는 1974년 발표한 논문 "GOTO문이 포함된 구조적 프로그래밍"[6][22]에서, 특정 상황에서는 GOTO문을 사용하는 것이 오히려 더 명확하고 효율적인 코드를 만들 수 있으며, 증명 가능성을 반드시 희생시키는 것도 아니라고 주장했다. 그는 GOTO문을 사용하더라도 프로그램의 순서도를 그렸을 때 특정 규칙(예: 앞으로 가는 분기는 왼쪽에, 뒤로 가는 분기는 오른쪽에 배치하고 서로 교차하지 않게 함)을 따르면 구조적인 명료성을 유지할 수 있다는 완화된 제약을 제안했다.
이러한 학계의 논쟁과 별개로, 산업계에서는 구조적 프로그래밍이 점차 받아들여지기 시작했다. 1970년대 IBM의 연구원 할란 밀스는 구조적 프로그래밍 개념을 뉴욕 타임스의 기사 아카이브 시스템 개발 프로젝트에 적용하여 큰 성공을 거두었다. 이 성공 사례는 다른 기업들이 구조적 프로그래밍을 도입하는 데 중요한 계기가 되었다. 다만 데이크스트라는 밀스가 적용한 방식이 자신이 제안한 추상화 중심의 구조적 프로그래밍과는 다소 차이가 있다고 비판하기도 했다.
GOTO문 논쟁은 1980년대까지도 이어졌다. 1987년 프랭크 루빈은 "'GOTO는 해롭다'는 고려, 해롭다고 고려됨"('Go to statement considered harmful' considered harmful)이라는 도발적인 제목의 글을 발표하며 다시 논쟁에 불을 지폈고[7], 데이크스트라를 포함한 많은 이들이 이에 반박하는 글을 기고했다.
결과적으로 GOTO문 논쟁은 단순히 특정 명령어의 사용 여부를 넘어, 프로그램의 가독성, 유지보수성, 정확성 등 소프트웨어 품질 전반에 대한 프로그래밍 커뮤니티의 인식을 높이는 중요한 계기가 되었다. 비록 절차적 프로그래밍 언어인 ALGOL, 파스칼, PL/I, Ada 등에서 구조적 프로그래밍이 더 용이하게 구현되었지만, 이후 등장한 많은 언어들은 구조적 프로그래밍을 장려하는 기능을 포함하고, 때로는 의도적으로 GOTO와 같은 기능을 제외하여 비구조적 프로그래밍을 어렵게 만드는 방향으로 발전했다.[2][3]
2. 3. 발전과 결과
1970년 무렵부터 구조적 프로그래밍은 인기 있는 프로그래밍 기법으로 자리 잡았다. 이에 따라 새로 등장하는 대부분의 절차적 프로그래밍 언어들은 구조적 프로그래밍을 장려하는 기능을 포함하게 되었으며, 때로는 GOTO와 같은 비구조적 프로그래밍 기능을 의도적으로 제외하여 구조적 작성을 유도하기도 했다. 물론, 기존의 비구조적 프로그래밍 방식의 특징을 남겨둔 언어들도 있었다. 구조적 프로그래밍에 처음 사용된 언어로는 ALGOL, 파스칼, PL/I, 에이다, RPL 등이 있으며[2][3], 특히 파스칼과 에이다는 잘 알려진 구조적 프로그래밍 언어이다.''구조적 프로그래밍''(때로는 모듈식 프로그래밍이라고도 함[2])은 작성 중인 프로그램에 논리적인 구조를 적용하여 프로그램을 더 효율적으로 만들고, 이해하고 수정하기 쉽게 만드는 것을 목표로 한다. 원칙적으로 모든 프로그래밍 언어로 구조적 프로그래밍을 구현할 수 있지만, 절차적 프로그래밍 언어를 사용하는 것이 더 자연스럽다.[2][3]
20세기 말에 이르러서는 대부분의 컴퓨터 과학자들이 구조적 프로그래밍의 개념을 배우고 적용하는 것이 유용하다는 데 동의하게 되었다. 그 결과, 원래 프로그래밍 구조가 부족했던 FORTRAN, COBOL, BASIC과 같은 초기의 고급 프로그래밍 언어들도 시대의 흐름에 맞춰 구조적 프로그래밍을 지원하는 기능을 추가했다. 이로 인해 프로그래밍 교육 현장에서도 GOTO문의 무분별한 사용을 용인하는 경우는 찾아보기 힘들어졌다.
하지만 프로그래머가 경험을 쌓으면서 엄격한 의미의 구조적 프로그래밍 원칙을 벗어나는 것이 더 효율적인 경우도 있다는 것을 알게 되었다. 이에 따라 일부 언어들은 직접적인 분기문을 제한하는 대신 예외처리 메커니즘을 제공하여 특정 상황에 대처할 수 있도록 했다. 그럼에도 불구하고 Java와 같은 일부 언어를 제외한 주요 산업용 언어들은 여전히 프로시저 내에서의 직접적인 분기를 위해 GOTO문을 유지하고 있다. 데이크스트라는 구조적 프로그래밍을 표준 교육과정에 포함시키는 데 큰 영향을 미쳤지만, 그가 주장했던 엄격한 규칙이 모든 현장에서 그대로 지켜지지는 않고 있다.
3. 주요 원리
구조적 프로그래밍은 저수준 관점에서 보면, 간단하고 계층적인 프로그램 제어 구조들로 구성된다. 이러한 제어 구조는 기본적인 구문들(할당문, 프로시저 호출 등)을 결합하여 더 복잡한 기능을 수행하도록 만드는 방법이다.
에츠허르 데이크스트라가 제시한 핵심 제어 구조는 순차, 선택, 반복 세 가지이며, 이는 프로그램의 논리적 흐름을 명확하게 구성하는 기본 원리가 된다. (자세한 내용은 제어 구조 섹션 참조)
또한, 구조적 프로그래밍은 큰 프로그램을 이해하기 쉬운 작은 단위의 서브루틴으로 나누어 작성하는 것을 중요하게 여긴다. 이를 통해 코드의 모듈성을 높이고, 전역 변수 대신 지역 변수나 매개변수를 활용하여 프로그램의 복잡도를 낮추고 이해도를 높인다. (자세한 내용은 서브루틴 (함수) 섹션 참조)
구조적 프로그래밍은 종종 하향식 설계 방법론과 관련이 있다. 하향식 설계는 큰 문제를 작은 단위로 나누어 구현하고 검증한 뒤, 이를 합쳐 전체 프로그램을 완성하는 방식이다.
3. 1. 제어 구조
저수준 관점에서 구조적 프로그램은 간단하고 계층적인 프로그램 제어 구조로 구성된다. 이 제어 구조들은 하나의 구문으로 간주되며, 더 간단한 구문들을 결합시키는 방법이다. 더 간단한 구문들은 또 다른 제어 구조일 수도 있고, 할당문이나 프로시저 호출과 같은 기본 구문일 수도 있다. 에츠허르 데이크스트라가 확인한 세 가지 기본 제어 구조는 순차, 선택, 반복이다.[19] 구조적 프로그램 정리에 따르면, 모든 프로그램은 원칙적으로 이 세 가지 제어 구조만으로 구성될 수 있다.
세 가지 기본 제어 구조는 다음과 같다.
- '''순차'''(sequence): 구문이나 서브루틴들이 작성된 순서대로 실행되는 가장 기본적인 구조이다.
- '''선택'''(selection): 프로그램의 상태, 즉 특정 조건의 참/거짓 여부에 따라 여러 구문 그룹 중 하나를 선택하여 실행하는 구조이다. 주로
if..then..else..endif
,switch
,case
와 같은 키워드로 표현된다. 조건문은 일반적으로 최소한 하나의 참 조건을 가지며, 각 조건 분기는 최대 하나의 종료 지점을 갖는다. - '''반복'''(repetition): 특정 조건이 만족되는 동안(예: 프로그램 상태가 특정 조건에 도달할 때까지) 구문 그룹을 반복하여 실행하거나, 어떤 컬렉션의 각 원소에 대해 특정 구문 그룹을 반복 실행하는 구조이다. 보통
while
,repeat
,for
,do..until
같은 키워드로 표현된다. 반복 구조는 하나의 진입점을 가지는 것이 권장되며, 초기 구조적 프로그래밍 이론에서는 종료점도 하나여야 한다고 보았다. 일부 프로그래밍 언어에서는 이러한 제약을 강제하기도 한다.
이러한 제어 구조는 goto문을 사용한 복잡하고 이해하기 어려운 프로그램 흐름 제어를 대체하기 위해 고안되었다. goto문은 프로그램의 특정 위치(레이블)로 실행 흐름을 직접 이동시키는 방식인데, 이는 프로그램의 논리적 흐름을 추적하기 어렵게 만들 수 있다. 제어 구조는 goto문의 기능을 두 가지 기본 패턴, 즉 (1) 조건에 따라 실행할 코드 그룹을 선택하는 '선택'과 (2) 특정 조건이 만족될 때까지 코드 그룹을 반복하는 '반복'으로 정형화하여 대체했다.
여기서 코드 그룹은 명령 코드(instruction code)의 묶음을 의미하며, 구조화 정리에서는 이를 부분 프로그램(subprogram)으로 정의한다. 부분 프로그램은 스테이트먼트(statement, 명령 코드 한 줄), 코드 블록(code block, 한 줄 이상의 스테이트먼트 묶음), 서브루틴(subroutine, 하나 이상의 스테이트먼트 또는 코드 블록 포함) 등을 포괄하는 용어이다. 부분 프로그램들은 순차적으로 나열되거나 다른 부분 프로그램 안에 포함되는 중첩 형태로 배치될 수 있으며, 이들의 실행 순서를 결정하는 것이 바로 제어 구조의 역할이다.
제어 구조의 개념 자체는 1960년에 공개된 ALGOL60에서 이미 나타났지만, 당시 널리 사용되던 FORTRAN이나 COBOL 같은 언어에는 1977년 이후에야 정식으로 도입되어 많은 개발 현장에서는 익숙하지 않았다. 1966년 코라도 뵘과 주세페 야코피니는 순차, 선택, 반복이라는 세 가지 구조만으로 어떠한 플로우차트(즉, 프로그램 로직)도 표현할 수 있음을 수학적으로 증명했다[36]. 이는 주로 이론적인 연구였으나, 에츠허르 데이크스트라는 1968년 유명한 편지 "Go To Statement Considered Harmful"을 통해 goto문의 무분별한 사용이 프로그램의 복잡성을 증가시키고 검증을 어렵게 만든다고 주장하며 제어 구조 사용의 중요성을 강조했다. 이는 소위 'goto 논쟁'을 촉발하며 구조적 프로그래밍과 제어 구조에 대한 관심을 크게 높이는 계기가 되었다.
1970년대, goto문이 여전히 많이 사용되던 개발 현장에서 제어 구조의 보급을 중시했던 IBM의 할란 밀스는 데이크스트라가 사용했던 "구조적 프로그래밍"이라는 용어를 자사의 기술 세미나 마케팅에 활용했다. 그는 앞서 언급된 뵘과 야코피니의 수학적 증명에 "구조화 정리"라는 이름을 붙여[36], IBM이 권장하는 제어 구조 사용의 이론적 근거로 삼았다. 이러한 과정을 통해 구조적 프로그래밍은 구조화 정리를 바탕으로 제어 구조(순차, 선택, 반복)를 사용하는 프로그래밍 기법으로 널리 인식되게 되었다.
데이크스트라의 초기 가드 명령어 언어 같은 일부 언어에서는
if..fi
와 같이 구조 전체를 명확히 감싸는 구문을 사용하여 구조의 단일성을 강조하기도 한다. 반면 C와 같은 다른 언어들은 이러한 방식을 사용하지 않는데, 이것이 반드시 코드를 잘못 이해하거나 수정할 위험을 크게 높이는 것은 아니다.3. 2. 서브루틴 (함수)
서브루틴(절차, 함수, 메서드 또는 서브 프로그램이라고도 함)은 여러 개의 명령어를 묶어서 하나의 이름으로 호출할 수 있게 해주는 기능이다. 즉, 단일 명령문으로 일련의 명령들을 실행할 수 있도록 한다.코드를 작성할 때는 큰 프로그램을 이해하기 쉬운 작은 단위, 즉 서브루틴으로 나누는 것이 중요하다. 이렇게 프로그램을 구조화하면 다음과 같은 이점이 있다.
- 이해 용이성: 프로그램 전체를 한 번에 파악하지 않고도, 분리된 작은 코드 조각(서브루틴)을 더 쉽게 이해하고 분석할 수 있다.
- 변수 관리: 일반적으로 프로그램 전체에서 사용되는 전역 변수는 가능한 적게 사용하고, 각 서브루틴은 자신만의 지역 변수를 사용하거나 값 또는 참조를 통해 인자를 전달받아 처리하는 것이 권장된다. 이는 서브루틴 간의 간섭을 줄여 코드의 안정성을 높인다.
이러한 기법들은 복잡한 프로그램을 더 관리하기 쉽고 명확하게 만드는 데 도움을 준다.
3. 3. 블록 구조
블록은 여러 개의 구문(명령문)을 하나의 구문처럼 다룰 수 있게 해주는 개념이다. 블록 구조를 지원하는 프로그래밍 언어는 코드 묶음을 형식적인 구문을 사용해 명확하게 구분하는데, 예를 들어 다음과 같은 방식들이 있다.4. 설계 기법
구조적 프로그래밍을 구현하는 데에는 여러 설계 기법이 활용된다. 대표적으로 하향식 설계, 단계적 상세화, 모듈화 등이 있으며, 이들은 프로그램을 보다 체계적으로 개발하고 관리하는 데 도움을 준다. 특히 구조적 프로그래밍은 큰 문제를 작은 단위로 나누어 해결하는 하향식 설계 방식과 관련이 깊은 경우가 많다.
4. 1. 하향식 설계
구조적 프로그래밍은 하향식 설계와 관련이 있는 경우가 많다. 하향식 설계를 할 때, 설계자는 큰 규모의 프로그램을 더 작은 단위의 공정으로 나누어 구현하고, 각각 검사한 다음에 전체 프로그램으로 합치는 방식을 사용한다. 이는 단계적 상세화와 관련이 있다.앞서 설명된 제어 구문들이 코딩 관점에서의 하위 공정 기술이라면, 프로그램 디자인 관점에서의 상위 공정 기술로 '구조적 설계'(structured design)가 있으며, 이 역시 구조적 프로그래밍이라고 불리기도 한다. 구조적 설계에서는 서브루틴(subroutine)을 묶은 서브루틴 복합체와 데이터 요소를 묶은 자료 구조(data structure)가 중요한 역할을 한다. 단계적 상세화 방법에 따라 서브루틴 복합체를 계층적으로 조합하고, 거기에 필요한 자료 구조를 연계하여 프로그램 전체를 구축하는 기술이 구조적 설계이다. 서브루틴 복합체는 프로그램 모듈(program module)로도 볼 수 있으며, 모듈의 응집도와 결합도 개념 또한 여기서 비롯된다.
1974년경부터는 IBM 주도로 '구조화'(structured)라는 이름이 붙은 여러 기술들이 발표되기 시작했다. 1975년 발표된 "잭슨의 구조적 프로그래밍"(Jackson structured programming, JSP)과 "구조적 설계"(structured design, SD), 1978년 발표된 "구조적 분석"(structured analysis, SA), 1981년 발표된 "구조적 분석 설계 기법"(structured analysis and design technique, SADT), 1980년대 발표된 "구조화 체계 분석 설계 기법"(structured systems analysis and design method, SSADM), 1989년 발표된 "모던 구조적 분석"(modern structured analysis) 등이 널리 보급되었다. 이 분야의 유명한 전문가로는 글렌포드 마이어스, 래리 컨스탄틴, 마이클 잭슨, 에드워드 요든, 톰 드마르코 등이 있다. 이 기술들은 "구조적 개발"로 총칭되었으며, 1980년대까지 소프트웨어 개발의 주류를 이루었다.
이러한 구조적 설계와 에츠허르 데이크스트라의 구조적 프로그래밍 사이에는 차이점이 있다. 구조적 설계는 서브루틴 복합체와 자료 구조의 연계를 중심으로 한 기술인 반면, 데이크스트라가 제안한 방식은 전용 서브루틴을 통해 다루어지는 추상 자료 구조를 중심으로 한 기술이다. 데이크스트라 방식에서는 단계적으로 추상화된 각 모듈의 계층적인 연결과, 추상 자료 구조와 추상 구문을 연계시키는 공동 상세화와 같은 사고방식이 제시되었다. 그러나 데이크스트라가 제창한 추상(abstraction) 지향의 구조화는 그 전위성 때문에 1970년대 동안 널리 이해받지 못했고, 발안자 본래의 구조적 프로그래밍은 상위 공정 관점에서도 널리 퍼지지 못했다.
4. 2. 단계적 상세화
단계적 상세화는 구조적 프로그래밍에서 프로그램을 설계하는 중요한 방법 중 하나로, 종종 하향식 설계와 관련된다. 하향식 설계는 큰 문제를 해결하기 위해 전체 프로그램을 더 작은 단위의 작업(공정)으로 나누고, 각 단위를 개별적으로 구현하고 검증한 뒤 하나로 합치는 방식이다.구조적 설계는 프로그램 디자인 관점에서 상위 수준의 접근법으로, 단계적 상세화 기법을 활용한다. 이 방식에서는 프로그램을 기능별로 나누어 서브루틴(subroutine)들의 묶음(서브루틴 복합체 또는 프로그램 모듈)을 만들고, 필요한 자료 구조(data structure)와 연계하여 계층적으로 조합함으로써 전체 프로그램을 구축한다. 이 과정에서 모듈의 응집도와 결합도 같은 개념이 중요해진다.
데이크스트라가 제시한 구조적 프로그래밍 방식은 이러한 구조적 설계와는 다소 차이가 있다. 데이크스트라의 접근법은 서브루틴과 자료 구조의 연계보다는, 특정 서브루틴에 속한 추상 자료형을 중심으로 한다. 여기서는 각 모듈을 단계적으로 추상화(abstraction)하여 계층적으로 연결하고, 추상 자료 구조와 추상적인 처리 구문을 함께 구체화해 나가는 '공동 상세화(joint refinement)'와 같은 아이디어가 강조되었다. 하지만 이러한 추상화 중심의 접근은 당시에는 다소 전위적이어서 1970년대에는 널리 받아들여지지 못했다.
4. 3. 모듈화
코드 작성자는 큰 프로그램을 이해하기 쉬운 크기의 작은 하부 프로그램(함수, 프로시저, 메서드, 블록 등)으로 나누어 관리해야 한다. 이렇게 프로그램을 독립적인 모듈로 분할하면 개발 생산성, 유지보수성, 코드 재사용성을 높이는 데 도움이 된다. 각 모듈은 특정 기능을 수행하며, 전체 프로그램을 한 번에 이해하지 않고도 분리된 작은 코드 조각을 쉽게 파악하고 수정할 수 있게 해준다.일반적으로 모듈화된 프로그램에서는 전역 변수의 사용을 최소화하고, 대신 각 하부 프로그램이 지역 변수를 사용하거나 값 또는 참조에 의한 인자를 전달받아 처리하는 방식을 권장한다. 이는 모듈 간의 불필요한 의존성을 줄여 코드의 독립성을 높이는 데 기여한다.
모듈화는 종종 하향식 설계(Top-down design) 방식과 함께 사용된다. 하향식 설계는 큰 문제를 더 작은 단위의 문제로 나누어 해결하고, 이를 다시 조합하여 전체 시스템을 완성하는 접근법이다. 단계적 상세화 기법 역시 이러한 과정과 밀접한 관련이 있다.
구조적 설계(structured design) 관점에서 모듈은 관련된 서브루틴(subroutine)들의 묶음이나 데이터 요소를 묶은 자료 구조(data structure)로 구성될 수 있다. 좋은 모듈 설계를 위해서는 모듈 내부 요소들이 얼마나 긴밀하게 연관되어 있는지를 나타내는 응집도(cohesion)를 높이고, 다른 모듈과의 의존성을 나타내는 결합도(coupling)를 낮추는 것이 중요하다. 높은 응집도와 낮은 결합도는 이해하기 쉽고 수정이 용이하며 재사용성이 높은 모듈을 만드는 핵심 원칙이다.
5. 예외와 한계
구조적 프로그래밍은 제어 흐름을 명확하게 하고 프로그램의 이해도를 높이는 것을 목표로 한다. 특히 순차, 선택, 반복이라는 세 가지 기본 제어 구조만을 사용하여 프로그램을 구성하고, `goto` 문의 사용을 제한하는 것이 핵심 원칙이다. 이상적으로는 모든 코드 블록이 단 하나의 진입점과 단 하나의 종료점을 갖도록 설계된다.
하지만 실제 프로그래밍 환경에서는 이러한 이상적인 구조만으로는 해결하기 어려운 문제들이 발생한다. 예상치 못한 오류 상황에 대처해야 하거나, 프로그램의 상태가 복잡하게 변화하는 경우, 엄격한 구조적 원칙을 고수하기 어려울 수 있다. 이러한 상황들은 구조적 프로그래밍의 예외적인 경우 또는 한계로 볼 수 있다.
이 섹션에서는 구조적 프로그래밍의 주요 예외 및 한계 상황으로 예외 처리 메커니즘의 필요성과 그에 따른 논쟁, 그리고 복잡한 상태 변화를 다루는 상태 기계 구현의 어려움 등을 살펴본다. 이러한 문제들을 해결하기 위해 현대 프로그래밍 언어들이 어떤 방식으로 구조적 프로그래밍 원칙을 확장하거나 보완하는지에 대해서도 알아본다.
5. 1. 예외 처리
구조적 프로그래밍에서 제어 구조는 원래 단일 진입점과 단일 종료점을 갖는 것을 이상적으로 여겼다. 하지만 실제 프로그래밍에서는 함수나 루프 중간에 예상치 못한 오류가 발생하거나 특정 조건에 따라 처리를 중단해야 하는 경우가 많다. 이러한 상황을 처리하기 위한 메커니즘이 바로 '''예외 처리'''이다.예외 처리는 에츠허르 데이크스트라가 초기에 제시한 엄격한 단일 종료점 원칙에는 어긋난다. 예를 들어 파일을 처리하는 도중 오류가 발생하면, 정상적인 종료 지점까지 가지 않고 중간에 함수 실행을 멈추고 오류를 알리는 것이 더 효율적일 수 있다.
```text
open file;
while (reading not finished) {
read some data;
if (error) {
stop the subprogram and inform rest of the program about the error; // 예외 발생 또는 조기 리턴 지점
}
}
process read data;
finish the subprogram; // 정상적인 단일 종료 지점
```
위 예시처럼 오류 발생 시 5번째 줄에서 바로 멈추는 것은 단일 종료점 원칙에 위배된다. 하지만 이 원칙을 억지로 지키려고 모든 오류 상황을 정상 흐름 안에서 처리하도록 코드를 수정하면, 코드가 훨씬 복잡해지고 이해하기 어려워질 수 있다.[9] 따라서 현대 프로그래밍 언어들은 대부분 `return`, `break`, `continue`와 같은 조기 종료(early exit) 구문과 더불어 예외 처리 메커니즘을 지원하여 프로그래밍의 유연성을 높인다.
그러나 조기 종료나 예외 처리는 자원 누수 문제를 일으킬 수 있다. 예를 들어 함수 중간에 `return`하거나 예외가 발생하여 함수를 빠져나가면, 함수가 끝나기 전에 실행되어야 할 뒷정리 코드(예: 동적 할당된 메모리 해제, 열린 파일 닫기)가 실행되지 않을 수 있다. 이는 메모리 누수나 자원 누수로 이어질 수 있다.
이러한 문제를 해결하기 위해 최신 언어들은 다양한 자원 관리 기법을 제공한다.[8] 대표적인 것이 `try...finally` 구문이다. `finally` 블록 안의 코드는 `try` 블록에서 예외가 발생하든, 중간에 `return`을 하든 상관없이 항상 실행이 보장되므로 자원 해제 코드를 넣기에 적합하다. C++에서는 RAII (Resource Acquisition Is Initialization) 기법을 사용하여 객체가 소멸될 때(함수 종료 시 스택에서 해제될 때) 자동으로 자원을 해제하도록 구현하기도 한다.
예외 처리에 대한 관점은 다양하다. 켄트 벡, 마틴 파울러 등은 단일 종료점 규칙이 항상 유용한 것은 아니며, 오히려 여러 종료점을 사용하는 것이 코드를 더 명확하게 만들 수 있다고 주장한다.[9] 허브 서터와 안드레이 알렉산드레스쿠 역시 단일 종료점은 더 이상 필수적인 요구 사항이 아니라고 본다.[10] 데이비드 와트는 오류 발생 시 상태 플래그를 검사하는 방식보다 예외 처리가 더 효과적이라고 분석했다. 상태 플래그는 프로그래머가 검사를 잊거나 무시하기 쉽지만, 예외는 명시적으로 처리하지 않으면 프로그램이 종료되므로 오류를 간과하기 어렵다는 것이다.
반면, 베르트랑 메이어는 `break`나 `continue` 같은 구문이 구조적 프로그래밍의 원칙을 해치는 "양의 탈을 쓴 `goto`"라며 사용을 강력히 반대했다.[11] 아리안 501호 폭발 사고의 오류 분석을 바탕으로 짐 보낭은 함수 간에 예외를 던지는 것 자체가 단일 종료 원칙 위반이라며 모든 프로시저 간 예외를 금지해야 한다고 주장하기도 했다. 그의 주장에 따르면, 모든 예외를 함수 내부에서 잡아서 처리하고 성공/실패 여부만 반환해야 한다.
bool MyCheck1() throw() { // 이 함수는 예외를 던지지 않음을 명시 (C++17 이전 문법)
bool success = false;
try {
// 예외를 던질 수 있는 작업을 수행합니다.
if (!MyCheck2()) {
throw SomeInternalException(); // 내부 예외 발생
}
// 위와 유사한 다른 코드입니다.
success = true;
} catch (...) { // 모든 종류의 예외를 잡음
// 모든 예외를 잡아서 기록합니다.
// 함수 외부로는 예외를 던지지 않음
}
return success; // 성공 또는 실패 여부만 반환
}
피터 리치는 예외 처리가 없던 시절에 만들어진 단일 종료 원칙을 현대에 그대로 적용하는 것은 무리가 있으며, 단일 반환점 외에 여러 예외 발생 지점(throw)을 허용하는 것이 현실적이라고 주장한다. 그는 예외를 감싸서 억지로 단일 종료를 만드는 것은 코드를 더 복잡하게 만들 뿐이며, 이는 카고 컬트적 사고방식이라고 비판했다.[12]
또한 예외 처리는 프로그램의 제어 흐름을 예측하기 어렵게 만든다는 비판도 있다. 예외는 코드의 명시적인 흐름과 다른 경로로 실행될 수 있기 때문에 "숨겨진 제어 흐름 경로"를 만들 수 있다.[13][15] 예를 들어 `for` 루프의 초기화 부분(`init()`)에서 예외가 발생하면 루프 본문이나 증감식(`increm()`)은 전혀 실행되지 않고 루프를 완전히 빠져나가게 된다.[14] 웨슬리 바이머와 조지 네쿨라는 예외가 프로그래머가 이해하기 어려운 제어 흐름을 만든다고 지적했다.[15]
병렬 컴퓨팅 환경인 OpenMP 등에서는 병렬 처리 블록 내에서 외부로 빠져나가는 조기 종료(예외 포함)를 엄격히 금지하기도 한다. 이는 병렬 작업의 동기화와 예측 가능성을 유지하기 위한 제약이다.[16]
5. 2. 상태 기계
파서나 통신 프로토콜과 같은 일부 프로그램들은 여러 상태를 가지며, 이러한 상태 변화는 기본적인 구조적 프로그래밍(순차, 선택, 반복)만으로는 깔끔하게 표현하기 어려운 경우가 있다.이러한 상태 기반 시스템을 구조적으로 만들기 위한 한 가지 방법은 각 상태 변화를 별도의 서브루틴으로 만들고, 변수를 사용하여 현재 활성 상태를 표시하는 것이다(트램폴린 기법 참조).
하지만 일부 프로그래머들은 상태 변화를 표현하기 위해 새로운 상태로 직접 분기하는 방식(예: goto 사용)을 선호하기도 한다. 이러한 방식의 상태 전환은 리눅스 커널 등에서 찾아볼 수 있다. 그러나 이런 직접적인 분기는 프로그램의 흐름을 이해하기 어렵게 만들 수 있다는 비판이 있다.
코루틴은 상태 기계를 다루는 또 다른 구조적인 접근 방식을 제공한다. 코루틴은 실행을 잠시 멈추고 다른 곳에 제어를 넘겨주었다가, 나중에 다시 호출되면 멈췄던 지점부터 실행을 재개할 수 있는 특징(재진입)을 가진다. 이는 스트림 처리(특히 입출력), 상태 기계 구현, 동시성 처리 등에 유용하게 활용된다. 실행 흐름 측면에서 보면, 코루틴은 서브루틴이 완전히 종료되고 반환하는 것보다 구조적 프로그래밍 원칙에 더 가깝다고 할 수 있다. 왜냐하면 실행이 완전히 끝나지 않고 중단된 지점에서 이어지기 때문이다. 다만, 코루틴은 여러 개의 실행 흐름이 동시에 활성 상태를 유지하므로, 기존의 단일 호출 스택 방식과는 다른 종류의 복잡성을 가질 수 있다.
매우 드물게 서브루틴이 임의의 위치로 진입하는 것을 허용하는 경우도 있는데, 이는 프로그램의 상태(예: 변수 값)가 예측 불가능하거나 모호해질 수 있어 goto와 유사한 문제를 야기할 수 있다.
6. 현대적 가치와 영향
구조적 프로그래밍에 대한 논의는 많은 새로운 프로그래밍 언어의 탄생과 기존 언어의 개선에 기여했으며, 객체 지향 프로그래밍과 같은 이후 등장한 프로그래밍 패러다임에도 영향을 미쳤다.
또한, 구조적 프로그래밍은 프로그래머들의 코딩 습관을 변화시키는 계기가 되었다. 데이크스트라가 지적했듯이, 복잡한 프로그램의 동적인 과정을 시각화하는 것은 어려운 일이므로, 프로그래머들은 GOTO문 사용을 줄이는 것뿐만 아니라 지나치게 복잡한 구조를 피하려는 경향을 갖게 되었다. 이는 코드를 더 명확하고 이해하기 쉽게 만들어 다른 개발자와의 협업에도 긍정적인 영향을 주었다.
한편, 데이크스트라가 작성한 "GOTO문의 해로움"이라는 글은 이후 컴퓨터 과학 분야에서 특정 기술이나 관행의 문제점을 지적할 때 "...의 해로움"이라는 제목 형식을 사용하는 유행을 만들기도 했다.
데이크스트라는 자신이 제안한 '구조적 프로그래밍'이라는 용어가 시간이 지나면서 본래 의도했던 프로그램 정확성 증명, 하향식 설계, 추상화, 모듈화, 정보 은닉, 계층적 프로그램 구조 등[45][39][33] 포괄적인 개발 이론과는 다르게 해석되는 경향이 있다고 2001년에 지적하기도 했다[44].
6. 1. 프로그래밍 언어 발전
1970년 무렵부터 구조적 프로그래밍은 인기 있는 프로그래밍 기법으로 자리 잡았다. 이 시기 이후 등장한 대부분의 새로운 절차적 프로그래밍 언어들은 구조적 프로그래밍을 장려하기 위한 기능들을 추가했다. 물론 일부 언어는 GOTO문처럼 비구조적인 프로그래밍을 가능하게 하는 기존의 기능들을 남겨두기도 했다. 대표적인 초기 구조적 프로그래밍 언어로는 파스칼(Pascal)과 에이다(Ada)가 있다.[2][3] 초기 구조적 프로그래밍에 사용된 다른 언어들로는 ALGOL, PL/I, RPL 등이 있다.20세기 후반에 이르러 대부분의 컴퓨터 과학자들은 구조적 프로그래밍의 개념을 배우고 적용하는 것이 유용하다는 데 동의하게 되었다. 초기에 프로그래밍 구조가 약했던 포트란, 코볼, BASIC과 같은 고급 프로그래밍 언어들도 구조적 프로그래밍을 지원하는 기능을 갖추게 되었다. 이로써 프로그래밍 교육 현장에서도 GOTO문을 무분별하게 사용하는 것을 옹호하는 교육자를 찾기 어려워졌다.
물론, 숙련된 프로그래머들은 때때로 엄격한 구조적 프로그래밍 원칙에서 벗어나는 것이 유용할 수 있음을 인지하고 있다. 많은 현대 프로그래밍 언어들은 직접적인 분기(GOTO) 사용을 제한하는 대신, 예외처리 메커니즘을 통해 특정 상황에 대처할 수 있도록 지원한다. 하지만 자바와 같은 일부 언어를 제외하고, 주요 산업용 언어들은 여전히 프로시저 내에서의 직접적인 분기를 위해 GOTO문을 유지하고 있다. 데이크스트라는 구조적 프로그래밍을 표준 교육과정에 포함시키는 데는 성공했지만, GOTO문을 완전히 배제하는 엄격한 조건을 관철시키지는 못했다.
구조적 프로그래밍에 대한 논의는 많은 새로운 언어의 탄생에 영향을 주었으며, 기존 언어에 구조적인 측면이 추가되는 등 프로그래밍 언어의 발전에 크게 기여했다. 또한, 객체 지향 프로그래밍과 같은 이후의 프로그래밍 패러다임에도 영향을 미쳤다. 예를 들어, 1972년 데이크스트라, 토니 호어, 올레 요한 달이 공동 저술한 "구조적 프로그래밍"(Structured Programming)[48] 책에서 달이 저술한 "계층적 프로그램 구조" 부분은 객체 지향 프로그래밍의 선구적인 언어인 Simula67에 기반하고 있으며, 이는 클래스 계층 구조와 상속 개념을 다루었다. C++를 개발한 비야네 스트롭스트루프 역시 객체 지향 프로그래밍을 설명하면서 Simula67의 영향을 언급했다.[49]
구조적 프로그래밍은 프로그래머들의 코딩 습관에도 변화를 가져왔다. 프로그램의 정확성 증명 문제를 떠나, 데이크스트라가 지적했듯이 시간에 따라 변하는 동적인 과정을 시각화하는 것은 인간에게 매우 어려운 일이다. 이 때문에 프로그래머들은 GOTO문 사용을 줄이는 것뿐만 아니라, 구조화된 제어 흐름문을 사용하더라도 코드가 너무 복잡하게 중첩되거나, 스코프가 너무 길어지거나, 서브루틴의 길이가 지나치게 길어지는 것을 피하려는 경향을 갖게 되었다. 이러한 습관은 다른 사람이 작성한 코드를 더 쉽게 이해하는 데 도움을 준다.
제어 구조(control structures)는 구조적 프로그래밍의 핵심 요소로, GOTO문 대신 if문(선택)이나 while문(반복) 등을 사용하여 프로그램의 흐름을 제어한다. 이는 특정 조건에 따라 코드 블록을 실행하거나 반복하는 방식으로 GOTO문의 기능을 대체한다. 이러한 제어 구조는 크게 세 가지로 나뉜다.
# '''순차'''(sequence): 코드를 작성된 순서대로 실행한다.
# '''선택'''(selection): 조건식의 결과에 따라 실행할 코드 블록을 선택한다.
# '''반복'''(repetition): 조건식이 참인 동안 특정 코드 블록을 반복 실행한다.
제어 구조의 개념은 1960년 ALGOL60에서 이미 도입되었지만, 당시 널리 사용되던 FORTRAN이나 COBOL에는 1977년 이후에야 정식으로 도입되어 개발 현장에 보급되는 데 시간이 걸렸다. 1966년 코라도 뵘 등이 "순차·선택·반복" 구조만으로 모든 계산 가능한 함수를 표현할 수 있다는 것을 수학적으로 증명했지만(이후 구조화 정리로 알려짐), 이는 당시에는 주로 이론적인 연구로 간주되었다. 데이크스트라는 이를 바탕으로 1968년 "Go To Statement Considered Harmful"이라는 글을 발표하여 GOTO문 사용에 대한 논쟁을 촉발시켰고, 제어 구조에 대한 관심을 크게 높였다. 1970년대 IBM의 할란 밀스는 데이크스트라의 논문 제목에서 인지도를 얻은 "구조적 프로그래밍"이라는 용어를 사용하여 제어 구조의 보급을 위한 기술 세미나를 진행했고, 뵘 등의 증명을 "구조화 정리"라는 이름으로 소개하며 이론적 근거로 삼았다. 이로써 구조적 프로그래밍은 IBM이 제창하는 구조화 정리를 논거로 한 제어 구조를 사용하는 프로그래밍 기법으로 널리 알려지게 되었다.
데이크스트라의 주장을 지지했던 도널드 커누스는 1974년 "Structured Programming with go to Statements"[22]를 발표하여 GOTO문 없는 프로그래밍의 본질에 대해 설명하고 GOTO문을 유용하게 사용할 수 있는 경우를 제시하며 논쟁에 대한 균형 잡힌 시각을 제공하려 했다. 하지만 GOTO문 논쟁은 이후에도 계속되었고, 특히 1970년대 후반 마이크로컴퓨터 보급과 함께 BASIC 사용자가 늘어나면서 GOTO문을 사용하지 않는 것 자체가 구조적 프로그래밍이라는 단순한 인식이 퍼지며 논쟁이 재점화되기도 했다.[50] 데이크스트라의 "GOTO문의 해로움"이라는 글은 이후 컴퓨터 과학 분야에서 특정 기술이나 관행의 과도한 사용을 비판할 때 "...의 해로움"이라는 제목을 사용하는 유행을 낳기도 했다.
6. 2. 프로그래머 습관 개선
구조적 프로그래밍은 단순히 기술적인 변화를 넘어 프로그래머들의 코딩 습관과 사고방식에 깊은 영향을 미쳤다. 데이크스트라는 1967년 발표한 "GOTO문의 해로움"이라는 글을 통해, 무분별한 GOTO문 사용이 코드의 논리적 흐름을 파악하기 어렵게 만들고 오류를 유발하기 쉽다고 지적하며 구조화된 제어 흐름의 중요성을 강조했다. 그는 구조의 종류를 제한하는 것이 프로그래머가 문제 해결에 더 집중하게 하고, 프로그램의 정확성을 보다 쉽게 증명할 수 있게 한다고 주장했다.이러한 주장은 프로그래머들이 코드를 작성하는 방식에 변화를 가져왔다. 구조적 프로그래밍의 원칙을 따르면서 다음과 같은 긍정적인 습관들이 형성되었다.
- 모듈화: 큰 프로그램을 관리하기 쉬운 작은 단위(함수, 프로시저, 메서드 등)로 나누어 작성하는 것이 일반화되었다. 이는 프로그램 전체를 한 번에 이해하지 않고도 각 부분을 독립적으로 파악하고 개발할 수 있게 도왔다.
- 지역성 강화: 전역 변수의 사용을 최대한 줄이고, 각 함수나 블록 내에서 필요한 데이터는 지역 변수나 매개변수를 통해 전달받는 방식이 권장되었다. 이는 코드의 특정 부분이 프로그램 전체에 미치는 예기치 않은 영향을 줄여 코드 가독성과 유지보수 용이성을 높였다.
- 복잡성 제어: GOTO문 사용을 자제하는 것 외에도, 조건문이나 반복문 등을 지나치게 깊게 중첩시키거나, 하나의 함수를 너무 길게 작성하는 것을 피하는 경향이 생겼다. 이는 코드의 논리적 흐름을 명확하게 하고 이해하기 쉽게 만들었다.
물론 도널드 커누스처럼 GOTO문의 완전한 제거에는 반대하며 특정 상황에서의 유용성을 주장하는 목소리도 있었고, 실제 IBM의 밀즈가 현장에 적용한 방식은 데이크스트라의 초기 이론과는 다소 차이가 있다는 비판도 있었다. 1987년 프랭크 루빈이 "''GOTO문의 해로움''의 해로움"이라는 글을 발표하는 등 논쟁이 이어지기도 했으나, 20세기 말에 이르러서는 구조적 프로그래밍의 핵심 원칙들이 프로그래밍 교육과 실제 개발 현장의 표준으로 자리 잡게 되었다.
결과적으로 구조적 프로그래밍은 프로그래머들이 더 명확하고, 이해하기 쉬우며, 신뢰성 높은 코드를 작성하도록 유도하는 중요한 계기가 되었다. 이는 단순히 코딩 스타일의 변화를 넘어, 소프트웨어의 품질, 개발 생산성, 유지보수 효율성을 향상시키는 데 크게 기여했다. 현대 프로그래밍 언어들은 대부분 구조적 프로그래밍을 기본적으로 지원하며, 예외 처리와 같은 발전된 메커니즘을 통해 구조적 프로그래밍의 개념을 계승하고 보완하고 있다.[2][3]
6. 3. "...의 해로움" 유행
데이크스트라가 1967년 ''CACM''에 기고한 서한 "GOTO문의 해로움"은 구조적 프로그래밍 논쟁의 중요한 시작점으로 여겨진다. 이 서한의 제목 형식인 "... considered harmful"은 이후 컴퓨터 과학 분야에서 특정 기술이나 관행이 과도하게 사용되거나 해롭다고 비판할 때 인용되는 일종의 유행어, 즉 "...의 해로움" 유행을 낳았다.이러한 유행의 대표적인 예로, 1987년 프랭크 루빈은 데이크스트라의 주장에 반박하며 "''GOTO문의 해로움''의 해로움"('Go to statement considered harmful' considered harmful)이라는 제목의 글을 발표했다.[7] 이 글은 루빈과 다른 비판자들에 대한 데이크스트라의 날카로운 재반박을 포함하여 많은 논쟁을 불러일으켰다.
참조
[1]
서적
Comparative programming languages
https://books.google[...]
Addison-Wesley
2015-11-25
[2]
웹사이트
What is Structured Programming?
https://www.techtarg[...]
2024-04-09
[3]
웹사이트
Reading: Structured Programming {{!}} ITE 115 Introduction to Computer Applications and Concepts
https://courses.lume[...]
2024-04-09
[4]
서적
Programming on Purpose, Essays on Software Design
https://archive.org/[...]
Prentice-Hall
1993-02-12
[5]
AV media
DLS • Donald Knuth • All Questions Answered
https://www.youtube.[...]
University of Waterloo
2018-11-15
[6]
학술지
Structured programming with go to statements
http://cs.sjsu.edu/~[...]
1974-12
[7]
학술지
'"GOTO Considered Harmful" Considered Harmful'
http://www.ecn.purdu[...]
1987-03
[8]
기술 보고서
Code Sandwiches
http://research.cs.w[...]
2008-10
[9]
서적
Refactoring: Ruby Edition
Pearson Education
[10]
서적
C++ Coding Standards: 101 Rules, Guidelines, and Best Practices
Pearson Education
[11]
서적
Touch of Class: Learning to Program Well with Objects and Contracts
Springer Science & Business Media
[12]
웹사이트
Single-Entry, Single-Exit, Should It Still be Applicable in Object-oriented Languages?
http://msmvps.com/bl[...]
2014-07-15
[13]
서적
Programming Languages: Principles and Practices
Cengage Learning
[14]
서적
Introduction to Programming Languages
CRC Press
[15]
학술지
Exceptional Situations and Program Reliability
http://www.cs.virgin[...]
[16]
서적
Parallel Programming in OpenMP
Morgan Kaufmann
[17]
웹사이트
構造化プログラミングとは - IT用語辞典
http://e-words.jp/w/[...]
2020-06-01
[18]
웹사이트
構造化プログラミング - 意味・説明・解説 : ASCII.jpデジタル用語辞典
https://yougo.ascii.[...]
2020-06-01
[19]
문서
E. W. Dijkstra, “Structured Programming”, In Software Engineering Techniques
http://homepages.cs.[...]
[20]
서적
プログラミングの科学
培風館
[21]
간행물
流れ図
共立出版
[22]
학술지
Structured Programming with go to Statements Computing Surveys
[23]
간행물
系統的プログラミング/入門
近代科学社
[24]
학술지
Flow Diagrams, Turing Machines And Languages With Only Two Formation Rules
ACM, New York, NY, USA
[25]
학술지
Go To Statement Considered Harmful
[26]
학술지
GO TO 論争:第1部 go to 文有害説
共立出版
[27]
학술지
GO TO 論争:第2部 GO TO 論争
共立出版
[28]
간행물
GO TO 論争:第3部 解説
共立出版
[29]
문서
有澤誠訳『文芸的プログラミング』p.45
[30]
문서
B. Randell and J.N. Buxton, (Eds.), Software Engineering
http://homepages.cs.[...]
[31]
간행물
ダイクストラかく語りき
共立出版
[32]
학술지
プログラミング−工芸から科学へ
情報処理学会
[33]
간행물
構造的プログラミング
共立出版
[34]
학술지
ソフトウェア工学の40年
http://www.graco.c.u[...]
[35]
서적
Structured Programming: Theory and Practice
Addison-Wesly
[36]
PDF
On Folk Theorems
http://www.wisdom.we[...]
[37]
논문
On folk theorems
http://portal.acm.or[...]
1980-07-01
[38]
서적
Introduction (Chief Programmer Team Management of Production Programming)
YOURDON inc.
[39]
논문
プログラミング方法論の問題点:超職業的プログラミングについて
情報処理学会
[40]
서적
算法表現論
岩波書店
[41]
서적
エズガー・W・ダイクストラ
日経BP社
[42]
간행물
ダイクストラ教授との3日間
共立出版
[43]
서적
構造化手法によるソフトウェア開発
日経BP社
[44]
웹사이트
What led to “Notes on Structured Programming”
https://www.cs.utexa[...]
2020-01
[45]
논문
ストラクチャード・プログラミング用言語
情報処理学会
[46]
웹사이트
E.W. Dijkstra Archive: What led to "Notes on Structured Programming" (EWD1308)
https://www.cs.utexa[...]
2021-08-16
[47]
서적
プログラミングの方法
サイエンス社
[48]
서적
Structured Programming
Academic Press, London
[49]
논문
What Is Object-Oriented Programming?
IEEE Computer Society Press, Los Alamitos, CA, USA
[50]
웹사이트
wikiquote:Edsger W. Dijkstra#How do we tell truths that might hurt? (1975)
https://en.wikiquote[...]
[51]
문서
構造化プログラミング(1975)
[52]
간행물
構造的プログラミング −批判と支持−
共立出版
[53]
간행물
Programming methodologies, their objectives and their nature
Infotech International
[54]
간행물
構造的プログラミング −批判と支持−
共立出版
[55]
서적
系統的プログラミング/入門
近代科学社
[56]
서적
How to Solve it by Computer
Prentice Hall
[57]
서적
謙虚なプログラマ
共立出版
[58]
웹사이트
The Programming Task Considered as an Intellectual Challenge
http://www.cs.utexas[...]
[59]
웹사이트
Concern for Correctness as a Guiding Principle for Program Composition
http://www.cs.utexas[...]
[60]
웹사이트
Programming as a discipline of mathematical nature
http://www.cs.utexas[...]
[61]
서적
The Craft of Programming
Prentice-Hall
[62]
서적
演習プログラムの証明
近代科学社
[63]
서적
プログラムの基礎理論
サイエンス社
[64]
간행물
Programming methodologies, their objectives and their nature
Infotech International
[65]
서적
プログラミング原論 ― いかにしてプログラムをつくるか
サイエンス社
[66]
서적
ソフトウェアクリーンルーム手法
日科技連
본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.
문의하기 : help@durumis.com