38

In a project that aspires from the onset to be maintainable across a revolving team of developers, what difference would it make to use literate programming against thorough commenting guidelines?

The latter would imply: classes with explicit purposes of what they do, why they are there, with examples, non-cryptic error codes, variables with inline explanations, a style guide that forces developers to use plain English, full sentences, eschew abbreviations and so on. Add to it that an IDE could be able to collapse the details or you could just extract the docs.

Could it be that literate programming was a solution to problem that was tackled meanwhile through other means? Could it be that back then, when literate programming was created, some languages/tools wouldn't allow for simple mechanisms like these?

14
  • 2
    Does this answer your question? How would you know if you've written readable and easily maintainable code?
    – gnat
    Jul 22, 2020 at 10:08
  • 4
    see also: “Comments are a code smell”
    – gnat
    Jul 22, 2020 at 10:09
  • 6
    @gnat: your first comment is completely off-track. The second one is ok (the OP should read it to understand tons of comments are not a solution to maintainability) , though not providing an answer to the question.
    – Doc Brown
    Jul 22, 2020 at 10:09
  • 6
    You mean literate programming by Knuth, I guess?
    – Doc Brown
    Jul 22, 2020 at 10:14
  • 4
    Seems the problem is twofold. First, many programmers simply can't (not won't) write reasonably literate & comprehensible blocks of text, so programming careers would be open only to people who can both code and write. This severely restricts the pool of potential employees. Second, judging from the examples I've seen of it, "literate programming" is much more difficult to read & understand than plain old C.
    – jamesqf
    Jul 23, 2020 at 3:15

8 Answers 8

53

Literate programming is the nice idea that you can write your code together with an explanation or walkthrough of that code. Importantly, you are not constrained by the syntax of the underlying programming language but can structure your literate program in any way to want. (Literate programming involves chunks of code embedded into text, not comments into code.)

