Wednesday, September 17, 2014

Why you SHOULD use layered architecture

This post argues against using layered architecture since according to the post you simply don't change implementation of your database or implementation of JPA.

Firstly, the term layering is a misused term, layered architecture should be regarded as layered on its own. There are several different layers, such as communication, framework, hardware each of these might contain several other layers of multiple layers of some notion, such as a OS hosting processes etc. Layering is a code standpoint when you choose the "what" of all of the combined layers and present functionality and why they matter to the layer above.

Now secondly, if layers matters, you are doing layers wrong (layering to hide implementation of frameworks in a application which is about e-commerce is silly). Layering is organizing context, a common misunderstanding is that layering are abstractions. It has a lot to do with abstractions and most of the times its get confused with it, but it really is about context relaying, where the details of a function effects the surrounding code and layers.

Context relaying is heavily bound to the fact that abstractions leak. Some sort of combined function will always leak the inherent functionality. If it were true that the function wouldn't leak, it has to be so general that it will accept anything and reply with precisely what you want, i.e the God Service.

Now computers are inherently stupid, they will do as exactly as told even if its wrong, as long you talk its language. Problem is that whenever you are producing code you mostly focus on the how not the what. As an example is the inherently problematic behavior when writing objects. You might name an object as Animal and when you read this it seems like a very sensible thing to name your object because it might have a place in the object community. However this is blatantly wrong because the notion of Animal doesn't mean anything unless you provide proper context which is described with code, either directly or indirectly. Try switch the name of that object to X4 and things starts to make less sense. In fact, try obfuscating the whole codebase and try to understand what is going on, and if you do you might be closer to a good layering structure.

Now a layer is where a bunch of objects are making sense regardless of other bunches of objects are doing, even if there seems to be some sort of dependency of them. The code has to be reflecting this, if more than one "bunch" of code is breaking layers you have done layering wrong. Object oriented programming and TDD may produce bad layering because you are only are regarding the object or the"unit". To get this correct you have to focus on context and behaviour while creating the object and "unit". Both SOLID and the principle behind TDD encourages doing layering correctly if you focus on context and behaviour, combine them with context relaying you are one step closer to doing layering correctly.

Another factor of the "mess of layers" is the misuse of interfaces. And this is inherited by the fact that  its simple to produce code interfaces but hard to create data interfaces and those are mostly overlooked. Such as when creating simple CRUDs.


  1. Thanks a lot for your response to our article.

    "Object oriented programming and TDD is prone to produce bad layering because of the fact that you are focusing on the "unit"."

    That's a very intriguing thought. I'd like to know more about your opinion on that

    1. Im still working on the details here, hopefully there is actually ways of providing some metrics on why. There are really two main things here.

      With TDD you are focusing on the test; write the test which fails and then write the code to make it pass. Problem with this idea is just what it says: You are not focusing on the what just the how, and the what is important because it gives context to the function. Because abstractions leaks you might find out that things farther away from the "unit" is affected which you might not expected so therefore your tests are not giving you that information. You might try and use TDD as a restricting technique, and thats fine I guess, as long you understand it won't make layers by itself.

      The same idea is applies to the objectification of things, the "Object.method" coordinate doesn't really imply much, like Dog.bark(), its too weak. Yeah sure, as a programmer I could make sense out of that but, in a layered structure how "far" and how "strong" does Dog.bark() effect its surrounding and should it matter? Lambdas and functional programming (I'm still quite exited of Erlang) is a tad better however not flexible enough, don't get me wrong here, they are just not good enough. They are not providing enough information to give "depth", which OO does.

      When writing code there is a "time effect"(not threads), "depth", "sinks", "knots" and "tainting", calling on code in one layer means something else if you would call it in some other layer. And when you are writing those TDD tests you won't know half of the things your test should be looking for, so you can't write the test in the true meaning of TDD.

      It might not sound much for now and I'm still struggling with how to describe it. The principle of TDD is still a good idea, but I think the implementation is a bit off, and the code should be describing the tests effect instead of the test itself.

    2. I think I can see where you are trying to go with that argument. Most specifically, I completely agree with the danger of TDD producing layers of its own. I've always seen that as the most important argument against TDD, even if I don't object the basic idea of TDD itself.

      With jOOQ, we're only focusing on end-to-end tests, which run queries via the jOOQ API against actual databases in actual transactions. We don't mock anything. We just know that the database probably works, so the database must still work when queried via jOOQ.

      Of course, jOOQ is a very simple domain for testing. Actual business logic is a lot harder to test.

      I'll be looking forward to your further musings about how OO and functional programming relate to TDD. I know that expressing these things concisely is hard, but I'm sure you'll get there :-)