In defense of Donald Knuth’s literate programming

I believe that Donald Knuth’s literate programming paradigm is the ultimate paradigm and the ultimate solution as to what programming should be. We should have and use a programming language with which we describe, in a specific, detailed and human-like way, what each program should do.

It is an unfortunate fact, to say the least, that in the same publication and from the same person that introduced Knuth’s literate programming, came subtle ridicule and opposition for this paradigm. The person that introduced Knuth’s approach, gave a (Unix command line) one-liner for what Knuth’s approach required many pages of literate programming code. And that, in my opinion, stopped what would have been a major breakthrough and paradigm shift in programming paradigms (pun intended).

That presentation of Knuth’s approach, in my opinion, held mankind back. One might think that it may have been only fair that this unfair criticism came from the Unix community that Knuth so much appreciates and upholds, but I don’t think so. First, because it was unfair and second, because not only Knuth and his approach suffered a cruel and unfair blow, but also the evolution of programming in general.

I would suggest to Donald Knuth to be careful in respect to who he considers friends and allies in the future. I know he will not change his respect for the Unix platform, but at least, he should consider it.

As far as literate programming is concerned, people should better take another look at it. It may be the answer they were looking all along. I, for one, consider it to be the solution to all of programming hurdles. The saying “the problem with computers is that they do what you tell them to do and not what you want them to do” nails down all programming hurdles and has to do with our inability to provide programming languages that are close to us and not to computers. Literate programming solves those problems in particular.

In the past, before I even read about literate programming, I would take such an approach whenever I could. If I saw someone that would create a SQL statement to retrieve data from a database, I would instruct them to use a full blown program instead. If the person would say that the SQL statement was adequate, I would reply that the specification may change and the data retrieval might require more elaborate logic in the future.

And if I saw someone use a one-liner shell command to obtain filenames or data from files, I would instruct them to use a program or a script instead. Again, my justification for this would be that the logic may need enhancement in the future. Requirements tend to change, especially if the requirements are not your requirements but your clients’ requirements. But this is not the only reason. Clients also expect that small changes to their wording or the introduction of ifs (conditionals) to their requirements should not be a lot of burden to you, so they expect quick delivery and a small charge for the changes they asked. So, you should be prepared to meet their requirements and do the changes they asked with little effort and in a short time. And you can accomplish that if you have anticipated these changes and have created a solution that can easily be enhanced. Your solution should not be rigid and change-challenged. One-liners, declarative programming, SQL statements and regular expressions should be avoided.

It is not only Turing completeness that you should strive for when looking for a programming language and paradigm in which to base your efforts. You should also respect the way the client presents her problem to you. If she uses a functional paradigm, then you should use a functional approach as well. If she does not, then you should not, too.

Indeed, if the client describes a problem to you and she knows how she wants the problem to be solved, you have better follow her lead and use a language that can describe her steps to the solution. I would advice against creating a different approach, even if that approach solves the problem in its entirety. And the reason I would advice against it is that the client may later add another requirement, tiny if her approach was used, huge if your approach is used. The client would not be happy to hear that you used a convoluted logic to solve her problem. She may instruct you to use her approach to make things easy for you and for her, something you should have done all along.

Let me give you an easy example. The client comes to you and says that she wants to take all lines from a number of files. For each line, she wants to take the third letter of the fourth word. Easy enough, so you might use a shell one-liner or a program with a regular expression. But then she changes her requirements and wants you to take the third letter of the fourth word, as before, but only if it is the same letter with the particular filename’s sixth letter. Things are more hectic now, but let’s say that you a command line wizard or a regular expressions master. So you make this happen as well. And then the client comes and says that she wants you to take the third letter of the fourth word only if it is the same letter with the particular filename’s sixth letter, otherwise she wants to take the count of all the previous lines in the particular file. Now, wouldn’t it be better if you have anticipated all this and started writing a full blown program all along?

And how should you write such a program? The programming language you use should allow you to use the client’s specifications as they were given to you. You want a programming language that you can use to write a program as follows:

