18 August 2005
by Joseph Jang
Go To Statement Considered Harmful by Edsger W. Dijkstra
Go To Statement Considered Harmful
the go to statement should be abolished from all "higher level" programming languages (i.e. everything except, perhaps, plain machine code)
Dijkstra의 "Go To Statement Considered Harmful"은 모든 고급 프로그래밍 언어에서 go to 문이 사라져야한다는 주장을 하고 있다.
Supposition
My second remark is that our intellectual powers are rather geared to master static relations and that our powers to visualize processes evolving in time are relatively poorly developed. For that reason we should do (as wise programmers aware of our limitations) our utmost to shorten the conceptual gap between the static program and the dynamic process, to make the correspondence between the program (spread out in text space) and the process (spread out in time) as trivial as possible.
그러한 주장에 대한 논지를 전개하기 전에 Dijkstra는 인간의 지적인 능력은 정적인 관계에 맞춰져있고, 시간에 따라 변화하는 프로세스들을 지각하는 능력은 상대적으로 떨어진다는 직관을 가정으로 내세우고 있다. 그리고, 그러한 이유로 정적인 프로그램과 동적인 프로세스 간의 개념적인 괴리를 줄이고 프로그램과 프로세스의 상응성을 가능한한 단순하게 만들어야한다고 주장하고 있다.
The Progress of a Process: Textual indices, Dynamic indices
이 후에 Dijkstra는 프로세스의 진행 정도 (the progress of a process) 를 어떻게 표현할 것인가에 대해서 논의를 하고 있다.
프로그램을 단순히 statement들의 연속 (pure concatenation) 이라고 볼 때, 프로세스의 진행 정도는 프로그램 상의 위치를 가리키는 textual index로 표현할 수 있다. 이는 conditional clauses나 alternative clauses, choice clauses, conditional expression을 도입하더라도 마찬가지다. procedure를 도입한다면 얘기가 약간 달라진다. procedure가 호출되었을 때, 프로세스의 진행 정도는 procedure를 호출한 부분의 textual index와 procedure 상의 texual index 로 표현되어야만 한다. 결국, procedure를 포함하는 프로그램의 프로세스의 진행 정도는 textual index의 집합, 즉 textual indices로 표현된다.
이런 얘기가 너무 추상적이라 이해하기가 힘들다면, 디버깅을 연상하면 되겠다. 어떤 시점의 프로세스의 진행 정도를 알 수 있다면, 그 프로그램의 상태도 유도할 수 있다. (다분히, formal verification의 냄새가…) 따라서, 프로세스의 진행을 중단시켰을 때, 프로그램의 상태, 즉 변수들의 값이 과연 옳은 것인가를 판단하기 위해서는, 이 프로세스가 얼마나 진행되었는가를 판단할 수 있어야한다. textual index나 textual indices는 우리가 디버깅할 때 흔히 보는 line number와 stack trace 정도로 보면 되겠다.
여기에 repetition clauses가 추가되면 좀 더 복잡해진다. repetition clauses 내에서는 프로그램 상의 위치(textual index)만으로 프로세스의 진행 정도를 표현할 수 없다. 따라서, 몇번이나 반복했는가의 정보를 포함하는 dynamic index가 필요하다.
"The unbridled use of the go to statement"
The unbridled use of the go to statement has an immediate consequence that it becomes terribly hard to find a meaningful set of coordinates in which to describe the process progress.
위에서 프로세스의 진행 정도는 textual indices와 dynamic indices의 집합으로 표현할 수 있음을 알았다. 하지만, go to 문이 프로그램에 추가된다면 어떨까? Dijkstra는 그 시점까지 수행된 statement의 수를 나타내는 counter가 필요하다고 얘기한다. 인간은 기계가 아니기 때문에 이러한 counter를 가지고 할 수 있는 것은 별로 없다. 디버깅의 예를 연상해보라. 프로세스 중단 시점까지 수행된 statement의 수가 주어졌을 때, 프로그래머가 프로그램을 가지고 얼마나 효율적으로 디버깅을 해낼 수 있을까? 아니, 프로그래머에게 대체 무슨 의미가 있는가?
procedure call 시의 textual index를 유지하는 것처럼, go to 문이 수행된 지점의 textual index를 유지한다면 어떨까? go to를 너무 난잡하게 쓰지 (unbridled use) 않는 한, 프로세스의 진행 정도를 나타내는 데에는 큰 문제가 없다고 생각한다. 그러한 근거는 conditional/choice/repetition clauses이나 procedure call도 동작 자체는 go to 와 같이 프로그램 상에서의 jump를 수반한다는 점에서 찾아볼 수 있다.
다만, conditional/choice clauses는 그러한 jump를 프로그램의 구조를 통해서 알려주기 때문에 추가적인 textual index를 필요로 하지 않으며, 또한 기존의 textual index 만으로도 jump의 의미를 프로그래머에게 명확하게 전달해준다. repetition clauses의 경우에도 jump는 반복이라는 단순한 의미를 담고 있다. procedure의 경우도 어떤 code block으로 jump 했다가 다시 돌아온다는 단순한 jump 모델을 바탕으로 하고 있다. conditional/choice/repetition clauses와 procedure는 jump의 동작을 모델화하고 의미를 부여한 go to문인 것이다.
결국, textual/dynamic indices와 같은 coordinates가 프로그래머에게 얼마나 의미가 있는가 (meaningful) 의 문제다. go to 문을 오용할 때, 그러한 coordinates가 표현하려는 것이 프로그래머에게 의미가 없거나 해석하기가 힘들다는 것이다.
"The go to statement as it stands is just too primitive"
The go to statement as it stands is just too primitive; it is too much an invitation to make a mess of one’s program. One can regard and appreciate the clauses considered as bridling its use. I do not claim that the clauses mentioned are exhaustive in the sense that they will satisfy all needs, but whatever clauses are suggested (e.g. abortion clauses) they should satisfy the requirement that a programmer independent coordinate system can be maintained to describe the process in a helpful and manageable way.
위의 인용이 이 paper의 결론에 해당한다. 위에서 얘기한 것처럼 conditional/choice/repetition clauses와 procedure는 go to라는 primitive를 의미가 있는 방식으로 사용할 수 있도록 해주는 좀 더 높은 수준의 장치인 것이다. 분명히 go to 문만을 쓰더라도 의미가 있는 방식으로 사용할 수는 있다. 문제는 그렇지 않을 가능성이 있다는 것이고, 때로는 의미가 있는 방식으로 사용했다고 하더라도, 그 의미가 제대로 해석되지 않을 가능성이 있다는 것이다.
Dijkstra는 이러한 clauses들이 go to 문의 모든 필요를 충족시킬 것이라고 생각하지는 않는다. 실제로 Donald E. Knuth의 Structured Programming with go to Statements나 David R. Tribble의 Go To Statement Considered Harmful: A Retrospective 또는 Linux kernel에서는 go to 문의 필요성을 보여주고 있다.
사실, Dijkstra가 제시한 programmer independent coordinate system이 go to의 harmfulness를 방지하기 위한 좋은 척도는 아니라고 생각한다. 그러한 coordinates가 존재한다는 사실 자체가 go to의 harmfulness를 방지해주는 것은 아니기 때문이다. Dijkstra가 얘기하는대로 coordinates가 존재할 뿐만 아니라 그 coordinates는 충분히 meaningful해야한다. 내 생각에는, 얼마나 meaningful한가와
은 척도에는 프로그래머들의 사고 체계가 관여될 수 밖에 없고, 결국은 문화와 같이 주관적인 성향을 가질 수 밖에 없지 않을까하는 생각이 든다. 예를 들어, repetition clauses를 사용할 때, 프로세스의 진행 정도를 dynamic indices로 표현할 수 있는 것은 우리가 repetition이라는 개념 또는 induction에 익숙하기 때문이고, 만약 그렇지 않았다면, dynamic indices 가 존재한다고 하더라도 이해하기가 힘들지 않았을까?
The Myth: Never Use go to Statements
Dijkstra의 이 paper가 끼친 가장 나쁜 영향은 아무래도 절대로, 절대로 go to를 써서는 안된다는 신앙일 것이다.
No one quarrels with using gotos to emulate structured constructs in languages that don’t support structured control constructs directly. The debate is about languages that support structured constructs, in which gotos are theoretically not needed. Here’s a summary of the points on each side. [16.1 Using gotos]
Steve McConnell은 당연하다는 듯이 이렇게 말하고 있지만, 어디서든 go to를 절대로 써서는 안된다는 신념을 가진 사람들을 여럿 보았다.
go to가 사용되는 예로 가장 흔한 것은 아무래도 error handling이다. C와 같이 exception을 지원하지 않는 언어에서 error handling을 위해서 go to를 사용하는 것은 매우 일반적인 idiom이다. error handling을 주 logic과 분리하는 것이 가독성을 개선한다는 것은 널리 알려진 사실이다. 그럼에도 불구하고, go to문의 사용을 반대하는 사람들은 단지 go to가 거기에 있다는 이유로 그런 프로그램을 나쁜 프로그램으로 생각한다. "Considered Harmful" Essays Considered Harmful의 가장 가까운 예라고 볼 수 있을 것이다.
어디에도 통용되는 말이겠지만, David R. Tribble은 Go To Statement Considered Harmful:
A Retrospective에서 다음과 같이 결론내리고 있다.
Dijkstra’s belief that unstructured goto statements are detrimental to good programming is still true. A properly designed language should provide flow control constructs that are powerful enough to deal with almost any programming problem. By the same token, programmers who must use languages that do not provide sufficiently flexible flow control statements should exercise restraint when using unstructured alternatives. This is the Tao of goto: knowing when to use it for good and when not to use it for evil.
go to 문의 사용에 대한 좀 더 실용적이고 자세한 가이드라인은 Steve McConnell이 Code Complete의 16.1 Using gotos절의 마지막에서 제시하고 있으니, 관심있는 사람들은 읽어보기 바란다.
References
Comments |
Categories: Software Development