I read this tweet:
"The object-oriented version of spaghetti code is, of course, 'lasagna code'. Too many layers." - Roberto Waltman— Programming Wisdom (@CodeWisdom) February 24, 2018
Jokes taken as advice
It's not the first time I'd heard of this quote. Somehow it annoys me, not just this one joke, but many jokes like this one. I know I should be laughing, but I'm always worried about jokes like this going to be interpreted as advice, in its most extreme form. E.g. the advice distilled from this tweet could be: "Layers? Don't go there. Before you know it, you have lasagna code..."
It's the same for every lame microservice joke out there; I feel most of those jokes cause people to reject any idea (no matter how good) related to splitting a monolith, using a service architecture (an architecture with services, not necessarily micro ones), etc. Like all things, it won't always be a good choice, but it won't be never a good choice either.
Actually, I think it would be awesome if people would more often consider the option to use some kind of event-driven service-based architecture. Just like I think it would be awesome if people would write more lasagna code, or layered code. Most attempts at layering fail horribly, just like many (most?) attempts at building services fail horribly. Why is that? Because mostly, we have no idea what we're doing. We do know our favorite frameworks by heart. Every configuration option, every little validation constraint, every command-line tool. But we don't know architecture that well.
As I've pointed out before, layers are indeed a great architectural tool for structuring your code. I won't repeat everything here. I just wanted to discuss the concept of a layer a bit more, because this tweet and my own response to it - "Actually, I've never encountered such a project." - received some interesting reactions, for example:
You haven’t? I have some to show you :D. Too many abstractions and services.— Jelrik van Hal (@jelrikvh) February 25, 2018
I think I have, but it's more about the layers of the call stacks at runtime than how the code is organised. Service A made up of X layers gets injected into service B, which is already made up of Z layers...— Dave Marshall (@davedevelopment) February 25, 2018
Indirection, not layering
This is actually what I was hinting at: layers, when applied successfully (I'll talk about what I mean by that), are a great thing for a code base. However, most attempts at layering actually result in (not layering, but) indirection. If you'd step-debug through unsuccessfully layered code, you'll taking many steps before you get to the clue of the joke: that all we're doing is bringing out some data, and putting it back in. The complicated steps hiding this simple truth, are the steps of a weird dance between controllers, action helpers, services, tables, data objects and mappers. A lot of indirection, due to mixing in infrastructural concerns at al levels, and often clumsy usage of the programming language.
Trying to trace the workings of this kind of code may feel like you're wading through sticky layers of lasagna. Or maybe, it feels more like peeling of layers of an onion. However, it doesn't mean we should get rid of the concept of a "layer". We only need to realize that what we're looking at really aren't layers.
Successful layering: define the rules
I think it only makes sense. We're trying to deal with the code we're looking at, trying to make it manageable. It's impossible to keep everything in our head at once. We try to follow rules like "skinny controllers", so we push code out of them. We want to prevent historical failures like having
mysql_query() calls all over the place, we don't want to mix PHP with HTML, and then this indirection ("too many layers" a.k.a. "unsuccessful layering") is what happens.
In my experience, successful layering can be achieved by taking care of the following:
We need to document the rules. Documentation doesn't have to be a document. It can be a directory structure, a naming convention, doc blocks above your code, etc. It can even be a rule set, verified by some static analysis tool.
We should reinforce the rules. This should be a team effort (so you're not that annoying "application layer" person). You should talk about how certain things may "belong to a different layer" and why. A common understanding will arise from this practice. Everybody should be able to explain why every rule is the way it is.
Instead of becoming zealous about the established rules, we need to re-evaluate them all the time. Is applying the rule still beneficial? Explain to each other what the merits of applying the rule is. Maybe it was a good idea a couple of years ago, but not anymore.
If you don't know where to start, just consider domain-application-infrastructure as a standard set of layers and try to follow the rules that come with these.
Keep in mind that you don't have to follow these rules in every imaginable situation. The rules are there to help you, and to evolve based on your experiences. You need to sometimes break them. For example, it's really hard (and in my opinion completely unnecessary) to implement the Specification pattern, without ending up with code that really belongs to several different layers. The same goes for your model classes; they will have certain characteristics that help them be persistable (which is an infrastructure concern).
Paradoxically, I find that it helps me make better decisions if I try to follow some rules very strictly. It'll help me understand why, when and how to break the rules responsibly. Just make sure that, whenever you feel like it's okay to break the rules, document (and reinforce, but also re-evaluate) this decision too.
Thanks again for this blog post, very intresting. It helps me, even if I'm not commenting it. It helps to understand what I have in my mine, putting word on it and make it easier to explain to the other.
So I would like to have your tips on the documentation part. Today I can "feel" when I do code review, why some code need some architecture refactoring, but I'm not always able to explain it directly (so it takes time to discuss about it) and overall I have difficulty to extract some rules from it. So Do you have tips to extract rules and document them to be understandable for the team and the following people?
As a general suggestion, I can recommend looking into "Living Documentation" (https://leanpub.com/livingd..., in particular, offering learning opportunities as part of in-place documentation (mentioning design patterns, design concerns, links to further reading, inside doc blocks).
It'll take some time of course, before everyone understands the rules of the game. And then you'll also have to be open to changing the rules. Maybe modified rules fit better with your project, maybe the programmers already have enough trouble keeping up with the technicalities of the framework, etc.
The least you can do is to apply the rules yourself. In my experience, one day people will take an interest in what you're doing and will start asking questions (or simply mimic your behavior).
Best of luck, and thanks for letting me know that the post was helpful.
btw, what you are saying it's true in some cases and it's called OVER-ENGINEERING.
Banking grade of security: (it could be MVC, Webforms, Managed Bean... 3-layer)
1) presentation (web) (it could have some logic and validation)
2) backend (it could have logic), sometimes called controller.
3) web service (client) or MQ (client)
4) web service (server) or MQ (server)
5) Logic (its a thin layer if any).
7) Store Procedure (more logic, if any)
Model/Object Domain/DTO/VO are not layer.
It sounds a lot of layer but most layers are really easy to develop. 3) and 4) can be removed, and 7) is optional. Anything higher is just a waste of resource.
Do we need injection? NOPE!. Injection is a nice trick but it's optional, and for most people, it's bad used.
Thanks for offering your point of view!
You are obviously missing the point in that quote which says "Too many layers!" Note the "Too many" part. This can be just as bad as "Too few", but between the two is a happy medium called "Enough".
I have been designing and building enterprise applications for several decades in several languages, and the best layering system I have encountered is the 3-Tier Architecture with its Presentation, Business and Data Access layers. During implementation in my latest OO language I had two separate components in the Business layer which a colleague recognised as being the Controller and View from the MVC design pattern, leaving the Model in the Business layer. Thus my architecture is a combination of 3TA and MVC. Your idea of Domain-Application-Infrastructure is not something that I would ever use.
I really think I'm not "missing the point" here. I agree of course about the golden means between too many and too few. It's just that, people listening to this joke might take it as advice in the extreme sense of not using *any* layering. So I think you missed *my* point (just kidding).
I understand from your comment that you'd never even consider using the layers I propose (not just me by the way), but to be honest, there are serious issues with MVC and 3TA. With MVC it's mainly that domain logic ends up in controllers; with 3TA it's the emphasis on data access in the core (where I would propose an emphasis on domain objects and their behavior).
Anyway, thanks for commenting.
Anybody who reads "don't use TOO MANY layers" and interprets it as "don't use ANY layers" is mentally deficient and should go bac to school.
Your serious issues with MVC and 3TA are down to faulty implementations and not the concepts themselves. Anybody who puts domain logic in the controllers is doing it wrong. Business logic belongs in and ONLY in the business/domain layer inside models.
When MVC is combined with 3TA it means that all data access logic is taken out of the model and put into a separate component in a different layer. Thus when the model wishes to perform any database access it talks to the DAO which then constructs and executes the SQL query which is specific to the DBMS being used at that time. There is no data access in the core.
In my implementation the core of the application resides in the models. All controllers, views and data access objects are reusable services which are provided by the framework. None of these services contains any application logic.
This is really not the kind of tone I'm looking for in the comment section of my blog.
I know that many developers take jokes like this as advice. These people are not "mentally deficient", they just don't know what position to take on this subject.
I'll leave this comment unmoderated, just in case it will be helpful for others to read it. If you feel like moderating it yourself after all, feel free to do so.
If you think that my tone was a little harsh then you are being too delicate. Anybody who seems to think that "don't use too many layers" is exactly the same as "don't use ANY layers" is exhibiting below-average intelligence and will therefore never be an above-average programmer. When it comes to applying any so-called "rule" or "principle", such as the Single Responsibility Principle or technical keys in databases, there are basically two ways in which it can be done - intelligently and indiscriminately. Intelligent people understand that a rule should not be applied unless the circumstances are appropriate, and when applying a rule they also know when to stop. They know the difference between "too little", "too much" and "enough". They know that "when appropriate" means that every set of circumstances needs to be evaluated on its own merits. Anyone who says "I don't know whether this rule rule is appropriate or not, so I shall implement it anyway and hope for the best" is most definitely not among the ranks of the above-average. Anybody who thinks "three layers are good, therefore six layers must be twice as good" is not firing on all cylinders, is one brick short of a full load, is one sandwich short of a picnic. No matter what pretty words you use it all means the same thing - they are intellectually impaired, mentally deficient, or lacking in the brain department.
There is no value in making judgements of people in this way. It doesn't help us solve problems, creates division, and doesn't actually make us feel better. It's a no win strategy.
There's also no purpose in fighting straw men. If we don't understand how misunderstandings might occur it may be best to reserve judgement and continue to ask questions. So long as we keep the mindset of genuinely wanting to understand and keep asking questions then we can acquire the most rare, valuable, and elusive form of knowledge, insight into our own perceptual limitations.
By criticising me for my description of people who cannot understand what they read you are seriously missing the point. If there is a discrepancy between what was in the mind of the writer and what is transferred to the mind of the reader then you need to account for that discrepancy. Was the writer imprecise in what he wrote, or does the reader not possess the necessary skills to fully comprehend what he reads?
In the case where a writer says "Don't use too many levels" and a reader interprets this as "Don't use levels ANY levels at all" then there is absolutely no question that it is the reader who is at fault.
If you want an classic example which shows a fault in the mind of the writer then look no further than Robert C Martin's Single Responsibilty Principle where he describes the necessary criteria as "reason for change". That, to me, is a totally useless description as it is open to far too much interpretation. It took several later articles for him to come up with a more meaningful description. In one article he states:
"GUIs change at a very different rate, and for very different reasons, than business rules. Database schemas change for very different reasons, and at very different rates than business rules. Keeping these concerns (GUI, business rules, database) separate is good design."
In another article he states:
"This is the reason we do not put SQL in JSPs. This is the reason we do not generate HTML in the modules that compute results. This is the reason that business rules should not know the database schema. This is the reason we separate concerns."
These descriptions are far more useful as they show actual areas of program logic which can be identified and therefore separated. If you look at the 3 concerns which he explicitly identified - GUI, business rules, database - you should see that this matches the description of the 3-Tier Architecture to a tee. That is what he preached, and that is what I practice. Note that I discovered and adopted the 3-Tier Architecture years before I heard of SRP. I don't follow that principle because I was told to follow it, I came across a working example and immediately saw the benefits.
I'm not missing the point.
My response is about a point that I find more important than the one that you or Matthias are discussing.
But, to speak to the point that you bring up. Especially in the era of the internet it is not a question of WHETHER OR NOT there will be misunderstanding. It may be closer to ask, "HOW MANY people will misunderstand." There's just too many people and information spreads in often uncontrollable ways.
I don't see the point of writing off / criticizing the people who misunderstand. That's part of a blame culture that I believe is counter-productive at best. I think that it's much more interesting to make a positive impact in people's lives and to try to affect them in a way that creates fewer misunderstandings and a better future for software design.
Of course, ultimately... as the physics of software becomes increasingly understood our cultures will have a much better idea of how to train etc. But, we're really all groping around in the dark for now. We can do a better job if we work together rather than isolate ourselves and other people.
I'm glad that you have enough experience (by looking at your website, it seems that you have many decades) to have some amount of insight as to what works for you in your personal situations. But, all of your ideas are genuinely bad when applied to circumstances in which they are less well-suited (yes, a tautology, but important).
You have your circumstances, others have their circumstances. To write-off those whose circumstances you're too ignorant to perceive (a universal human failing) doesn't help them and it doesn't help you.
In pretending that your insights are universal you prevent yourself from understanding circumstances outside of your experience and create a barrier for others who would want to understand yours.
> I don't see the point of writing off / criticizing the people who misunderstand.
If you are not prepared to discuss exactly why the level of misunderstanding is so high, and what to do about it, then you are part of the problem instead of being part of the solution. Just suppose there were similar levels of confusion in other professions, such as with doctors and surgeons, or people who design aircraft, vehicles or buildings. If their "confusion" began to cause deaths then there would be demands for something to be done. While few programmers write software on which people's lives depend, this confusion causes bad software, and bad software casts a shadow over the entire profession. I have already stated that people can be confused by a lack of clarity in what they read rather than not being able to understand what has been properly written, so perhaps we should start by rewriting all these programming principles in clear, concise, precise, accurate and unambiguous terms.
You should remember that as programmers we regularly have to communicate with the most stupid things on the planet - computers. They do not have any in-built intelligence, their only claim to fame is that they can follow instructions at an incredible rate that no human being can match. In other words they are nothing but fast idiots. The instructions we write for these idiots has to be 100% precise and must cover all possible situations otherwise unexpected, sometimes unpleasant, things may happen.
It should be the same when someone is writing instructions for other programmers. The fact that human beings do not have the same level of idiocy as computers is no excuse to give vague, wishy-washy, ambiguous and imprecise instructions. If you bother to read the articles on my website you will see that I regularly attack those programming principles, such as SOLID, which were so badly written that they have generated huge volumes of misinterpretation. This misinterpretation spreads like Chinese Whispers so that the end result is far removed from what was originally intended. I had years of programming experience before I encountered most of these principles, and this enabled me to see them for what they are - nothing but snake oil.
Let's end this pointless discussion here and now. I'm not being too delicate, it's just that "tone" in this case vastly reduces the educational value of what you write and I don't want these unhelpful comments on my blog, which I'm trying hard to make as useful to others as possible.
Nice, your posts are always enriching!
Thanks for letting me know, Josef!
No advice should be taken to extreme or used as excuse not to try doing things right.
btw., I've posted about lasagna as well: http://en.rmcreative.ru/blo... I prefer spaghetti :)
Nice post, thanks for sharing.
Please keep writing. We need more moderating voices.
Thanks, Shawn, I will!