@DanLebrero.

software, simply

Book notes: The Ascetic Programmer

Book notes on "The Ascetic Programmer: How asceticism benefits programming, science, and the arts" by Antonio Piccolboni

These are my notes on The Ascetic Programmer: How asceticism benefits programming, science, and the arts by Antonio Piccolboni.

A case to “do more with less” (conciseness) and “less is more” (frugality), without forgetting that is not that easy:

I would have written a shorter letter, but I did not have the time Blaise Pascal

Key Insights

  • Lines of code are a valuable measure of program complexity.

    If we wish to count lines of code, we should not regard them as “lines produced” but as “lines spent” Dijkstra
  • The difference between a compressed program and a concise one is that the latter is human-intelligible.
  • I considered what was written eons ago sacred.
  • More general functions create indirect dependencies between parts of a program and, thus, more of the entanglement.
  • If keeping two programs completely independent is paramount, an option is duplicating.
  • Often code can grow as an accumulation of special cases until we realize a general rule that can replace them and covers additional ones as a bonus.
  • If a long variable name works as documentation, is having to read it every time you run into it a good idea?
  • Any non-trivial program should define the concepts relevant to the task on hand and implement data structures and operations to represent and manipulate those concepts, and this extends the language.
  • Languages are defined by what they allow and what they prevent.
  • Languages that forbid many constructs preclude them from expressing valid computations, hence developers will have to use longer programs to define equivalent computations.
  • A simpler language should also be less powerful and therefore require more code for the same tasks:
    • However, Lisp sidesteps this trade-off to some degree.
  • Code generation isn’t a suitable replacement for abstraction.
  • Making many more assumptions about what you’re trying to do allows to be much more concise, at some cost of generality.
  • Developers give up on reading source code beyond what is strictly necessary to add their contributions.
  • Machine Learning: the complexity just morphed, but it is learned from data rather than hand-coded.
  • Short programs are easier to test.
  • Maintaining simplicity in the face of supporting new features requires a constant, organized, resourced effort.
  • Working on reducing complexity is generally considered second-class work and not career-boosting.
  • You can’t become a superstar if you have to pick the next entry in a so-called backlog.
  • Lawrence Kesteloot: Every line of code you write is a potential bug.
  • Two approaches in API design:
    1. Minimal.
    2. Humane: strives to support as many reasonable use cases as possible.
    • A developer writing against a minimal API will have to write more code but learn less than against a humane one.
  • Bad code begets bad code.
  • Let the rot spread a little and meet your deadline.
  • Development these days is fragmented into long series of self-inflicted emergencies.
  • Deep Learning: Sun and co-authors concluded that “performance increases logarithmically based on volume of training data”.
  • The Parsimony Principle: plurality should not be posited without necessity.
  • Shorter sentences are easier to read and understand.
  • Everything that is not useful in the picture is, it follows, harmful.
  • Not only can most things wait, most things should. You either can’t stop thinking about them, or those thoughts fade away. Let time do some work for you.
    • Time acts as a filter.

TOC

Introduction

  • Asceticism in programming comes in two flavors, roughly described by the slogans “do more with less” (conciseness) and “less is more” (frugality).
  • Don’t expect a grand theory, but rather a series of interconnected anecdotes and expert opinions, interspersed with the occasional theorem and research paper.

Chapter 1 - Computing

1.1 - Metrics

  • Lines of code are a valuable measure of program complexity.

If we wish to count lines of code, we should not regard them as “lines produced” but as “lines spent” Dijkstra

  • Alternatives:
    • Counting tokens.
    • Cyclomatic complexity:
      • Correlates well with program size.
  • Properties that predict program size:
    • Number of bugs (Capers Jones).
    • Probability of project failure.

