I have read a bounch of articles about coupling which all without exception view it from a high perspective. They rarely elaborate it with real projects.
So, there is a specific question I met:
Simplified model as following:
- architecture 1
# m: module
---------
|context|
---------
/ | | \
/ | | \
---- ---- ---- ----
|m1| |m2| |m3| |m4|
---- ---- ---- ----
Context depends on m1, m2, m3, and m4, and only one single dependency.
- architecture 2
# m: module
# al: abstract layer
---------
|context|
---------
/ \
----- -----
|al1| |al2|
----- -----
/ | | \
---- ---- ---- ----
|m1| |m2| |m3| |m4|
---- ---- ---- ----
Context depends on al1 and al2, and al1 and al2 depend respectively on
m1, m2 and m3, m4. They all have only one single dependency.
The questions is:
- Which one have looser coupling than the other and why?
- If answer is latter, then is there any relation between loose coupling and more layers?
Consider Coupling not as a number that you can measure. Coupling is the property of code using something from other code. Coupling is not just the number of dependencies or includes. The motivation of loose coupling is to reduce the ripple effects that occur when changing something in your code in order to avoid that you also have to change something somewhere else, and then again something else and then more and more and so on.
That been said consider that in architecture 2 you have some things in
al1andal2, which in architecture 1 you have incontext. That has consequences: If you have to change for example the code ofal1, then you can immediately say thatm3andm4are not affected. That is good. And that is the purpose of loose coupling. You change something and you know in advance that inm3andm4you have no consequences. In professional life knowing such things is valuable because you can well estimate the consequences of modifyingal1.If you don't have
al1, then you only know, there is something incontext. So typically you cannot estimate the consequences, you have to recompile everything (coupling has indeed an impact to the compilation time). Changing something incontextis more a surprise than changing something inal1. You don't want surprises. And therefore the architecture 2 is probably better. Things are more loosely coupled.Concretely: In your diagram of architecture 2
m3andm4do not depend onal1. This is clearly a reduction of the coupling.But the word coupling is not the only terminus of importance. Architecture 2 demonstrates that there are two parts that are not related to each other (because
al1andal2do not depend on each others). Both parts have a strong "cohesion". Grouping them together incontextwould be a mistake. Things that don`t belong to each others shouldn't be grouped together.To your question 2: The answer is yes, if your abstraction does not add extra complexity. But typically abstraction does add extra complexity. So that means, there is no general answer to your question. In your daily life as software developer you are often in the situation to establish an abstraction layer with the objective to improve the code but then you realise that you have overengineered things and the abstraction layer made everything to the worse.
You may have heared the word "refactoring". It is important to change such wrong architecture decisions. You often have to try out things in the architecture to see what does they mean and restructure the code. It would be nice to have a criteria that helps you to decide what architecture is better.
But if you mean with "layers" levels of inheritance, then the general answer is: Inheritance is a very strongest coupling and often does not reduce the coupling.