Get the names and paths of the particular files
For each file in these files
{
   For each line in the file
   {
      Get the fourth word
      Get this word’s third letter
      Get the sixth letter of the file’s name
      If the third letter of the fourth word and the sixth letter of the file’s name are the same
      {
         Output the third letter of the fourth word
      }
      Else
      {
         Find the number of lines that precede this line in the file
         Output this number
      }
   }
}

(Please note that I just came up with the syntax that I just used. This is not the same syntax as in Knuth’s literate programming, but it will help me prove my point nonetheless.)

Now this is a program that I can read and understand and that corresponds to what the client asked for. Later, when the client wants you talk about the program and future enhancements, the layout/code above is something that can be understood and changed easily.

Keep in mind that the client does not care if you used a clever regular expression to solve a problem. When she later wants you to provide a more elaborate program in place of this regular expression, you might find it difficult, because it would require a massive change in your approach. I would definitely not suggest explaining to your client that regular expressions are not Turing complete! This is not what the client wants to talk about. The client wants to talk about straightforward solutions to what appear (and usually are) straightforward problems.

You might have constructed the most elaborate SQL statement. If your reporting environment allows you to only make one query and display the results of this query, then the client will not be happy to learn that it may be difficult to add a little bit of logic to that. “All you have to do is add an if” is what she will say. It just may happen that the logic she wants in this “if” is something that cannot be described in SQL. The client should not be the one to take the blame, here.

The layout/code I provided above should help you understand what literate programming is all about. It is a programming style that corresponds to the way you would describe the program’s logic to someone. And while it is descriptive, it is, thankfully, not declarative. You can describe any logic with ease and, most importantly, without hacks, the kind of hacks that any other programming paradigm might have you pull.

Imagine having someone provide another solution to the problem I solved with my layout/code above. Imagine someone solving that same problem with a Unix shell one-liner. It will certainly be something along the lines of those find, grep, sort, uniq, cat, cut, sed, awk commands chained together with pipes. These solutions puzzle me. I have to remember what each command does and how it is programmed. And then I have to follow the logic, which more often than not is one of clever hacks; an approach which, by the way, is most prone to errors. And, most of all, it is ineligible. And let’s not talk about the eligibility of regular expressions! Let’s not even go there!

The client wants you to follow her lead and her guidelines. Although I am big fan of the functional programming paradigm, I would advice against using it if your specifications are not given as such. The client does not want you using clever tricks, clever hacks or clever program “juggling”. She wants you to know that you follow a comprehensive, legible, clean approach. She wants things in your code to be as tidy and as ordered as they are in her mind.

The person that introduced Knuth’s literate programming, used a command shell one-liner as an equivalent approach to pages and pages of literate programming code. Although both approaches produced the same results, they were certainly not equivalent as far as eligibility and enhancement ability are concerned. Shorter programs are not always easier maintained, easier to enhance or more understandable.

You should strive to provide solutions that correspond to how humans think and, particularly, to how your client thinks. You should be able to code in a way that your code resembles, nay, is the specifications that you use. You should not care about whether your program is small or big. You should care about how easy it is to understand, change and maintain it. You should not rush to provide your client with a program that solves just the particular problem at that point in time. Instead, you should provide your client with a program that is coded in a way that is legible even for the client and can anticipate or accommodate any change required from it. When you present a program to your client, you should be able to feel confident about your solution, in terms of correctness, eligibility and expandability. You should always be able to (at least in your mind) say to your client: “Evaluate this program and then hit me with your best shot”.

Advertisements

About Dimitrios Kalemis

I am a systems engineer specializing in Microsoft products and technologies. I am also an author. Please visit my blog to see the blog posts I have written, the books I have written and the applications I have created. I definitely recommend my blog posts under the category "Management", all my books and all my applications. I believe that you will find them interesting and useful. I am in the process of writing more blog posts and books, so please visit my blog from time to time to see what I come up with next. I am also active on other sites; links to those you can find in the "About me" page of my blog.
This entry was posted in Development. Bookmark the permalink.