1.2 - Concise Software

  • There are entire methodologies aimed at creating arbitrary deadlines and fostering a fictional sense of emergency.
    • Limits on size are rarely, if ever, encountered.
  • Sometimes you have to write 500 unnecessary lines of code to get to the 50 absolutely necessary lines of code.
  • The difference between a compressed program and a concise one is that the latter is human-intelligible.
  • A line of code’s further costs are in the future and harder to estimate.
    • We hardly ever tried to estimate those delayed costs. Therefore, the incentives to delete are weaker.
  • Nobody taught me how to delete code.
    • I considered what was written eons ago sacred.
  • Where does the quasi-repetition stop, and where does the “vaguely related code” start?
  • Even when identification is easy, there may not be time to eliminate repetition because of the work required.
    • However, writing a ticket to mark some duplication we left unattended generally isn’t a career boosting move, and those tickets never get taken care of regardless.
  • More general functions create indirect dependencies between parts of a program and, thus, more of the entanglement.
  • If keeping two programs completely independent is paramount, an option is duplicating.
  • Conciseness and modularity are two sides of coping with size.
  • Often code can grow as an accumulation of special cases until we realize a general rule that can replace them and covers additional ones as a bonus.
  • More code often means less flexibility and functionality.
  • Different abstraction techniques are touted for their potential to reduce coupling and not for any conciseness advantage.
  • Bill Atkinson used to report a negative number of lines contributed, including a “-2000” in the week he had rewritten some routines in QuickDraw to be six times faster.
  • If a long variable name works as documentation, is having to read it every time you run into it a good idea?
  • Who enjoys reading documentation?
  • Joshua Bloch: APIs should be self-documenting.
  • Any non-trivial program should define the concepts relevant to the task on hand and implement data structures and operations to represent and manipulate those concepts, and this extends the language.
  • Languages are defined by what they allow and what they prevent.
  • Paul Graham: Macros can do two things that functions can’t: hey can control (or prevent) the evaluation of their arguments, and they are expanded right into the calling context.
  • Guy Steele: It’s really hard to make a language that’s great at everything, in part just because there are only so many concise notations to go around. There’s this Huffman encoding problem.
  • Languages that forbid many constructs preclude them from expressing valid computations, hence developers will have to use longer programs to define equivalent computations.
  • A language with many ways to express the same computation will lead to more verbose programs.
  • Defining more common computations with shorter programs and accepting some verbosity for less common ones could be a good compromise but implies different languages tailored for different domains.
  • A simpler language should also be less powerful and therefore require more code for the same tasks:
    • However, Lisp sidesteps this trade-off to some degree.
  • Verbose code is something to skim in long, painful, lonely sessions.
  • Users love these more concise forms, but having multiple evaluation rules makes programs harder to understand and hinders their parametrization and generalization.
  • Code generation isn’t a suitable replacement for abstraction.
  • POJO-aggrieved Java programmers.
  • No API designer can escape the compromise between the complexity of an API, its power, and the complexity of user code.
  • Edward Tufte:
    • Data-ink ratio, the ratio of ink spent to display data vs the total amount used in a chart, and recommended maximizing it.
    • Data density: the number of data points per unit of area.
    • Display lots of data with just enough ink, minimize and de-emphasize everything that isn’t data.
  • Grammar of graphics by Leland Wilkinson.
  • Making many more assumptions about what you’re trying to do allows to be much more concise, at some cost of generality.
  • This lack of modularity is sometimes positively spun as coming “batteries included”, meaning that any integration challenges are taken care of.
  • Two orders of magnitude fewer lines of code mean a lot less attack surface.
  • A much smaller codebase also means code that is more likely to work the way it is supposed to.
  • Developers give up on reading source code beyond what is strictly necessary to add their contributions.
  • If you need one KLOC to fix a bug and can produce it within the available time, so be it. The maintenance bill doesn’t reach the original author.
  • Machine Learning: the complexity just morphed, but it is learned from data rather than hand-coded.
  • Short programs are easier to test.
  • GolfScript: unlike most code blocks in this book, we will not try to understand this one.
  • What is valid for programs continues to be so at the level of system architecture.
  • Heroku: Only by concertedly building a minimal stack that is stable and nearly operable can we maximize our ability to push forward with new products and ideas.
  • Maintaining simplicity in the face of supporting new features requires a constant, organized, resourced effort.
  • Minimalism is a necessary condition for the evolution of the product, not a “nice to have”.
  • If the pressure to build new features engenders complexity, we can work to reduce it after the fact.
  • The progression toward complexity is reversible.
  • Working on reducing complexity is generally considered second-class work and not career-boosting.

