The Ascetic Programmer
5/5
()
About this ebook
"You don't need to be stuck on a bus between Oslo and Göteborg to enjoy reading this book [...]
Much interesting stuff to think about for the thinking and practicing programmer.
... and I'm not just saying that because he quotes me :-)"
–Poul-Henning Kamp, Author of Varnish-Cache and many contributions to FreeBSD Unix
Ascetic programming is the writing of computer programs using fewer lines of code or forgoing certain programming language features. Imposing restrictions on programming other than those on resources goes at least as far back as Edsger W. Dijkstra's condemnation of the goto statement. However, among possible restrictions, the one on program length is the most interesting. It has positive associations to computing, from correctness to maintainability.
Asceticism originated as a spiritual practice targeting worldly pleasures and promising salvation or enlightenment. This book will focus mainly on code length restrictions and, more generally, description length restrictions, and our rewards will be plenty and varied, but less spiritual.
Asceticism in programming comes in two flavors: conciseness and frugality. The former aims at delivering the same functionality with fewer lines of code; the latter's goal is identifying essential features and discarding the rest. They both apply to programming at all scales, from snippets to systems.
Beyond programming, unexpected examples of asceticism can be found in statistics, philosophy, the visual arts, music, literature, and more. Outside science and engineering, both the function and the complexity of an artifact are less clear or undefined, so this foray will be, by necessity, more speculative at times.
This book doesn't present a grand theory or a practical method, but rather anecdotes and expert opinions, together with the occasional theorem and research paper, some from giants in their respective fields and some from regular professionals. Let the case for asceticism build from the totality of the book rather than a single, decisive argument.
Hopefully, you will be convinced that asceticism benefits engineering, science, and the arts and inspired to adopt unnecessary restrictions in your endeavors.
Related to The Ascetic Programmer
Related ebooks
Implementing Design Patterns in C# 11 and .NET 7 - 2nd Edition: Learn how to design and develop robust and scalable applications using design patterns (English Edition) Rating: 0 out of 5 stars0 ratingsFundamentals of Software Engineering: Designed to provide an insight into the software engineering concepts Rating: 0 out of 5 stars0 ratingsHow to Observe Software Systems Rating: 0 out of 5 stars0 ratingsSeriously Good Software: Code that works, survives, and wins Rating: 5 out of 5 stars5/5JavaScript Domain-Driven Design Rating: 3 out of 5 stars3/5Data Structures and Algorithm Analysis in Java, Third Edition Rating: 4 out of 5 stars4/5Software Developer Rating: 0 out of 5 stars0 ratingsThe Psychology of Computer Programming: Silver Anniversary eBook Edition Rating: 4 out of 5 stars4/5Haskell from Another Site Rating: 0 out of 5 stars0 ratingsThe Clojure Workshop: Use functional programming to build data-centric applications with Clojure and ClojureScript Rating: 0 out of 5 stars0 ratingsHaskell Design Patterns Rating: 0 out of 5 stars0 ratingsHaskell High Performance Programming Rating: 0 out of 5 stars0 ratingsThe Go Workshop: Learn to write clean, efficient code and build high-performance applications with Go Rating: 0 out of 5 stars0 ratingsThe Fascinating World of Graph Theory Rating: 4 out of 5 stars4/5Introductory Discrete Mathematics Rating: 4 out of 5 stars4/5Learning Functional Data Structures and Algorithms Rating: 0 out of 5 stars0 ratingsAn Introduction to Functional Programming Through Lambda Calculus Rating: 0 out of 5 stars0 ratingsNode.js Blueprints Rating: 0 out of 5 stars0 ratingsGo Programming Blueprints Rating: 0 out of 5 stars0 ratingsData Structures and Algorithms with Go: Create efficient solutions and optimize your Go coding skills (English Edition) Rating: 0 out of 5 stars0 ratingsLearning F# Functional Data Structures and Algorithms Rating: 0 out of 5 stars0 ratingsLearn ClojureScript: Functional programming for the web Rating: 0 out of 5 stars0 ratingsRust In Practice Rating: 0 out of 5 stars0 ratingsThe Coder Habits: The #39# Habits of the Professional Programmer Rating: 5 out of 5 stars5/5Writing Compilers and Interpreters: A Software Engineering Approach Rating: 3 out of 5 stars3/5Data Structures in C / C ++: Exercises and Solved Problems Rating: 0 out of 5 stars0 ratingsLearning Rust Rating: 0 out of 5 stars0 ratingsLearning Cypher Rating: 0 out of 5 stars0 ratings
Mathematics For You
Basic Math & Pre-Algebra For Dummies Rating: 4 out of 5 stars4/5Quantum Physics for Beginners Rating: 4 out of 5 stars4/5What If?: Serious Scientific Answers to Absurd Hypothetical Questions Rating: 5 out of 5 stars5/5Mental Math Secrets - How To Be a Human Calculator Rating: 5 out of 5 stars5/5The Little Book of Mathematical Principles, Theories & Things Rating: 3 out of 5 stars3/5Fluent in 3 Months: How Anyone at Any Age Can Learn to Speak Any Language from Anywhere in the World Rating: 3 out of 5 stars3/5My Best Mathematical and Logic Puzzles Rating: 4 out of 5 stars4/5Precalculus: A Self-Teaching Guide Rating: 4 out of 5 stars4/5Calculus For Dummies Rating: 4 out of 5 stars4/5Basic Math & Pre-Algebra Workbook For Dummies with Online Practice Rating: 3 out of 5 stars3/5Standard Deviations: Flawed Assumptions, Tortured Data, and Other Ways to Lie with Statistics Rating: 4 out of 5 stars4/5Algebra I Workbook For Dummies Rating: 3 out of 5 stars3/5Algebra II For Dummies Rating: 3 out of 5 stars3/5Basic Math and Pre-Algebra: 1,001 Practice Problems For Dummies (+ Free Online Practice) Rating: 3 out of 5 stars3/5Math Magic: How To Master Everyday Math Problems Rating: 3 out of 5 stars3/5How to Solve It: A New Aspect of Mathematical Method Rating: 4 out of 5 stars4/5A Mind For Numbers: How to Excel at Math and Science (Even If You Flunked Algebra) Rating: 4 out of 5 stars4/5Secrets of Mental Math: The Mathemagician's Guide to Lightning Calculation and Amazing Math Tricks Rating: 4 out of 5 stars4/5GED® Math Test Tutor, 2nd Edition Rating: 0 out of 5 stars0 ratingsAlgebra - The Very Basics Rating: 5 out of 5 stars5/5Pre-Calculus For Dummies Rating: 5 out of 5 stars5/5Calculus Made Easy Rating: 4 out of 5 stars4/5Mental Math: Tricks To Become A Human Calculator Rating: 2 out of 5 stars2/5GED Math Test Tutor, For the 2024-2025 GED Test: Certified GED Aligned Prep Rating: 0 out of 5 stars0 ratingsThe Moscow Puzzles: 359 Mathematical Recreations Rating: 5 out of 5 stars5/5The Everything Everyday Math Book: From Tipping to Taxes, All the Real-World, Everyday Math Skills You Need Rating: 5 out of 5 stars5/5Flatland Rating: 4 out of 5 stars4/5Alan Turing: The Enigma: The Book That Inspired the Film The Imitation Game - Updated Edition Rating: 4 out of 5 stars4/5Mathematics, Magic and Mystery Rating: 4 out of 5 stars4/5Calculus Essentials For Dummies Rating: 5 out of 5 stars5/5
Reviews for The Ascetic Programmer
1 rating0 reviews
Book preview
The Ascetic Programmer - Antonio Piccolboni
The Ascetic Programmer
How asceticism benefits programming, science, and the arts
Antonio Piccolboni
Cover illustration based on a program by Robert Nystrom [183]. Used by permission.
Many thanks to Marco Scanu and David Bylsma for providing feedback on an early draft, Tom Lindsey and my wife Maria for patient proofreading and to Maria for her unwavering support.
© 2023 Antonio Piccolboni CC BY-NC-ND
Contents
The Ascetic Programmer
Introduction
Who should read this book?
Reading advice
1 Computing
1.1 Metrics
1.2 Concise Software
1.2.1 Programming
1.2.2 Deleting Code
1.2.3 Repetition
1.2.4 Abstraction
1.2.5 Rewrites
1.2.6 Algorithms
1.2.7 Notation and Formatting
1.2.8 Documentation and Comments
1.2.9 Languages
1.2.10 Libraries
1.2.11 Programs
1.2.12 Systems
1.3 Frugal Software
1.3.1 Programming
1.3.2 Languages
1.3.3 Libraries
1.3.4 Programs
1.3.5 User Interfaces
1.3.6 Systems
1.4 Hardware
1.5 Verbosity and Bloatware
1.6 Code Considered Harmful
1.7 Methodologies
2 Science and Engineering
2.1 Epistemology, Statistics and Machine Learning
2.1.1 The Parsimony Principle
2.1.2 A Universal Prior
2.1.3 Minimum Message Length
2.1.4 Deep Learning
2.1.5 Extreme parsimony
2.2 Mathematics
2.3 Engineering and Design
2.4 Biology
3 Literature, Visual Arts and More
3.1 Speaking and Writing
3.1.1 Concise Writing
3.1.2 Reducing Text
3.1.3 Conciseness is Hard
3.1.4 The Law
3.1.5 Counterpoint
3.2 Visual Arts
3.2.1 Architecture
3.2.2 Photography
3.2.3 Painting
3.2.4 Counterpoint
3.3 Music
3.4 Management
3.5 Humor
Conclusion
Bibliography
Title Page
Cover
Table of Contents
The Ascetic Programmer
Introduction
Ascetic programming is the writing of computer programs under restrictions unrelated to resources such as memory or power. They range from using fewer lines of code to forgoing certain programming language features. My interest in ascetic programming started with challenges among coworkers, which we undertook to keep our skills sharp, our curiosity for programming alive, and, not least, for bragging rights.
We were not the first to think of imposing restrictions on programming other than those on resources. For instance, you may be familiar with Edsger W. Dijkstra’s condemnation of the goto statement (see Sec. 1.6). However, among possible restrictions, the one on program length has caught my long-term interest. It has connections to different facets of computing, from maintainability to testing to theory. These associations are mostly positive, meaning that shorter programs are better along several dimensions: for instance, they are more readable and maintainable and contain fewer errors.
Asceticism originated as a spiritual practice millennia ago. Ascetic restrictions traditionally target worldly pleasures and promise salvation or enlightenment in return. This book will focus mainly on code length restrictions and, more generally, description length restrictions, and our rewards will be plenty and varied, but, unfortunately, won’t include salvation.
Asceticism in programming comes in two flavors, roughly described by the slogans doing more with less
and less is more.
On the one hand, we seek to deliver the same functionality with fewer lines of code; on the other, we aim to identify essential features and discard the rest. I will refer to the former as conciseness and to the latter as frugality. We will discuss both as they apply to programming at different scales, from snippets of code to complete systems.
Beyond programming, I discovered unexpected examples of asceticism in statistics — where the preferred jargon is parsimony — philosophy, the visual arts, music, literature, and more. Outside science and engineering, the function of an artifact is less clear or undefined, and thus the boundary between conciseness and frugality becomes blurred. The equivalent of program length may or may not be available: for instance, it is, to a degree, for statistical models but less so for the visual arts. I hope you will find these more speculative forays interesting.
This book is a collection of cases or testimonials where brevity plays a positive role and where verbosity is the villain. The opposing view that verbosity is superior has also been allotted some space, as a counterpoint, without any pretense of equal treatment. Don’t expect a grand theory or a practical method, but rather a series of interconnected anecdotes and expert opinions, interspersed with the occasional theorem and research paper, some from giants in their respective fields and some from regular people working in the trenches. Let the case for asceticism build from the totality of the book rather than a single, decisive argument.
I hope that, by the end, you will be convinced that asceticism benefits engineering, science, the arts, and more. May this book inspire you to adopt unnecessary restrictions in your endeavors.
Who should read this book?
This book covers a wide variety of subjects, from computer programming to science to the arts. It doesn’t go particularly deep in any of them, but, reflecting my own background, it provides the most detail in the section about computing, less so in the one about science and only makes a cursory pass through the arts. I hope that anyone who has some familiarity with programming and mathematics will be able to enjoy most of the book. While there are plenty of internal connections, many of which I highlighted with cross-references, they are not essential for understanding. Therefore, skipping a subsection here or there won’t prevent you from enjoying the rest.
Reading advice
On devices that allow resizing the text view or the font, I recommend you choose settings such that the display shows a full line of code without wrapping — up to 88 characters. Where supported, long lines will scroll horizontally, and only as a last resort will they wrap. Since, in computer programs, indentation is meaningful, and this book often discusses line counts, this will reduce clarity.
For the most part, footnotes contain definitions of concepts or entities that may be unfamiliar to some. If you don’t feel like you need to read a footnote to improve your understanding, it is probably safe to skip it. Other footnotes provide license information for material reproduced in this book when appropriate.
Code snippets are for illustrative purposes only, are stripped of import or equivalent statements to access libraries, and are not guaranteed to be correct even restoring those statements.
1 Computing
The console of an IBM 650 automatic calculator [1], see Sec. 1.6.Figure 1: The console of an IBM 650 automatic calculator [1],¹ see Sec. 1.6.
1.1 Metrics
A first step towards espousing conciseness as a goal in software engineering is convincing ourselves that lines of code, or LOCs, are a valuable measure of program complexity. Certainly, 100,000 lines of well-structured code are simpler to understand or maintain than the same amount of so-called spaghetti
code, which contains many interactions between its parts. However, one of the pioneering figures in computer science, Edsger W. Dijkstra, posed the problem of size as a fundamental one in software engineering [2]:
[…] widespread underestimation of the specific difficulties of size seems one of the major underlying causes of the current software failure.
Elsewhere, Dijkstra warned again about the dangers of accumulating large codebases [3]:
[…] if we wish to count lines of code, we should not regard them as lines produced
but as lines spent
: the current conventional wisdom is so foolish as to book that count on the wrong side of the ledger.
Dijkstra’s preferred solution, namely structured programming, is intended to make it easier to deal with large codebases rather than to reduce code size (see Sec. 1.2.4).
Microsoft co-founder Bill Gates, according to Internet folklore, said:
Measuring programming progress by lines of code is like measuring aircraft building progress by weight.
In more recent times, this sentiment is still present among developers. For example, free software advocate Chris Warburton writes on Hacker News² [4]:
Software is a liability, not an asset. We should produce as little as needed, and delete it if possible.
In the classic software engineering book The Mythical Man-Month, Frederick P. Brooks Jr. states [5]:
Productivity seems constant in terms of elementary statements, a conclusion that is reasonable in terms of the thought a statement requires and the errors it may include.
Albeit expressed in statements rather than lines, according to the use of the time, this supports the idea that LOCs are a reasonable measure of complexity. This book follows the common practice of counting LOCs. Yet this count is partially dependent on the vagaries of code formatting (see Sec. 1.2.7). An alternative is counting tokens, the size of the representation of a program that a computer builds to run it. It is a formatting-independent measure, which we will adopt in one specific example (see Quicksort in Sec. 1.2.6).
We can often run into invariants like the one referenced above expressed in terms of LOCs. For instance, John Lions, the author of a well-known guide to the Unix operating system (see Sec. 1.3.6), states [6]:
It has often been suggested that 1000 lines of code represents [sic] the practical limit in size for a program which is to be understood and maintained by a single individual.
While the exact value in this statement may be debatable and its origin unclear, what is noteworthy is that it uses LOCs as its unit of measure. Code structure, programming language, or application domain appear to be secondary.
No other quantity has emerged as a viable substitute for LOCs. Herraiz and Hassan review some of the alternatives and come to the following conclusion [7]:
All the complexity metrics are highly correlated with lines of code, and therefore the more complex metrics provide no further information that could not be measured simply with lines of code.
Among the alternatives is cyclomatic complexity [8]. It focuses on the flow of control in a program by viewing it as a graph. A node represents a sequence of statements devoid of control statements, and if and while statements correspond to the subgraphs in Fig. 2.
Graphs corresponding to if and while statements resp.Figure 2: Graphs corresponding to if and while statements resp.
With this graph representation, the cyclomatic complexity of a program is one more than the circuit rank³ of its associated graph, that is, E−N+2PE - N + 2P, where EE is the number of edges, NN is the number of nodes, and PP is the number of connected components. If you suspected this is a long-winded way to count the number of control statements, you would be right, unless we consider multiway branching statements like switch in C. It is possible to double the size of a program without altering its control structure — say, interleaving logging statements with the original ones — and, therefore, without changing its cyclomatic complexity. However, experimental studies show that it correlates well with program size, and those that used it to predict the number of bugs⁴ while controlling for program size had inconsistent results. A possible conclusion is that cyclomatic complexity isn’t so valuable since program size is not a controllable feature of commercial software
[8]. However, program size, controllable or not, predicts crucial properties of software.
One of them is the number of bugs. According to Capers Jones, a consultant on software methodologies, it is more than proportional to program size, falling in the range of 0-25 defects per KLOC (a thousand LOCs) for programs smaller than 2 KLOCs, but rising to 4-100 for those over 512 KLOCs ([9]; as quoted in [10]).
However, even more important than the number of bugs is the probability of project failure, defined as substantially missing a project’s goals. For example, Stack Overflow and Discourse co-founder Jeff Atwood writes [11]:
Here’s the single most important decision you can make on your software project if you want it to be successful: keep it small. Small may not accomplish much, but the odds of outright failure — a disturbingly common outcome for most software projects — is [sic] low.
W. Wayt Gibbs, a science writer for Scientific American, explains [12]:
Software is exploding in size as society comes to rely on more powerful computer systems. That faith is often rewarded by disappointment as most large software projects overrun their schedules and many fail outright — usually after most of the development money has been spent.
1.2 Concise Software
1.2.1 Programming
I actually found a way to shorten his code by 1 word and it had only taken me 20 years to do it. […] it was the only time I’d managed to reduce some of Gosper’s code.⁵ It felt like a real victory. And it was a beautiful piece of code.
In this passage from an interview with Guy L. Steele Jr., inventor of the Lisp dialect Scheme, we read how the quest for conciseness transcended its practical origins and mutated into an aesthetic one [14]. Back in the day when Steele and Bill Gosper, also a founding figure for symbolic computations and Lisp, left their mark on computing, computer memory was so scarce that shortening a program even by one word could have been necessary. Twenty years later, the evolution of hardware and software had been such that there could no longer be practical motivations to shave off a word; only the intellectual ones remained.
Yukihiro Matsumoto, inventor of the programming language Ruby, agrees with the aesthetic qualities of concise code but also adds the language of ethics [15]:
Brevity is one element that helps make code beautiful. […] In the vocabulary of programming, brevity is a virtue.
Dan Ingalls, a key contributor to the implementation of the language Smalltalk, recalls that, as he learned the language FORTRAN, he tried to see how much shorter I could make programs, and stuff like that,
suggesting that, for him, it was a learning or playful activity [14].
For an experimental study, Lutz Prechelt asked several mostly inexperienced programmers to solve a simple string problem in various languages monitoring several properties of the solutions, including length. He concludes [16]:
Interpersonal variability, that is the capability and behavior differences between programmers using the same language, tends to account for more differences between programs than a change of the programming language.
Focusing on program length, this study finds that choice of language and programmer skill or style equally contribute to variation. Yet the point that matters for us is the wide variability in program length for the same task in the same language (see Sec. 1.2.9 for language-dependent conciseness). In this study, the programmers were allowed to code according to their preferred style. Would they have performed differently had they been asked to minimize length?
They may have, but it isn’t something they will often be asked to do in their careers. We have seen that code size was a priority in the pioneering age of computing, and it might still be when developing software for underpowered devices. However, I am not aware that code size currently is an externally imposed constraint on major platforms. An exception should be web development since program download is part of the load time of a page. Yet, it hasn’t prevented web pages from ballooning in size (see the web obesity crisis,
Sec. 1.5). Not only minimizing program length is no longer a goal: at least in some situations, there has been pressure to increase it. In an interview, former Microsoft CEO Steve Ballmer recalls how IBM required billing by the KLOC and that there was no way to convince them that this system discouraged the search for more concise solutions [17]. Once a task was estimated to require, say, 20 KLOCs, that put a cap on how much money the developer could make, and it became a target to hit.
Free from external pressure, do programmers aim to keep their programs short? Some argue in favor of slowing down, which is related to program length since time is a limited resource. For example, Poul-Henning Kamp, the author of the web caching program Varnish, estimates that he wrote what he intended to be his highest quality program — ever
at the breakneck speed of 5 LOCs per hour [18]. If that sounds slow, the equivalent estimate in the previously mentioned Mythical Man-Month is much slower: 10 LOCs per programmer-day.⁶ Kamp adds that for life-and-death software, where correctness is paramount, such as that developed for human space flight missions, the same estimate drops to one LOC per programmer-day. Sure such a coding speed must discourage code bloat (but see Sec. 1.5 for bloated space software).
It isn’t only rocket science. Matt Lacey, a mobile developer and consultant, in a post titled You’ve only added two lines — why did that take two days!
lists plenty of reasons why, at times, development may slow down to such a crawl [19]. He reports about fixing a bug, first understanding it in detail, from which subsystems are affected to how to reproduce it. Then, unsatisfied with just making the issue disappear, Lacey endeavors to find its root cause, if the problem may represent a class of related ones and how to fix it with a high-quality solution that won’t break his program elsewhere. Finally, he spends some more time preventing this or similar problems from happening in the future. Two days to perform all these tasks, even if the solution is only two lines, don’t seem like a waste of time.
Everyone in the software industry knows that slowing down is the opposite of how it works. There are entire methodologies aimed at creating arbitrary deadlines and fostering a fictional sense of emergency. Limits on size, on the other hand, are rarely, if ever, encountered. No boss ever told my teammates or me: you could have done this with less code,
or let’s try to keep it under 1000 LOCs.
However, I found a counter-example (see Dwm in Sec. 1.2.11 for an additional one). An anonymous Quora user asks if he should fire someone who unnecessarily wrote 500 lines of code
without context [20]. We don’t know what these lines were supposed to achieve or if there was a pattern of verbosity in this engineer’s work. Rejecting the rush to summary judgment, another user replies:
As a programmer, I’ve written many, many lines of unnecessary code. Why? Because sometimes you have to write 500 unnecessary lines of code to get to the 50 absolutely necessary lines of code.
(for code deletion, see Sec. 1.2.2).
Going back to Kamp and his Varnish, he further writes:
Back when I was a kid I could write 1000 lines in a single sleep-deprived session across midnight, but it didn’t take that long before I discovered that I had to throw out most of it once I woke up again.
I was 40 years old when I started Varnish and I had 22 years of professional experience,