- Coding is always slow
- Coding produces both code & bugs
- The code always needs to be edited, the first version is just roughed in.
- Do not use disposable code in industrial strength projects.
You want the code to be as small as possible, it is easier to deal with. Larger codebases are worse, not better.
You want the code to be as readable as possible so it is easier to edit. If it is a choice between small or readability, readability wins. If it is a choice between readable or performance, readability wins.
You can always fix readable code later. But it must be reable first, and remain readable afterwards.
You don’t want the code to be redundant, cause you’ll always forget to change all of the different manifestations of it for the same bug. Redundancies are bugs or potential bugs. Changes to redundant code cause the code to drift apart.
You need the codebase to be tightly organized so that it is easier to find and fix the problems. You can accidentally waste more time fixing bugs, than in coding/refactoring, so you need to optimize for that.
There should be one and only one place to put each line of code. All of the code should be in its one place. If there are lots of different places where you can put the code, you are disorganized.
The author is not the only one who needs to reread the code. Others will have to read it as well. Good code will be read by a lot of people.
Because you didn’t just magically get it right the first time, you and other people will have to go over the code, again and again, in order to make it better. Code doesn’t get written, it evolves.
The fiction that layers are bad is poor advice. Layers are the main way you keep the code organized. Without them, the code is just one huge flat mess. That is far worse, it is totally unreadable.
Layers can be abused, there can be too many of them. But not having any at all is worse. It is easier to remove a layer than add one.
A good function is specific to some part of the computation. It is general. It does the one thing that it says it does, nothing more. Sub-level detail processing is below it, in other functions. High-level flow is above it. Once you know what it does, and trust that it does exactly and only that, then you can ignore it, which makes life easier.
All data should come into the code from somewhere else. It should never be hardcoded in the code, it should not be hardcoded when passed down to the code. Thus all strings, integers, constants, etc. are suspect. The best code has zero hardcoded values.
If you need to do a bunch of steps each time for a common action, wrap the steps. The fewer things you call the better your code is. If you rely on remembering that all things have to always be done together, either you’ll forget or someone else who never knew will do it incorrectly. Either way, it is now a bug, and it may not be an obvious one, so it will waste time.
If you need to move around some data, all together. Wrap the data, in a struct, object, whatever the language supports. Composite variables are far better than lots of independent variables.
If you need to decompose the data (aka parse) to use it somewhere, decompose it once and only once. Keep it decomposed in a struct, object, etc. move it around as a composite.
If the call for some library/technology/etc. is messy, wrap it. Wrapping is a form of encapsulation, it helps to avoid bugs and reduce complexity.
If there are strange lines of code that are nonintuitive or don’t make sense, wrap them. At minimum, it gives you a chance to name it appropriately; at maximum, it leaves just one place to change it later.
Too many functions are way better than too few. If you have to get it wrong, create a billion functions. They force you to have to find reasonable names for the parts of work you are doing. If you don’t know how to name a function, then you don’t understand what you are doing. If you have too many functions it is easy to compact them. If you have too few, you are screwed.
Don’t use language features if you don’t understand them. The goal of coding for a system is not to learn new technology, it is to write industrial-strength code that withstands the test of time. If you want to play, good, but don’t do it in a real project, do it in little demos (which can be as messy as you want).
Do not pack lines. Saving yourself a few lines of code, but packing together a whole bunch of mechanics, just hides the mechanics and misguides you as to the amount of code you have. Separate out each and every line of code, it doesn’t take any real time and it lays out the mess in its full ugliness. If the mess is ugly fix that, don’t hide it.
Never do the same thing in a system in two or more different ways. You need to do something, do it one way and only one way, wrap it in a function, and reuse it in all other instances. This cuts down on complexity. By a huge amount. It cuts down on code, thus it cuts down on bugs.
Build up the mechanics to work at a higher level. That is, if you need an id to get to a user, and the user to get to their profile, then you should have a FindUser(id) which is supplied to the call FindProfile(user). Build up reusable pieces, don’t code down into stuff.
You want the code to be as readable as possible so it is easier to edit. If it is a choice between small or readability, readability wins. If it is a choice between readable or performance, readability wins.
You can always fix readable code later. But it must be reable first, and remain readable afterwards.
You don’t want the code to be redundant, cause you’ll always forget to change all of the different manifestations of it for the same bug. Redundancies are bugs or potential bugs. Changes to redundant code cause the code to drift apart.
You need the codebase to be tightly organized so that it is easier to find and fix the problems. You can accidentally waste more time fixing bugs, than in coding/refactoring, so you need to optimize for that.
There should be one and only one place to put each line of code. All of the code should be in its one place. If there are lots of different places where you can put the code, you are disorganized.
The author is not the only one who needs to reread the code. Others will have to read it as well. Good code will be read by a lot of people.
Because you didn’t just magically get it right the first time, you and other people will have to go over the code, again and again, in order to make it better. Code doesn’t get written, it evolves.
The fiction that layers are bad is poor advice. Layers are the main way you keep the code organized. Without them, the code is just one huge flat mess. That is far worse, it is totally unreadable.
Layers can be abused, there can be too many of them. But not having any at all is worse. It is easier to remove a layer than add one.
A good function is specific to some part of the computation. It is general. It does the one thing that it says it does, nothing more. Sub-level detail processing is below it, in other functions. High-level flow is above it. Once you know what it does, and trust that it does exactly and only that, then you can ignore it, which makes life easier.
All data should come into the code from somewhere else. It should never be hardcoded in the code, it should not be hardcoded when passed down to the code. Thus all strings, integers, constants, etc. are suspect. The best code has zero hardcoded values.
If you need to do a bunch of steps each time for a common action, wrap the steps. The fewer things you call the better your code is. If you rely on remembering that all things have to always be done together, either you’ll forget or someone else who never knew will do it incorrectly. Either way, it is now a bug, and it may not be an obvious one, so it will waste time.
If you need to move around some data, all together. Wrap the data, in a struct, object, whatever the language supports. Composite variables are far better than lots of independent variables.
If you need to decompose the data (aka parse) to use it somewhere, decompose it once and only once. Keep it decomposed in a struct, object, etc. move it around as a composite.
If the call for some library/technology/etc. is messy, wrap it. Wrapping is a form of encapsulation, it helps to avoid bugs and reduce complexity.
If there are strange lines of code that are nonintuitive or don’t make sense, wrap them. At minimum, it gives you a chance to name it appropriately; at maximum, it leaves just one place to change it later.
Too many functions are way better than too few. If you have to get it wrong, create a billion functions. They force you to have to find reasonable names for the parts of work you are doing. If you don’t know how to name a function, then you don’t understand what you are doing. If you have too many functions it is easy to compact them. If you have too few, you are screwed.
Don’t use language features if you don’t understand them. The goal of coding for a system is not to learn new technology, it is to write industrial-strength code that withstands the test of time. If you want to play, good, but don’t do it in a real project, do it in little demos (which can be as messy as you want).
Do not pack lines. Saving yourself a few lines of code, but packing together a whole bunch of mechanics, just hides the mechanics and misguides you as to the amount of code you have. Separate out each and every line of code, it doesn’t take any real time and it lays out the mess in its full ugliness. If the mess is ugly fix that, don’t hide it.
Never do the same thing in a system in two or more different ways. You need to do something, do it one way and only one way, wrap it in a function, and reuse it in all other instances. This cuts down on complexity. By a huge amount. It cuts down on code, thus it cuts down on bugs.
Build up the mechanics to work at a higher level. That is, if you need an id to get to a user, and the user to get to their profile, then you should have a FindUser(id) which is supplied to the call FindProfile(user). Build up reusable pieces, don’t code down into stuff.