Not just long-lived projects. Working on bespoke, internal systems means you’re never truly done. And what you’ve done a month ago may not be what’s wanted now.
The reason why good code is code that is easy to read, is because products evolve, and so does the code.
Suddenly the taxonomy of that enum starts to shift, and the name that was perfect yesterday does not make sense tomorrow.
These changes happen gradually and a basic acceptance of the code base not being on par with the product understanding is necessary in order to have any kind of velocity on not only spend time refactoring.
I can write a bubble sort instead of quicksort and that code will be bad.
Maybe you can do the same thing with privacy policies. Most complicated privacy policies are bad, so they make them hard to read so that people do NOT understand them and give up.
But you could have a privacy policy that is bad and easy to read. "We can do anything".
I think good code is primarily easy to read. And I think it should not attract attention through bad behavior, so it should additionally not come under scrutiny for that.
Of course your code should live up to requirements and be correct, for it to be good - The requirements can also be performance requirements.
If you have a list of maximally 10 elements that needs to be sorted and you opt for quicksort over bubble sort in a context where bubble sorts time/space guarantees perfectly solved the requirements, well, then you absolutely wrote bad code.
This is what a more senior developer understands, where a junior would jump in and write worse code.
I don’t think you read the whole article. I had the same thought as you from the headline, but they gone on to state that good code is so easy to read when you need to make changes that you don’t have to go through it multiple times to make the required changes.
However, the other part of that answer was to make the code immensely readable, because we read more code than we write unless we’re incredibly junior or comically superhuman.
I did a consulting gig at Allstate around the time of Y2K. I chatted with a senior architect who had been with the company for over 20 years. He noted that there were such a vast array of programs and systems in place, some of which had been running for at least 40 years. I wonder if any of that code had been read, good or bad, for decades. And I am willing to bet that the source code for some of it was lost.
This of course led to no small level of anxiety during the run up to Y2K.
As a side note, while I was there, the dictum came down that there was to be no more assembler programming to be done.
The long-lived projects I've seen have some code that mostly works that doesn't have any tests and is hard to grok. Nobody touches it because 1) any change might break something unexpected and 2) if you touch it, you might end up owning it.
I wouldn't call that good code but it's often too good to spend time replacing.
There's a class of code where you never need to read it because it's effect is well understood and it does it without problems. It has the right level of abstraction to be useful in multiple places and not specific to a singular case. It's not going to be top level code, but it's a building block you know you can rely on.
This is something I think functional styles of programming lead more naturally towards than OO or procedural. It's far easier to separate concerns when you can pass around like bundles of functionality (i e. first order functions). Also it really helps when you are used to writing code with no dependency except what is passed in, and not effect except what is returned. Then thhen you're sure that the code is not leaky in it's abstraction.
You can do it in other paradigms, but it's it's not where the language naturally leads you. OO has retained state as a key foundation of it's philosophy. Procedural code tends to mix up the how something is done and the what is being done. (e.g. the iteration through a data structure, with the definition of what is being searched for).
Code that does what it should is rarely read. Until you need to change it.
And it may not be changing due to it being incorrect. If an attendant system gets replaced, you may have to change all the other systems it has touched. Business requirements may have changed. Stakeholders may have changed.
There are plenty of reasons for code to change beyond there being a bug.
I don’t think you read the whole article. I had the same thought as you from the headline, but they gone on to state that good code is so easy to read when you need to make changes that you don’t have to go through it multiple times to make the required changes.
Recently I was going through the codebase that our company has spent the last 7 years developing, trying to find examples of code we reuse a lot. This turned out to be very unintuitive: the functions we actually reused the most had practically fallen below the threshold of conscious thought. They almost "just work", so I hadn't realized how much I'd been using them.
What GP is referring to isn't literate programming. It's more like doc comments moved to the side instead of inline. Not sure it ever had its own name.
That is a bold statement. I'm 100 convinced that it's based on your code architecture.
Good code in my systems are ones that don't need to be touched or read very often, and the fluid/unknowns parts are decoupled elsewhere.
Sometimes business requirements issue, Sometimes difficult technical problem.
That doesn't make sense . A good quality code is ready a lot, internally we reference good code as example for new employees and it is also being read, reused again and again. The author looks like just non-engineer manager.
The bad code is read a few times and refactor as soon as we get a chance.
This feels borderline tautological: good code is good because it’s good.
Good or bad, you’re going to end up needing to add new features to this code. Or someone misunderstood an input or output to/from this code and you’ll need to read through it to understand how it’s implicated in a bug.
I think ‘good code is easy to read’ is pretty profound: DRY code with the right abstraction is easy to read. DRY code with the wrong abstraction is hard to read.
It's because they are using "read" to mean "understood/interpreted" in the sense that the reader is executing the program in their head.
In their last paragraph:
It should be so well-structured and named that its purpose and functionality are immediately apparent [when read]. This minimizes the need for others to read through **and interpret** the code, allowing them to use it more effectively.
(emphasis added)
So the point is really: "Good code should be so apparent that when the reader reads it they do not have to be a human interpreter."
Have you ever had the need to read the source code of a tool because it doesn't behave the way it should, and its help and documentation prescribes?
I have been there a couple of times, and how some stuff is handled in these codebases were sad. Sloppy, assumption ridden, or pure, inelegant and fragile hacks.
Even if you're reading a code to modify it, good code is easier to follow and read (point of the junior developer), and as a result, you touch less and less parts of the code to develop it even further.
So yes, Good code is rarely read, or "read less, and in more niche cases".
> Have you ever had the need to read the source code of a tool because it doesn't behave the way it should, and its help and documentation prescribes?
I believe this varies wildly programmer to programmer. I'm often diving into code and reading that when debugging. I've done this with many code bases. It may be debatable if any of them are "good".
There’s a thin sliver of things I have read through that I considered good (even great) that were high effort to read. Things like STL, boost (in parts), numpy… huh. Come to think of it, all things that use C++ templates… and I’m a big fan of templates…
The thing they all have in common is that they are/were overwhelmingly useful to people who didn’t need to go digging inside of them to use or understand them. These are bodies of code for which the behavioral and algorithmic properties were documented thoroughly, bodies of code that generalize to wide ranges of applications.
Still, we’re not all writing STL core classes every day. Sure. Write code so good it doesn’t need to be read. Write code so good that people want to read it. And write code that, when read, is welcoming, comprehensible, and considerate of others or yourself in the future.
Saying the first thing shouldn’t mean unsaying the other things… Something our author may learn over time.
There’s probably a time axis that comes into play, at least for a large number of projects. Bad code which is immediately useful, even indispensable, can decline in utility fairly sharply the parameters which determine its usefulness change faster than it can be adapted to meet those needs or goals.
There's definitely a time axis that comes into play. I'd say that all tech debt should be (but probably isn't always) in that top left quadrant. Like they say, good/fast/cheap - pick two (if you're lucky).
Adding features to a code means it was incomplete. Misunderstanding input/output usually means it is poorly documented or lacked a good API. A good API works at the surface (in/out) and not in the volume.
Really good code solves a problem completely. I have worked with such code and yes almost nobody ever goes into this code (and makes changes).
Missing feature implies an error at the Requirements level.
This does not impact readability or the idea of "good code" in my opinion.
You could have an application that is missing features which still contains examples of "good code". Learning about "good code" by reading the source code of this application won't really give any direct hints of missing features...the granularity is different.
What about changing features? E.g. a feature has to change 2 years down the line because certain laws are passed and this changes how the business logic should behave.
> Adding features to a code means it was incomplete
In practice this isn't true. The code may have been perfect and complete according to the business requirements of 1 month ago. But the business requirements of 1 month ago and today are often completely different.
I'm not familiar with many systems or backend software that are still actively used, multiple decades old, and not still receiving updates. If it's not even a decade old, it's not old enough to say requirements won't change.
Well, what's wrong with code being incomplete at some point of time?
Is it not waterfall enough? Is it too much learning from customers? Is it too small PRs of duration less than 1-6 months? Is it not enough premature optimization?
You are being a pedant. "Good" can describe anything that meets high standards or performs well in its context, e.g. as 'good game' or 'good weather.'
Your excessive focus on minor linguistic nuances is counterproductive. It's more important to understand the overall message than to get bogged down by trivialities, which everyone here seems to be able to do — except you.
Moreover, by repeatedly correcting language, you give off an 'I'm smarter than you' vibe, which isn't conducive to a productive conversation.
In the real world, code is read often and for many reasons. The main ones I can think of are:
1) To understand the system without necessarily wanting to change anything. This is common with new employees or anyone wanting to learn more.
2) The system often needs tweaks, bug fixes or new features. Each of these normally requires that the code in question is read by several people several times.
3) The architecture is normally not perfectly modular, so changing one part often requires one to understand and tweak the neighbouring parts of the system, too.
I agree with the first one but the other 2 are basically what the author is speaking out against.
Some change/rework is unavoidable, but if code is good, then it should be relatively rare. Modularity isn't sufficient for code to be good. It's difficult to have truly 'loose coupling' without 'high cohesion'; each module should have distinct and well-defined responsibilities. My test for high cohesion is the question: "Is this module easy to describe to a user with limited technical abilities?"
If modules are both loosely coupled and high cohesion, you'll find that you rarely need to change the code, or won't need to change it much, even after substantial refactorings. This is because such modules provide a near-optimal level of abstraction. Interfaces of such modules tend to be simple (a relatively small number of simple parameters, e.g. primitive types); this is what makes the modules easy to substitute.
For example, consider a database client library, the most powerful method is for running queries against the database; this method typically requires only a single argument as a query; a string, though it will also typically support an object/map as second argument to substitute values into the query. How often do you need to change the database client library because of a refactoring? You could literally pivot your entire business model from a social media app to an enterprise CRM and you wouldn't have to change a single line of code in your database client. You might change how you use your database client within your back end logic, but you won't have to change the implementation of the client itself.
There are many less extreme examples though where a module can handle very significant changes to your business without having to be modified at all. Maybe your business pivoted from being a professional/business social media app to being focused on friends and family; it might change some aspects like friend discovery, algorithm recommendations, banning, etc... But you should be able to keep most of your existing code if your code is good quality.
My definition of good code is "Code that is resistant to change when faced with requirement changes." Though there is a lot of overlap with "Code that is rarely read."
That's kinda unrealistic.
It's okay to expect that if you change the requirements for A, there should be no changes in the code of B.
It's not okay to expect that if you change the requirements for B, then there should be no changes in the code of B.
For essentially all my projects, I end up having most of my business logic at the trunk of the project source. The leaf nodes are the most general purpose modules (e.g. database clients, utility functions), the branches are still relatively generic but closer to the business domain. The trunk (e.g. entry point of my program) changes very frequently and is directly related to the business domain. The branches change rarely and the leaves almost never change. The leaves are usually third-party modules. For the leaves, I will typically swap them out if they cease to meet my requirements. I almost never refactor those. For the branches, I sometimes have to refactor 1 or 2 of them at most. I can't recall ever doing a refactoring which touched on many branches at the same time.
Most of my refactoring only affect the trunk of the code. I try to have all the business logic for a program or service represented in a single file. If the file gets too big, I create new modules 'branches' and move the most generic logic to those branches. My top level file tells the full story of the program/service. Anyone can open that file and, based on the module names and method names that are being called, they can figure out what happens and when. All the events, endpoints, logging, access control and other externally observable behavior is wired together in that file.
If the file has been abstracted to the maximum amount possible (with all generic functionality moved to branch modules) and it's still too big, it may be time to switch to a micro-service architecture. Break up the trunk into 2 parts and we basically end up with 2 apps/services. This rarely happens though. With the right level of abstraction, you can fit a massive amount of user functionality in a single main file. By the time the main file's code becomes overwhelming, the application's UX becomes overwhelming for the end user too... Time to split up into multiple apps.
Think of how complicated UX would be if a video-editing software tried to support image editing as well (e.g. to make fancy title screens or UI overlays). It would become too much for the user. Just make two different applications; one for video editing, one of the image editing. You can integrate them in a seamless way, but they should be different apps.
This long comment doesn't contradict my point because "The trunk ... changes very frequently". Requirements change, and thus, code changes. There is nothing you can do about it. It's cool when everything is modularized enough that you never need to change some parts of the code. But it doesn't mean those parts of the code are better than code that changes often.
Now, if you think a little more about this, there is a huge risk that some of your leaf code should be in a library. For example, SQL builders, ORMs, UI kits, markdown formatters, etc. When it's a publicly available package used by many devs around the world, the code in it often changes. The reason why your leaf code doesn't change is that you don't have a proper investment return for small changes because you are a single user. Code in libraries handles more useful use cases, it handles more edge cases, it provides better API, and it contains fewer bugs than code in leaf nodes. And all that's while code in libraries is constantly changed. And code in leaf nodes... I would say that the proper description for it is "used, but dead".
i offer the entirety of sqlite as a counter-example. Based on that project's forum traffic and my participation within that project, i estimate that there are hundreds, if not thousands, of people who actively read that project's C code. That doesn't make it "bad code," that just makes it code which people want to understand (which, in turn, requires reading).
So code that gets read a lot isn't good code, got it.
This means that core algorithm bundles in business applications that necessarily carry a lot of complexity and need lots of careful maintenance over the decades can never reach the status of good code.
On the other hand, the twenty lines of bash I use to hook mpv into SomaFM streams are very good code.
There is an entire discipline on the idea that the effort to make code easily read/understood will result in source code which is easier to maintain and write:
The person you interviewed gave a better definition. “Code that is easy to read” is often a good code. Code that is rarely read only exists in the manager’s imagination.
This is only (theoretically) true in the sense that if you build the perfect abstraction, you should not have to think too often about it.
Building good abstractions requires:
1. skill that is in relative terms rare in the profession;
2. enough experience with the problem domain that the abstraction provides the perfect balance between ease-of-use and flexibility as the context changes;
3. a dedicated individual or a small team who nurtures and gatekeeps the evolution of the abstraction obsessively.
For the other 99% of real world cases, the best you can do is try your best to build decent, not-too-leaky abstractions for the problem as you face it today, and the underlying code better be readable because you'll need to maintain it constantly, as will all kinds of other people in varying states of cluelessness.
I have found that what developers consider easy to read varies. So unless you have a lead developer with the political clout to enforce a standard you will end up with a code base with a very inconsistent style.
Unfortunately in the corporate world the people with the required clout rarely want to spend the time necessary to enforce a style.
The best code that I've worked with is always code that is easy to modify. Code that I read rarely could be anything; I'm really oblivious to how good or bad it is until I need to modify it.
As someone who has professionally read code, I don’t think a lot of code gets read very often. It could be also that good code doesn’t take long to read.
Also about the claim that that 10x programmers are fantasy, I call your attention to Fabrice Bellard https://bellard.org/. I have also worked with one or two in my decades of programming career. I probably peak out at somewhere around 0.75.
Those who are disagreeing with the author seem to not realize that he's just engaging in a bit of navel-gazing wordplay. Sort of like when people say "good programmers should be lazy". What they really mean is that good programmers should think ahead and craft their code with an eye minimizing future modifications.
Similarly, I think the author is simply saying that well written, easy to read, easy to understand code shouldn't have to be re-read multiple times by the same person. Which is good. The inverse would be that difficult to understand code would have to be read, re-read and studied deeply to actually grok. And thus read a lot. Which is bad.
Basically he's saying that if the API is great you rarely need to read the implementation. To which: sure, in some blessed cases where the API was great to start with and nothing changed so you don't need to change the API or the implementation.
I think the critics (myself included) perfectly understood that point.
> What they really mean is that good programmers should think ahead and craft their code with an eye minimizing future modifications.
The critique is exactly that this can not happen in real world projects because you can only speculate what requirements for the code base is down the road.
To counter this I usually apply two princinples:
1. Occam's razor - implement the simplest solution
2. Write code that is readable and understandable, so it is easier to change the code with the requirements.
The last being completely opposite to what the author of the article thinks.
The worst thing I can think of is somebody needlessly DRYing up a code base prematurely - this is in my opinion a junior behavior.
Code quality and how often it is read are mostly orthogonal.
You can have an stinky old piece of legacy software that no one ever reads because that system is deprecated and slowly getting phased out, and we can live with it in the meanwhile.
You can have the most elegant a beautiful piece of code that gets read a lot, because it is in the critical path of a very active and rapidly evolving system, and people need to reference, modify and extend it a lot.
However there is a crucial way where OP is wrong: there is a pull and push between code quality and how often it is read. If your code is a legacy big ball of mud, people will be less inclined to touch it, probably going to the extend of rewriting the whole thing. On the other hand when code is well written, people are less afraid of digging into it.
Lastly, even if OP thesis was correct, I don't know think it would change anything. Strive to write the best code you can within reasonable constraints, independently of how much other will read it (which in my experience is almost always underestimated).
Hm, I would agree more with the overall headline and conclusion if it was about time spent reading code.
The best code and code bases allow you to quickly understand how they are structured and don't necessarily hold subtle, nasty surprises - or at least make it obvious if something is a nasty, subtle surprise. Those code bases tend to be a quick read.
The bad functions and code bases require you to carefully consider every little aspect of every single line in detail. And I don't just mean "read every line", I mean "Dissect lines based upon language specs, and also keep in mind this is interacting with 5 different other parts of the code base. Or not. Who knows?" In such code bases, just figuring out what something does tends to be a slog.
114 comments
[ 2.9 ms ] story [ 210 ms ] threadThe reason why good code is code that is easy to read, is because products evolve, and so does the code.
Suddenly the taxonomy of that enum starts to shift, and the name that was perfect yesterday does not make sense tomorrow.
These changes happen gradually and a basic acceptance of the code base not being on par with the product understanding is necessary in order to have any kind of velocity on not only spend time refactoring.
"good code is easy to read" - that does not work.
I can write a bubble sort instead of quicksort and that code will be bad.
Maybe you can do the same thing with privacy policies. Most complicated privacy policies are bad, so they make them hard to read so that people do NOT understand them and give up.
But you could have a privacy policy that is bad and easy to read. "We can do anything".
I think good code is primarily easy to read. And I think it should not attract attention through bad behavior, so it should additionally not come under scrutiny for that.
If you have a list of maximally 10 elements that needs to be sorted and you opt for quicksort over bubble sort in a context where bubble sorts time/space guarantees perfectly solved the requirements, well, then you absolutely wrote bad code.
This is what a more senior developer understands, where a junior would jump in and write worse code.
And, honestly, I think that somewhat holds. That said, as an aim, writing readable code that doesn’t need to be read to be used is a good one.
I wrote as much in a quora response almost a decade ago to the question “how does one become a great coder” ( https://www.quora.com/How-does-one-become-a-great-coder-prog... ), and I think it still holds.
However, the other part of that answer was to make the code immensely readable, because we read more code than we write unless we’re incredibly junior or comically superhuman.
This of course led to no small level of anxiety during the run up to Y2K.
As a side note, while I was there, the dictum came down that there was to be no more assembler programming to be done.
I know what you are thinking. They should just burn the mainframe with fire and rewrite it all. I recommend the book https://www.amazon.com/Kill-Fire-Manage-Computer-Systems/dp/....
I wouldn't call that good code but it's often too good to spend time replacing.
This is something I think functional styles of programming lead more naturally towards than OO or procedural. It's far easier to separate concerns when you can pass around like bundles of functionality (i e. first order functions). Also it really helps when you are used to writing code with no dependency except what is passed in, and not effect except what is returned. Then thhen you're sure that the code is not leaky in it's abstraction.
You can do it in other paradigms, but it's it's not where the language naturally leads you. OO has retained state as a key foundation of it's philosophy. Procedural code tends to mix up the how something is done and the what is being done. (e.g. the iteration through a data structure, with the definition of what is being searched for).
Code that does what it should is rarely read. Until you need to change it. And it may not be changing due to it being incorrect. If an attendant system gets replaced, you may have to change all the other systems it has touched. Business requirements may have changed. Stakeholders may have changed.
There are plenty of reasons for code to change beyond there being a bug.
https://commadot.com/wtf-per-minute/
See e.g. http://www.literateprogramming.com/
Good code in my systems are ones that don't need to be touched or read very often, and the fluid/unknowns parts are decoupled elsewhere. Sometimes business requirements issue, Sometimes difficult technical problem.
The bad code is read a few times and refactor as soon as we get a chance.
Not doing code review on a collaborative project? You're already setup for failure...
OP's point of view is valid if they are the only one working on the project. Only you are responsible for your low standards.
Good or bad, you’re going to end up needing to add new features to this code. Or someone misunderstood an input or output to/from this code and you’ll need to read through it to understand how it’s implicated in a bug.
I think ‘good code is easy to read’ is pretty profound: DRY code with the right abstraction is easy to read. DRY code with the wrong abstraction is hard to read.
In their last paragraph:
(emphasis added)So the point is really: "Good code should be so apparent that when the reader reads it they do not have to be a human interpreter."
I have been there a couple of times, and how some stuff is handled in these codebases were sad. Sloppy, assumption ridden, or pure, inelegant and fragile hacks.
Even if you're reading a code to modify it, good code is easier to follow and read (point of the junior developer), and as a result, you touch less and less parts of the code to develop it even further.
So yes, Good code is rarely read, or "read less, and in more niche cases".
I believe this varies wildly programmer to programmer. I'm often diving into code and reading that when debugging. I've done this with many code bases. It may be debatable if any of them are "good".
Which is readable, understandable and exceptionally good at what it does for 200 line bash script.
So, there's good code out there.
The good ones dont.
The thing they all have in common is that they are/were overwhelmingly useful to people who didn’t need to go digging inside of them to use or understand them. These are bodies of code for which the behavioral and algorithmic properties were documented thoroughly, bodies of code that generalize to wide ranges of applications.
Still, we’re not all writing STL core classes every day. Sure. Write code so good it doesn’t need to be read. Write code so good that people want to read it. And write code that, when read, is welcoming, comprehensible, and considerate of others or yourself in the future.
Saying the first thing shouldn’t mean unsaying the other things… Something our author may learn over time.
Adding features to a code means it was incomplete. Misunderstanding input/output usually means it is poorly documented or lacked a good API. A good API works at the surface (in/out) and not in the volume.
Really good code solves a problem completely. I have worked with such code and yes almost nobody ever goes into this code (and makes changes).
That definitely implies code can't be good if needs change, which makes no sense to me.
eg someone releases a new file format. You believe ffmpeg is bad code?
In ffmpeg case I assume this is how it would be.
Your approach is I guess valid for self contained algorithmic code, i.e. 0.000001% of code out there.
This does not impact readability or the idea of "good code" in my opinion.
You could have an application that is missing features which still contains examples of "good code". Learning about "good code" by reading the source code of this application won't really give any direct hints of missing features...the granularity is different.
In practice this isn't true. The code may have been perfect and complete according to the business requirements of 1 month ago. But the business requirements of 1 month ago and today are often completely different.
Is it not waterfall enough? Is it too much learning from customers? Is it too small PRs of duration less than 1-6 months? Is it not enough premature optimization?
There are actually aspects of morality which might be discussed, but I generally don’t think it’s the topic at hand.
Your excessive focus on minor linguistic nuances is counterproductive. It's more important to understand the overall message than to get bogged down by trivialities, which everyone here seems to be able to do — except you.
Moreover, by repeatedly correcting language, you give off an 'I'm smarter than you' vibe, which isn't conducive to a productive conversation.
Some change/rework is unavoidable, but if code is good, then it should be relatively rare. Modularity isn't sufficient for code to be good. It's difficult to have truly 'loose coupling' without 'high cohesion'; each module should have distinct and well-defined responsibilities. My test for high cohesion is the question: "Is this module easy to describe to a user with limited technical abilities?"
If modules are both loosely coupled and high cohesion, you'll find that you rarely need to change the code, or won't need to change it much, even after substantial refactorings. This is because such modules provide a near-optimal level of abstraction. Interfaces of such modules tend to be simple (a relatively small number of simple parameters, e.g. primitive types); this is what makes the modules easy to substitute.
For example, consider a database client library, the most powerful method is for running queries against the database; this method typically requires only a single argument as a query; a string, though it will also typically support an object/map as second argument to substitute values into the query. How often do you need to change the database client library because of a refactoring? You could literally pivot your entire business model from a social media app to an enterprise CRM and you wouldn't have to change a single line of code in your database client. You might change how you use your database client within your back end logic, but you won't have to change the implementation of the client itself.
There are many less extreme examples though where a module can handle very significant changes to your business without having to be modified at all. Maybe your business pivoted from being a professional/business social media app to being focused on friends and family; it might change some aspects like friend discovery, algorithm recommendations, banning, etc... But you should be able to keep most of your existing code if your code is good quality.
My definition of good code is "Code that is resistant to change when faced with requirement changes." Though there is a lot of overlap with "Code that is rarely read."
Most of my refactoring only affect the trunk of the code. I try to have all the business logic for a program or service represented in a single file. If the file gets too big, I create new modules 'branches' and move the most generic logic to those branches. My top level file tells the full story of the program/service. Anyone can open that file and, based on the module names and method names that are being called, they can figure out what happens and when. All the events, endpoints, logging, access control and other externally observable behavior is wired together in that file.
If the file has been abstracted to the maximum amount possible (with all generic functionality moved to branch modules) and it's still too big, it may be time to switch to a micro-service architecture. Break up the trunk into 2 parts and we basically end up with 2 apps/services. This rarely happens though. With the right level of abstraction, you can fit a massive amount of user functionality in a single main file. By the time the main file's code becomes overwhelming, the application's UX becomes overwhelming for the end user too... Time to split up into multiple apps.
Think of how complicated UX would be if a video-editing software tried to support image editing as well (e.g. to make fancy title screens or UI overlays). It would become too much for the user. Just make two different applications; one for video editing, one of the image editing. You can integrate them in a seamless way, but they should be different apps.
Now, if you think a little more about this, there is a huge risk that some of your leaf code should be in a library. For example, SQL builders, ORMs, UI kits, markdown formatters, etc. When it's a publicly available package used by many devs around the world, the code in it often changes. The reason why your leaf code doesn't change is that you don't have a proper investment return for small changes because you are a single user. Code in libraries handles more useful use cases, it handles more edge cases, it provides better API, and it contains fewer bugs than code in leaf nodes. And all that's while code in libraries is constantly changed. And code in leaf nodes... I would say that the proper description for it is "used, but dead".
i offer the entirety of sqlite as a counter-example. Based on that project's forum traffic and my participation within that project, i estimate that there are hundreds, if not thousands, of people who actively read that project's C code. That doesn't make it "bad code," that just makes it code which people want to understand (which, in turn, requires reading).
A = "good code"; B = "rarely read"; C = "often read"
A implies B
B is exclusive with C
X leading to C implies X is not A
This means that core algorithm bundles in business applications that necessarily carry a lot of complexity and need lots of careful maintenance over the decades can never reach the status of good code.
On the other hand, the twenty lines of bash I use to hook mpv into SomaFM streams are very good code.
https://literateprogramming.com/
(or if that's off-line, see: https://en.wikipedia.org/wiki/Literate_programming )
and published books which exist so that folks can read the source code of programs:
https://www.goodreads.com/review/list/21394355-william-adams...
Building good abstractions requires: 1. skill that is in relative terms rare in the profession; 2. enough experience with the problem domain that the abstraction provides the perfect balance between ease-of-use and flexibility as the context changes; 3. a dedicated individual or a small team who nurtures and gatekeeps the evolution of the abstraction obsessively.
For the other 99% of real world cases, the best you can do is try your best to build decent, not-too-leaky abstractions for the problem as you face it today, and the underlying code better be readable because you'll need to maintain it constantly, as will all kinds of other people in varying states of cluelessness.
Unfortunately in the corporate world the people with the required clout rarely want to spend the time necessary to enforce a style.
Also about the claim that that 10x programmers are fantasy, I call your attention to Fabrice Bellard https://bellard.org/. I have also worked with one or two in my decades of programming career. I probably peak out at somewhere around 0.75.
Similarly, I think the author is simply saying that well written, easy to read, easy to understand code shouldn't have to be re-read multiple times by the same person. Which is good. The inverse would be that difficult to understand code would have to be read, re-read and studied deeply to actually grok. And thus read a lot. Which is bad.
It's morning, and I really hope I did successfully pull off something close to real irony there.
> What they really mean is that good programmers should think ahead and craft their code with an eye minimizing future modifications.
The critique is exactly that this can not happen in real world projects because you can only speculate what requirements for the code base is down the road.
To counter this I usually apply two princinples:
1. Occam's razor - implement the simplest solution
2. Write code that is readable and understandable, so it is easier to change the code with the requirements.
The last being completely opposite to what the author of the article thinks.
The worst thing I can think of is somebody needlessly DRYing up a code base prematurely - this is in my opinion a junior behavior.
You can have an stinky old piece of legacy software that no one ever reads because that system is deprecated and slowly getting phased out, and we can live with it in the meanwhile.
You can have the most elegant a beautiful piece of code that gets read a lot, because it is in the critical path of a very active and rapidly evolving system, and people need to reference, modify and extend it a lot.
However there is a crucial way where OP is wrong: there is a pull and push between code quality and how often it is read. If your code is a legacy big ball of mud, people will be less inclined to touch it, probably going to the extend of rewriting the whole thing. On the other hand when code is well written, people are less afraid of digging into it.
Lastly, even if OP thesis was correct, I don't know think it would change anything. Strive to write the best code you can within reasonable constraints, independently of how much other will read it (which in my experience is almost always underestimated).
The best code and code bases allow you to quickly understand how they are structured and don't necessarily hold subtle, nasty surprises - or at least make it obvious if something is a nasty, subtle surprise. Those code bases tend to be a quick read.
The bad functions and code bases require you to carefully consider every little aspect of every single line in detail. And I don't just mean "read every line", I mean "Dissect lines based upon language specs, and also keep in mind this is interacting with 5 different other parts of the code base. Or not. Who knows?" In such code bases, just figuring out what something does tends to be a slog.