1.3 - Frugal Software

  • It isn’t so much the code they write, but they decide to work on.
  • You can’t become a superstar if you have to pick the next entry in a so-called backlog.
  • Atwood: If you can’t get away with no code, next best thing is to start with brevity.
  • Lawrence Kesteloot: Every line of code you write is a potential bug.
  • Atwood: visible logging code is clutter, it actively obscures the code that is doing the real work in the application. We have since removed all logging from Stack Overflow, relying exclusively on exception logging. Honestly, I don’t miss it at all.
  • Filter feature requests before queuing them.
  • Two approaches in API design:
    1. Minimal.
    2. Humane: strives to support as many reasonable use cases as possible.
    • A developer writing against a minimal API will have to write more code but learn less than against a humane one.
  • Josue Block:
    • API should be as small as possible, but not smaller.
    • The two requirements seem to almost directly contradict each other.
  • What is more frugal than an API with a single entry that does it all?
  • “Negative feature list”: a list of features that it does not offer.
  • Mythical Man-Month: it is better to have a system omit certain anomalous features and improvements, but to reflect one set of design ideas, than to have one that contains many good but independent and uncoordinated ideas.

1.4 - Hardware

  • The missing keyboard of the iPhone.
  • RISC architecture.

1.5 - Verbosity and Bloatware

  • Hoare: Wouldn’t you be delighted if your Fairy Godmother offered to wave her wand over your program to remove all its errors and only made the condition that you should write out and key in your whole program three times!
  • After a bug was identified while in orbit, Boeing decided to review the whole code base for the project.
    • Unfortunately, there were already a million LOC to review.
  • Maciej Ceglowski: two steps secret to improve the performance of any website:
    1. Make sure that the most important elements of teh page download and render first.
    2. Stop there. You don’t need all that other crap.

      There are two ways of constructing a software design: one way is to make it so simple that there are obviously no deficiencies and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult. Hoare
  • SQL is not a small language. PostgreSQL implementation contains 469 keywords. Just part 2 (out of 14) of the SQL:2016 standard has 1732 pages.
  • If the DRY principle guides Python and Ruby, Java should be considered a WET language: Write Explicitly Tenfold.
  • Bad code begets bad code.
  • Let the rot spread a little and meet your deadline.
  • Development these days is fragmented into long series of self-inflicted emergencies.

1.6 - Code Considered Harmful

  • Go To Statement.
  • Ifs: Anti-If Manifesto.
  • Class inheritance.
  • You have never been paid to write code. Indeed, code is a nasty byproduct of being a sw dev.

Chapter 2 - Science and Engineering

2.1 - Epistemology, Statistics and Machine Learning

  • The Parsimony Principle:
    • Plurality should not be posited without necessity.
    • Aristotle: we may assume the superiority, other things being equal, of the demonstration which derives from fewer postulates or hypotheses.
  • Bayesian statistics inadequate for science, as conclusions are too dependent on the choice of prior - that is why its dominant variant is called subjective Bayesianism.
  • Deep Learning: Sun and co-authors concluded that “performance increases logarithmically based on volume of training data”.
    • An additive improvement requires order-of-magnitude larger datasets and models and two orders of magnitude more computing power.
    • Convolutional nets and deep nets, which, for the same size, show better performance.

2.3 - Engineering and Design

Perfection is finally attained not when there is no longer anything to add, but when there is no longer anything to take away Antonie de Saint-Exupery

Chapter 3 - Literature, Visual Arts and More

3.1 - Speaking and Writing

  • Shorter sentences are easier to read and understand.
  • With strict paper length limits: Many a choice turn of phrase and illustrative simile had to be sacrificed to precision, flow and brevity.

I would have written a shorter letter, but I did not have the time Blaise Pascal

  • Plausibly extending a text was easier for this AI system than summarizing it.
  • Lawyered-up companies try to gain the upper end on smaller ones or private citizens by overwhelming them with long and complex contracts.

3.2 - Visual Arts

  • Everything that is not useful in the picture is, it follows, harmful.

3.4 - Management

  • Not only can most things wait, most things should. You either can’t stop thinking about them, or those thoughts fade away. Let time do some work for you.
  • Time acts as a filter.

Did you enjoy it? or share!

Tagged in : book notes