Followup to: How to comment your code – Part 1
Design is a tool to make our code more maintainable, AKA, better.
Specifically, a good design makes our code:
- Easier to change
- Easier to understand
In this article, I'll focus on the first and get the second as a bonus.
How hard is it to change something in a program?
Since we are not focusing on "how hard is it to understand the code", let's say you understand the code.
The "hardness" will come because you are trying to change one thing but other things are dependent on it and you need to change them too.
This 'dependancy' is called 'coupling'. Coupling is the source of all evil. If you don't know what coupling is in the context of software design, then please read about it, and keep in mind you are reading about evilness.
Any coupling between two components means that if one changes then the other has to. This makes both components harder to change == harder to maintain == lower quality code.
If your GUI knows about your database, BAD.
If your code is full of cout << "my log print", thus coupling the code to the fact that you have a console, BAD.
If you're thinking "but not all coupling can be avoided", then you're right. If your function foo calls function sum_lengths, then foo's code is coupled to sum_length's current function signature.
So does this mean we can't call functions anymore? Of course it doesn't. But we should still NOTICE this coupling, and we must remember that not all couplings were created equal. If sum_length takes as a parameter an array of lengths in centimeters and returns a length in meters, then sum_lengths is coupled to the metric system used in the program. It will be invalid if we start using inches. This kind of code should HURT you to look at.
You'd probably prefer a simple sum(arr), which doesn't know about the metric system, and doesn't even know that it's summing lengths (!), or if we'll use the terminology of coupling: sum isn't coupled to meters or to lengths. We could say that it's "more standard" or "more generic", and that would be true, but notice, that both of these can be expressed as "has less coupling".
Why is it so useful to talk in terms of coupling #1: Awful discussions about design
Do you know (and I hope you don't) those design conversations where Guy #1 says "Design A looks better to me" and Guy #2 says "But we should do design B because it's better. Can you see? These classes here feel more correct".
Pick your variation.
I bet you have this programmer who thinks he can design but he actually can't. And mainly, he never justifies his designs with more than "it feels correct".
You probably try explaining him about layers or the "open-closed principle" or whatever principle he's currently breaking with his design, but that conversation doesn't get far.
I suggest a new standard in these conversations. If design A gets rid of coupling that exists in design B (and doesn't add any), then design A is better. EOF.
Imagine how short and efficient design conversations will become.
And even the newest programmers will be able to participate fully, even without knowing about all the design patterns you read about.
Which leads me to my next point
Why is it so useful to talk in terms of coupling #1: Great training for new programmers
Programmers often have this phase when they can get code to work and then you try teaching them how to design.
And you teach them lots of design principles. And design patterns. And so on.
2 points for each design principle you know that you'll write down or recall right now.
I claim that 80% of the design principles simply help us reduce or avoid coupling. And avoiding coupling can lead to good code that complies with all these design principles.
By just using ONE principle.
Sounds too good to be true?
When I'd teach C++ and design, this would be the only design principle I'd teach.
In the last class, the lesson is supposed to be "design patterns".
But the students were good enough designers to INVENT the design pattern themselves. I would give them a problem and they would, in group discussion, invent "iterator", "proxy", "state machine" and others. I would often lead them with the same question over and over: "What coupling is there in the solution that you offered?".
Why is it so useful to talk in terms of coupling #3: It's easy to learn. Relatively.
It's learning one design principle instead of many.
But it's more than that.
If you just learned about "layers", your brain needs to actively think once in a while (when?), "should I use layers here?".
Developing an intuition takes time.
And it's the same with most other principles. "Is this a good place to use a state machine?", "Is this a good time for hooks?"
How to you teach someone, or yourself, when to use each pattern? It's easy to say in hindsight that "this was a good place to use it". It's also easy to notice places to use the design patterns that your intuition already learned. But it's not trivial to learn these new kind-of-habits.
BUT
It's easy to notice things that HURT TO SEE.
What would you say if you'd find this code in your project:
void x(int a, int kp)
{
x2(a++, kp+a)
}
You see meaningless names and it HURTS. You'd twich. I can't find a good word for the kind of "twitch" that I'm talking about. It itches.
If you are used to comments like me, then seeing code without comments HURTS. (I learned to appreciate code that doesn't need comments, but this took deliberate effort).
I twitch when I see spelling mistakes. I twitch when somebody says "I'll remember" and doesn't write anything down.
I twitch when I see coupling.
Teaching yourself to twitch from something isn't that hard. And it will never go away as long as you keep seeing+twitching from it.
Teaching a programmer to twitch from coupling is not something he'll have to deliberately think about later. He'll twitch, and then, his brain will automatically think "can this be avoided or reduced?", and often it will be.
So, when this principle is taught correctly, your student will be able to use it effortlessly.
Aftermath: Coupling in real life
"I'll make sure I always have a recharger in my bag, so that I won't be dependant on finding one or on sleeping at home everyday"
"I'll keep a 15 minutes gap between meetings, so that I won't have a strong coupling between the first meeting finishing on time and the second meeting starting on time"
"Let's buy a car so that we aren't coupled to public transport"
"I'll put this file in the cloud , so that I can access it anywhere and I'm not coupled to being on this computer to access it"
Avoiding coupling in real life allows you to be ready for situations without needing to guess that they will happen. Guessing what will happen is impossible. Like trying to guess the changes that you'll need to make in your software 😉
Also avoiding all coupling is impossible. But focusing on avoiding coupling is the best technique for preparing for the unexpected that I know. People are often surprised how prepared I am for unexpected situations. As if I guessed them. But no, I just avoided coupling.