There are three huge problems with literate programming: it takes a lot of effort, there is little tooling, and changes become more difficult.

  • Documentation always requires effort. Literate programming requires less effort than maintaining separate documentation of comparable quality. However, this amount of effort is still unwarranted for most kinds of code. A lot of code is not interesting and requires little discussion, it's mostly just delegating stuff to some framework. The kind of tricky logic that benefits from literate programming is comparatively rare.

  • While there are various tools for literate programming (including Knuth's original WEB, and decent support in the Haskell ecosystem), they all suck. The next-best thing I've come across is org-mode, but that requires the use of Emacs. The problem is that programming is more than typing letters, it's also debugging and navigating code, which benefits greatly from an IDE-style experience. Auto-complete is non-negotiable! Literate programming tools also tend to require non-standard build processes, or mess up line numbers in error messages – not acceptable. If a tool makes your code easier to understand but harder to debug, that's not necessarily a good choice.

  • Related to this is the issue that changes to literately programmed software become more difficult. When you refactor code, you also have to restructure the document. But while you have a compiler or linter to ensure that your code continues to make sense, there's no guarantee that you haven't disrupted the structure of the document. Literate programming is writing and programming to equal parts.

So while full-blown literate programming does not seem to have a place in modern software development, it is still possible to reap some of the benefits. Consider in particular that literate programming is now over 35 years old, so a lot has happened in the meanwhile.

  • Extracting a function with a useful name has many of the same benefits of a chunk of code in literate programming. It's arguably even better because variable names get their separate scope. Most programming languages allow functions to be defined in an arbitrary order, which also allows you to structure the source code within a file in a sensible manner.

  • Literate programming can be used to describe the “why” of a code in a human-readable manner. A somewhat related idea is to express requirements for your program in a both human- and machine-readable format, e.g. as suggested by BDD. This forms a kind of executable specification.

  • Some markup languages have the ability to pull code snippets from your source code. This lets the code be code and lets you construct a narrative around these snippets, without having to duplicate, copy, or update the code. Unfortunately, the popular Markdown has no built-in mechanism for that (but RST, AsciiDoc, and Latex+listings do). This is possibly the best current alternative for creating literate programming-style documents.

9
  • 2
    "Literate programming involves chunks of code embedded into text, not comments into code." - This immediately makes me think of Rust's doc tests, i.e. small sample bits of code embedded in documentation comments that are actually runnable tests. Not quite the same, as I don't think there's any straightforward way of different samples to interact with each other, but seems somewhat related to the literate programming concept.
    – 8bittree
    Jul 22, 2020 at 16:24
  • 3
    @8bittree yes, doctests (borrowed from Python) are a play on the “executable documentation” idea and are brilliant, but don't allow larger programs to be assembled in this style (in Rust, every doctest is its own program). Jupyter is another example that allows code and text to be interleaved, but Jupyter's execution model precludes a program to be presented in arbitrary order – code blocks are executed top to bottom.
    – amon
    Jul 22, 2020 at 16:34
  • 7
    To more explicitly state it: Code is checked by a compiler. Comments are not. The two are destined to diverge, and you easily end up with comments that deceive. I like executable documentation like in Python, but remember that only the code is validated to work. The comments explaining the valid code snippet could be completely wrong.
    – Alexander
    Jul 22, 2020 at 20:25
  • 2
    There's a fourth problem with literate programming: redundancy. Saying what you're going to do, then doing it. This is part of the reason why changes are so difficult - in this case it mirrors the effect in traditional programming where stale comments are left after the code has been changed. That's why the advice is so often to write code to be readable, so that comments aren't needed. Jul 23, 2020 at 11:49
  • 1
    @user7761803: You still need to somehow capture the "why" and intent. It can take years to get into a code base that is only a naked implementation (even with reasonable naming of functions and variables). The original developers may not be available for questions for whatever reason. For example, part of the current implementation may be half-baked or incorrect (not what was intended). Jul 23, 2020 at 13:18
27

Literate programming is great in situations where the code is mostly there in support of the prose. That's why Jupyter notebooks and similar are common for scientific programming. I also use it when I am teaching a programming workshop.

In other situations, people often mistakenly think of the comments as being for humans and the code as being for the computer. If that were so, we may as well write in machine code, because the computer doesn't care. Instead we write in high-level programming languages because it's easier for humans to read and write.

Maintainability isn't achieved by "saving" code with copious comments. Messy code is really difficult to write clean documentation for, especially if you're asking the same person to write both. Clean code mostly stands on its own, with comments and other documentation playing a supporting role.

5
  • Would jupyter notebooks (haven't used them) be useful for implementing a large multi-module program, or is it better to document interactions with an existing program? Jul 23, 2020 at 9:04
  • 5
    @ThorbjørnRavnAndersen No, they’re generally recognised to be terrible at that. Some people (me included) even question their usefulness for their purported main purpose, which is exploratory data analysis (but also teaching). Joel Grus gave an influential talk on the subject, I don’t like notebooks. Jul 23, 2020 at 10:23
  • 2
    @ThorbjørnRavnAndersen, in my mind, jupyter notebooks are in the same category of tools as UML diagrams. Very useful when you're talking about code. Not so much in the day to day of building code. Jul 23, 2020 at 14:23
  • 1
    @ThorbjørnRavnAndersen Although it was designed to create documents with embedded code in my experience very few people I know use it for that purpose. Instead they use it as a terminal that speaks Python and has access to their database. Jupyter notebook is most commonly used as a command line (the fact that it saves everything feels more like a history feature instead of constructing documentation)
    – slebetman
    Jul 24, 2020 at 3:11
  • @slebetman It's great as a command-line replacement; I can also imagine a more general scripting engine built around the concept - really, anything where you want a freeform organization of code, with a bit of context. I've been working on a PoC of literate programming for game scripting - most of that is built around mostly isolated snippets of code that benefit greatly from context. I expect the smaller the pieces of code you need to understand the code, the more value you get from literate programming.
    – Luaan
    Jul 24, 2020 at 10:21
14

The modern attempts of the core idea of literate programming seems to be Jupyter notebooks.

In Knuth's own words: "The main idea [of literate programming] is to treat a program as a piece of literature, addressed to human beings rather than to a computer". That's pretty much what a Jupyter notebook is, a literature for human to read and share ideas, that just happens to contain interactive, executable code.

Generally, it seems like literate programming generally only makes sense if you're writing an academic paper or an article, and you want to include executable code in that paper/article.

literate programming was a solution to problem that was tackled meanwhile through other means

Yes, modern programming tend towards the thinking to improve readability of the code rather than adding comments. If code isn't readable without comments, then the code should be refactored so it is readable without comments. This is mainly through judicious use of intent revealing name and structures.

1
  • 10
    There is a vast difference between "readable without comments" and "understandable without comments". Programs tell you how, not why, and you need both to maintain them. Jul 23, 2020 at 9:03
2

Literate programming was a great idea at that time (and in fact I used it back then to write the only piece of software with a public release and some user-base, which never got any error report.)

But: there are some "buts":

  • IDEs nowadays often use some kind of real-time-while-you-type compilation to show errors immediately. This probably would not work.
  • Software used to be much smaller in the 80s. The complete codebase of TeX would be less than a single module in any piece of enterprise software today. Therefore, it is very difficult to structure software as a single train of thought now, which is where literate programming really shines.
  • I am not aware of any source-level-debugger for literate programming. (Enlighten me via a comment if there is one.) This is a tool which I'd never go without.
5
  • 3
    It would be great today, but nobody creates the tools.
    – gnasher729
    Jul 22, 2020 at 10:51
  • 1
    I did some experiments with writing code using nuweb back in the day, and added the necessary directives to have the compiler understand the .w file was the source, so the debugger (gdb iirc) used that instead. Jul 23, 2020 at 12:34
  • 1
    The popularity of languages that do code generation (see the multitude of languages that compile down to JavaScript) means that there's actually pretty good debugger support in some stacks these days for distinguishing between the generated code corresponding with a given line, and the original source corresponding with that generated line. Building plumbing to generate such a map from the input to your literate-programming tool does not strike me as an insurmountable task. Jul 24, 2020 at 22:12
  • Can you include some background info on your software which had no error reports (a link would be fine)? I'm interested in knowing more. Jul 30, 2020 at 14:11
  • Too long ago. It was a program named "shark" made to gobble up the contents of "fish disks" which were the most popular freeware library on the Amiga in the 90s. I don't have the code any more.
    – mtj
    Jul 30, 2020 at 17:49
2

Wikipedia says:

"The literate programming paradigm, as conceived by Knuth, represents a move away from writing computer programs in the manner and order imposed by the computer, and instead enables programmers to develop programs in the order demanded by the logic and flow of their thoughts."

I don't think modern programming languages impose many order constraints that matter, so I don't see any big difference from using appropriate comments in the source code.

Also per wikipedia:

"The main intention behind this approach was to treat a program as literature understandable to human beings."

That seems a good aspiration. Good coding style ( appropriate choices of names, etc. ), combined with extra explanation in comments where appropriate is the answer, but it's mostly just hard work. I don't think there are any silver bullets here.

3
  • 2
    Have you ever actually tried using it? Jul 23, 2020 at 9:02
  • 1
    What modern programming languages? Don't all imperative languages impose order? Jul 23, 2020 at 13:29
  • @PeterMortensen: No, the order in which operations appear in the source code is up to the programmer. Consider: y = f(g(x)) vs t = g(x); y = f(t) or even y = g(x).f()
    – Ben Voigt
    Jul 24, 2020 at 20:01
1

What Knuth’s literate programming tools would allow you to do: Say you want a new feature. And for that feature, you need to create classes X and Y, and make changes to method in classes A, B and C. “Literate programming” would let you put all that in one source file, instead of say C++ where you had to add two header files and two source files for the classes, plus make changes in 3 different files.

This was very nice, but worked in Pascal (I think) only and I haven’t seen it implemented anywhere else.

Newer languages are getting closer. For example Java and Swift where you don’t have separate header and source files (Swift can extract the interface = what programmers need, not what the compiler needs like C++, don’t know what Java has). That’s a big step.

Other newer features are closures that pack up small bits of code that could be plugged into other classes. So the new classes you added for feature X might add bits of code to classes A, B and C like in Literate Programming, through language features and through having classes prepared for this. Not quite the same, but getting closer.

You still need documentation in literate programming, so this isn’t either / or.

4
  • 1
    There was a C-weave and -tangle back in the 90s (which I used.)
    – mtj
    Jul 22, 2020 at 11:29
  • But having separate header and source files makes things MUCH more readable/understandable.
    – jamesqf
    Jul 23, 2020 at 3:07
  • You missed the bit about expressiveness in the documentation while still being part of the code. That is to me the real advantage. Jul 23, 2020 at 9:01
  • Re "...worked in Pascal (I think) only": No, it is also available for C / C++ (CWEB). As an example, an entire embedded system has been written in it (still in use/active development at least until 2018). As part of the build process, a single large C file is generated and presented to the C compilers (several C cross compilers). Jul 23, 2020 at 12:50
1

tl;dr - README.md is the modern day heir to literate programming

First of all, Knuth invented literate programming because he needed it for typesetting his books digitally. This was around 1980, making it probably the oldest software package in common use today (not counting mainframes).

As he wanted to teach a subject, elaborate explanation of the actual code was paramount. You most likely do not need this today. Also a lot of the features provided (because the assembly language he used - Standard Pascal - didn't) are now implemented in the languages themselves.

What do we need?

  • Documentation close to the code.
  • Documentation contains live code, not a dead copy.
  • Documentation in a form that is a first class citizen on the web (i.e. usable with a browser)
  • Documentation written in a language that is version control friendly, that is plain text.

GitHub is probably the main stream provider of what we have today which in practical use is the direct successor of literate programming, namely README.md files which are written in the Markdown language, and rendered when navigating the source (this is the really important bit). This allows you to easily document and describe your program, and Markdown is easy to learn. The ability to have the Git repository be both code and documentation is a very important milestone!

Screen shot showing rending of live Java code

I did an experiment to see if I could explain how my "Hello, World!" in Dagger 2 (a Java dependency injection framework) was put together at https://github.com/ravn/dagger2-hello-world as a single file being both Java and Markdown (in the spirit of literate programming) and it came out pretty well. I then learned that the AsciiDoc language can refer to snippets in other files (to get live code in the documentation), but I have not yet tested it fully.

3
  • 4
    Re README.md is the modern day heir to literate programming. No, it is not. Literate programming mixes code and comment in a way that documentation and code are intimately intertwined. A README file, in whatever form, separates documentation from code. Jul 23, 2020 at 20:33
  • @david yes it is. Please see the link I gave. Jul 23, 2020 at 20:40
  • 1
    README.md is the modern day heir to literate programming is a bit different than it is possible to partially emulate literate programming by symlinking README.md to a source code file (i.e. having a polyglot of e.g. markdown and Java). Jul 25, 2020 at 0:58
0

Neither

I have a frame challenge for you, you write:

"Could it be that literate programming was a solution to problem that was tackled meanwhile through other means?"

I posit that this problem hasn't been tackled at all, at least not in practice. All the "solutions" here work in theory, and maybe in settings where everyone from the CEO to the junior programmer is convinced of it's use, skilled enough to execute it and has the discipline to never stray from the path.

The only practical example of this I'm aware of (though I'm sure there are more) is the software for the space shuttle

In my personal experience, even the best documented code has a lot of open questions and places where the documentation diverges from the code (no matter commented, literate, wiki-ed or otherwise documented).

The most successful projects I've encountered however would, bar one, not even document their code at all but in stead focus on good naming, good structure, code reviews and taking time to get new devs up to speed.

So in my case, the answer to the question in the title would be: Neither.

Not the answer you're looking for? Browse other questions tagged or ask your own question.