One of my absolute favorites by Dijkstra, most neatly summed up as “computing science is hard, now shut up and teach it.” It’s filled with neat little nuggets (“As economics is known as ‘The Miserable Science’, software engineering should be known as ‘The Doomed Discipline’”) and also addresses a serious concern about the ways Computer Science is taught.
There are echoes of this piece in his letter to the UT Austin Budget Council about switching from Haskell to Java as the introductory language, in which he says the following:
It is not only the violin that shapes the violinist, we are all shaped by the tools we train ourselves to use, and in this respect programming languages have a devious influence: they shape our thinking habits. This circumstance makes the choice of first programming language so important. One would like to use the introductory course as a means of creating a culture that can serve as a basis for computing science curriculum, rather than be forced to start with a lot of unlearning (if that is possible at all: what has become our past, forever remains so).
Lots of great stuff in here mixed in with just enough outrageously foolish bits to keep it interesting.
Unfathomed misunderstanding is further revealed by the term “software maintenance”, as a result of which many people continue to believe that programs —and even programming languages themselves— are subject to wear and tear. Your car needs maintenance too, doesn’t it?
In the same vein I must draw attention to the astonishing readiness with which the suggestion has been accepted that the pains of software production are largely due to a lack of appropriate “programming tools”. […] Again, the shallowness of the underlying analogy is worthy of the Middle Ages.
This from an era when the idea of first-class functions was relegated to a handful of academic languages.
Actually, I think it is reasonable to complain that the analogies used by software engineering are woefully inadequate for all the reasons he cites.
The approaches and terminology he describes have now been so thoroughly institutionalized that we’re unlikely to ever be rid of them. Routine bug-fixes and extension are certainly necessary and will likely forever more be called “maintenance” but it’s still nice to think “what if”, what if we could call this activity something that didn’t imply the electrons got tired after doing the same thing repeatedly.
If you leave your car in the garage and never drive it around, it won’t need maintenance. Likewise if your software runs in isolation and doesn’t have to interact with the wider, constantly-changing world, then once you’ve gotten it running, it may not need maintenance. Maybe this was less obvious in Djikstra’s world before the browser parade and new OS versions twice a year, but “bitrot” is a real thing, it’s just a function of the software’s interaction with the outside world rather than something intrinsic to the code itself.
That’s the interesting semantics of common terms like “bug”. It seems to imply that there was something that happened to do the code, that a problem somehow sneaked into the system. It hides the fact that bugs happen because somewhere along the line someone made a mistake.
On a broader scope, Dijkstra spent a lot of time talking about formal verification, and the idea of programs being “correct by construction”. Essentially, this is the opposite of today’s largely test-based systems. In a test-based system, you build the thing and then use tests to verify that you built it correctly. But a test can only show the presence of problems, not prove their absence. On the other side, formal verification (say, verification by a type checker) can prove the absence of certain problems, but will also necessarily reject otherwise correct programs. Put another way, formal verification provides a lower bound on failure (“this class of errors cannot happen”), while testing provides an upper bound (“this class of errors do not happen”).
Bugs are those things which, due to programmer mistakes, have escaped one or both of these protective measures. One of the major reasons for expansions in both type systems and testing frameworks is the recognition of the importance of removing bugs. Essentially, when you reduce the space available for bugs to occur, you reduce the proportion of bugs in a code base. But really, you reduce the number of mistakes programmers can make and ship.
“Bug” is unlikely to stop being the default term for a programmer mistake, but happily, bugs are likely to become less and less common as our ability to formally verify programs via type checking and test them via testing frameworks improves. All is not lost.
One of my absolute favorites by Dijkstra, most neatly summed up as “computing science is hard, now shut up and teach it.” It’s filled with neat little nuggets (“As economics is known as ‘The Miserable Science’, software engineering should be known as ‘The Doomed Discipline’”) and also addresses a serious concern about the ways Computer Science is taught.
There are echoes of this piece in his letter to the UT Austin Budget Council about switching from Haskell to Java as the introductory language, in which he says the following:
Lots of great stuff in here mixed in with just enough outrageously foolish bits to keep it interesting.
This from an era when the idea of first-class functions was relegated to a handful of academic languages.
Actually, I think it is reasonable to complain that the analogies used by software engineering are woefully inadequate for all the reasons he cites.
The approaches and terminology he describes have now been so thoroughly institutionalized that we’re unlikely to ever be rid of them. Routine bug-fixes and extension are certainly necessary and will likely forever more be called “maintenance” but it’s still nice to think “what if”, what if we could call this activity something that didn’t imply the electrons got tired after doing the same thing repeatedly.
If you leave your car in the garage and never drive it around, it won’t need maintenance. Likewise if your software runs in isolation and doesn’t have to interact with the wider, constantly-changing world, then once you’ve gotten it running, it may not need maintenance. Maybe this was less obvious in Djikstra’s world before the browser parade and new OS versions twice a year, but “bitrot” is a real thing, it’s just a function of the software’s interaction with the outside world rather than something intrinsic to the code itself.
That’s the interesting semantics of common terms like “bug”. It seems to imply that there was something that happened to do the code, that a problem somehow sneaked into the system. It hides the fact that bugs happen because somewhere along the line someone made a mistake.
On a broader scope, Dijkstra spent a lot of time talking about formal verification, and the idea of programs being “correct by construction”. Essentially, this is the opposite of today’s largely test-based systems. In a test-based system, you build the thing and then use tests to verify that you built it correctly. But a test can only show the presence of problems, not prove their absence. On the other side, formal verification (say, verification by a type checker) can prove the absence of certain problems, but will also necessarily reject otherwise correct programs. Put another way, formal verification provides a lower bound on failure (“this class of errors cannot happen”), while testing provides an upper bound (“this class of errors do not happen”).
Bugs are those things which, due to programmer mistakes, have escaped one or both of these protective measures. One of the major reasons for expansions in both type systems and testing frameworks is the recognition of the importance of removing bugs. Essentially, when you reduce the space available for bugs to occur, you reduce the proportion of bugs in a code base. But really, you reduce the number of mistakes programmers can make and ship.
“Bug” is unlikely to stop being the default term for a programmer mistake, but happily, bugs are likely to become less and less common as our ability to formally verify programs via type checking and test them via testing frameworks improves. All is not lost.