If you open code every function that is used once, you lose functional decomposition, which can hurt readability.
If we have a linear process with a large number of steps, it can help to group them hierarchically via functions, just as a play is divided into acts and scenes.
Functional decomposition was once taught as an important technique in program design (related to the "top down" approach). I believe it still remains important.
Here is an example of a function called only once: a module initialization function. If we take the advice literally, we shouldn't have an init function that calls numerous other init functions one by one. Since they are called once, we should pull them all into that init function. Well, what is that going to do to the cohesion and coupling.
Ironic that I find functions with multiple return statements to be much less readable than declaring a return variable at the top named for what the function will be returning, usually with the default value that the function would return, setting it in multiple points throughout the function, and then returning it once at the end.
I never got around to formally describe it, but I had this idea how we could formalize these concepts like readability or programming effort.
We can think of each function (those make up our program) as a channel in information theory - input values are input symbols and output values are output symbols. Our "not understanding" of what the function does is modeled as the noisiness of the channel, so the higher the understanding, the higher the information gain between inputs and outputs of the function.
But I never got around to compose the channels and their associated entropies, which would be the goal of this formalization.
Nice thread! I really like "How do I use whitespace to communicate that different items belong to the same idea?". It's like the 'non-verbal communication' of written comms hah!
Instead of encouraging developer to optimize beyond what their programming language expose, shouldn't we change our software model to include space?
A simple example would be cellular automata (not necessarily "automata") which make clear use of space. But for this to happen, we would need new CPU design that doesn't only attempt to become a C interpreter.
Every single sentiment expressed in this article has been expressed before. I agree with all of it, but there really isn't anything original here. This is the received wisdom on readability.
I am sure when I scroll down there will be people being upvoted for such profound insights as 'readability is good'. checks yep.
I broadly agree with all the points here. I guess the author reasons about code the same way I do, which is interesting. The exception is the bit about vertical space - we effectively have infinite vertical space and limited horizontal space, I think we should trade them off accordingly.
I especially agree with the idea around "code locality". I find the easiest code to deal with are those that doesn't require me to understand how everything works, to understand how one thing work.
>>> keep your modules (functions, classes, components) deep: small interfaces packing significant functionality. The idea here is to give users of the module the biggest benefit for the least learning.
Great! Now I have to travel through 100 small classes spread across 1000 files in a 10000 nodes directory tree in order to understand 1 high level class. Great readability improvement!
Maybe we interpreted the article differently, but I understood this point as favouring a few "big" classes/interfaces/functions, as opposed to a lot of "small" classes.
You'll see down below a case for inlining functions that are only used once, and the quote "As for one liners that are called only once, just inline them. The small functions guy can take a hike."
Loup Valliant's main project is monocypher. It is typically distributed as one C file and one H file. It provides a relatively small interface by being well-scoped and well-designed.
Nowhere does he say that you should have 100 small classes across 1000 files. He says the opposite: your modules should have a lot of functionality but a small interface.
Why the focus on vertical screen space? I find I am rarely looking at the top and bottom of my viewport at the same time.
The only advantage I see is being able to tile more files onto my screen.
Perhaps I am too used to having to scroll, and never had the joy of not needing to at all, but this is the weirdest part of the article to me.
I agree with the author. It's subtle but it's about signal to noise. A screen full of whitespace has no signal and it's an artificial impediment to the knowledge transfer from screen to brain.
Unfortunately auto-formatting is a better for other reasons so we don't have much wiggle room here but left alone I adopt the authors style
> It's subtle but it's about signal to noise. A screen full of whitespace has no signal and it's an artificial impediment to the knowledge transfer from screen to brain.
Not always.
I'm a developer that likes a lot of whitespace. My style is exactly the one the author hates.
I struggle with full walls of text. As in, my brain just simply cannot handle whitespace-free, or nearly whitespace-free, code.
Whitespace makes it easier for me to read, exactly the opposite of the author.
And that's okay. But it's certainly not an impediment of knowledge transfer to my brain.
I think we need to liberate ourselves from the "folders of files of text" way of coding.
We really shouldn't ever have to think about where to put things.
Each function should be stored in its own text file.
Then these files are indexed in a database.
Then they can be tagged: manually or by parsing its AST / types.
Then using the tags you can organize the code any way you want.
Better yet, maintain a dependency graph to see all callers and callees, and view code like that.
Even better yet, instrument your code, and at runtime let the stack trace determine the organization of your code in your editor.
Some problems I can see though is that humans seem to like things to belong in one place. That's why folders win over tags usually. But...your existing folder/file structure of code is simply one "view" from the database. Some people use module names, some people use file types (components, helpers, etc.)
Existing IDE's and text editors (and runtimes) are holding us back!
There were multiple attempts over the decades to move the code from files to other organization structure, and in my opinion they all made matters worse.
It's so much easier to just see a directory structure which reflects the module structure of your project and be able to quickly open any file in any tool and not just in the IDE of your chosen programming language.
Also prior: Matlab. What a horrid system that was.
You describe solutions for specific problems a programmer has from time to time (and some implementations that aren't relevant to anything), but we don't think like that. Not about programming, nor about writing prose or conducting experiments. We don't need arbitrary flexibility, but support that matches our cognitive make-up. Many memorization techniques rely on location, probably because we're hard-wired for that. So folder structures probably work better than tags.
We forget tags. I've seen it happen. Our system supports tags in certain contexts, and now the same tag is there in multiple variations, just because people couldn't remember it was there or what is was called, and there is only a handful of them. Now imagine a system that has tens of thousands of tags...
IDE's aren't allowing us to use our full potential, but the path towards that is not logical and straightforward.
Nested tags for me, with tag tree viewable as a 'folder' structure in a side panel. Solves the problems "Which [one & only one] folder do I put this in?", "Which folder _did_ I put that in?!", and "Why are we allowing x copies of this in n folders, each with different dates/contents?".
Works for me with email, too.
Mutually-exclusive folders for-the-lose. Wellll…for my usage, anyway.
The definition of readability changes with one’s experience. With time you really want something with less redirections and something which is easy to change like globally.
except there is no optimization function which produces local maxima of unreadability. precisely the opposite with readability. i.e. there is no unreadability cult in the real world. you're just using it as a rhetorical device. in fact, there is no maximum level of unreadability. what's more unreadable than 50 exabytes of brainfuck? 51 exabytes of brainfuck
If we have a linear process with a large number of steps, it can help to group them hierarchically via functions, just as a play is divided into acts and scenes.
Functional decomposition was once taught as an important technique in program design (related to the "top down" approach). I believe it still remains important.
Here is an example of a function called only once: a module initialization function. If we take the advice literally, we shouldn't have an init function that calls numerous other init functions one by one. Since they are called once, we should pull them all into that init function. Well, what is that going to do to the cohesion and coupling.