There are a lot of ways to create software. In fact, there are even a lot of ways to create good software. When it comes to application server deve...
For further actions, you may consider blocking this person and/or reporting abuse
Hi there, nice article!
However, one thing I don’t agree with is
as it pretends that JEE implies an anemic domain model. Of course, this approach makes sense for simple CRUD applications but it is also possible to follow an object-oriented approach, e.g. domain-driven design.
Glad you like it, Flo!
So maybe I wasn't very clear in that regard in the article. You can of course add whichever methods you want or need in your domain model; JPA will not care about them (unless they have the signature of a getter/setter but that's another story). The main point that I was trying to make here is: do never, never ever try to reference one of your services (no matter from which layer) inside the domain model. Things will go south very very fast from there, I lived to regret it myself. One of the "golden rules" of the JEE architecture is: once you are outside the Dependency Injection Container context, do not try to get back into it.
I totally agree that a data model that does literally nothing else than containing the data isn't necessarily something you want in an object-oriented system. I also agree that this is troublesome from an OOP perspective because you eliminate a large portion of the benefit that OOP provides (in particular polymorphism). The folks who do react-redux in the oh-so-object-oriented javascript world do just that all day long: they do not even bother to assign classes (prototypes) to their data structures anymore, it's just data. JEE doesn't force you to do anything like that; as long as whatever your method is going to do will not access services. In particular, you would have:
userRepository.save(user)
... and not...
user.save()
The latter is the "solution" that OOP actually promises: functions and data go together. And I could not agree more that this is very appealing and very nice. However, in practice, you hit a wall here.
save()
- well, save to where exactly? The database? An XML document? There is an excellent talk by Robert Martin on a related issue. Sometimes you need to separate the algorithm from the data, because there may be more than one algorithm operating on it (save to XML, save to database, save to I/O stream...) and you cannot possibly foresee any future algorithm you will require. In the end, it all boils down to one thing: managing the dependencies between your objects. In particular in a JEE-style environment, objects move from the persistent state (stored in the DB) to the transient state back and forth all the time, and there are multiple representations of each object, due to the way requests are handled and isolated from one another. Thus, the separation of services (for "heavyweight" operations) and methods on the domain model itself (for local changes) makes sense. But I do understand your point. Frankly, I've been pondering on this very issue myself a lot.Thanks a lot for taking the time to answer!
I am still not sure I agree :D Again, my point was that JEE simply makes no assumptions about how to model the domain. While I agree with many of the points in your post these have nothing to do with JEE in particular but with software architecture in general. So I think it is a bit misleading as people might connect these ideas to enterprise Java.
Uhm, JEE also does not force anything even if a rich model does reference a service. Again, I think you are mixing JEE and general advice about software architecture. As for the advice part: not so sure this statement holds in any case. For example, think about domain-driven design. There each layer explicitly makes space for own services and, of course, this can be modelled in JEE.
P.S. Uncle Bob’s talk indeed is great. You should also check out his blog post about Clean Architecture if you have not already read it anyway :-)
Thanks for the response. I think this discussion is important and quite interesting.
As you stated, domain model classes accessing or not accessing services isn't strictly about the JEE architecture anymore. Indeed, the JEE architecture is agnostic to this decision. However, if we look a bit deeper into the technical details, when you are dealing with a JEE-like architecture, you will likely also want some kind of dependency injection (DI) framework. Otherwise, you will end up with a lot of singletons and hard-wired dependencies which in turn make your code very difficult to handle in unit and integration tests (been there, done that, and lived to regret it).
So what you usually find is either some flavor of Google Guice, Spring's IoC Container or some other implementation of JSR 330. All of these containers help you to implement de-facto singletons without resorting to
static
variables in your code, such that you can easily interchange them (or even mock them) for testing. However, this technique only works for singletons (and a selected handful of other 'scopes'), but it will not work for domain model elements - which is: objects you pass around and you instantiate as required withnew
(or a factory) on the fly.In such a scenario, any service you define becomes a "singleton-scoped bean" in the container. Every bean in the container can request the container to inject other container beans into itself, usually via the constructor, via annotated setters or directly in fields. Now, if you have a method in a domain model element, there are only two ways of how this method could ever gain access to a bean from the container: either by passing the bean directly as a parameter (which is ugly; who passes around singletons?) or by having some
static
reference to the application container itself. And no matter which JSR 330 implementation you choose, every single one of them will tell you on the first page of the instructions manual: making the application context publicly available in astatic
variable is an anti-pattern.So how do we implement a method that requires access to a service method then? Well, that method becomes a service method of its own. Does it contradict the principles of OOP? Yes, it certainly does. But it helps a lot in keeping your call hierarchies clean. Some junior programmer next door might otherwise come up with the glorious idea of sending an HTTP request (and blocking the thread while waiting for the response, because why not!) in a regular bean setter. Limiting the capabilities of the domain model a bit helps programmers to estimate the impact of their method calls. What I would not want to have is that a regular setter method internally calls X, X calls Y, Y calls Z, and Z withdraws money from my bank account ;-) Trust me, I've had it all. I've seen people implementing hibernate entities as observables.
I guess this will become a bit more clear when we talk about actual implementations. I've got the feeling that we are actually aiming for similar things but express them in a different vocabulary.
Regarding Uncle Bob: I really enjoy his talks and books (I'm currently reading "Clean Architecture", his latest book). I am usually very much in agreement with what he says (except for his strange love for "write the test first" practices). However, even though in contrast to other "architecture gurus" he tries to keep his arguments close to reality and make them actionable, he remains quite abstract in his conclusions all too often. He tells people what to avoid, but rarely what to go for. At the end of the day, we have to put it into code, not lawsuits. My personal position is usually somewhere in the middle between Uncle Bob, Martin Fowler and Bertrand Mayer.
Hi Martin,
this is a great answer and I especially like that it now draws a clear line between JEE and architectural best practices. You should consider writing another blog post about this!
It's funny that we are both interested in similar philosophies about programming. I have read Clean Architecture as well (even pre-ordered :D) and I can also agree with the majority of things that Uncle Bob suggest (yep, even the TDD part; although I as well do not practice it constantly but this is more of an organizational problem in the company I work for). Anyway, if you’d like to talk about actual implementations feel free to send a link to a GitHub repository (or something) that reflects your approach. Although by now, I am quite confident that we probably won’t find much to discuss ;-)
The next article I have planned is a follow up on this one on how to actually implement this architecture with spring-boot. Time is a bit short at the moment though. I'm looking forward to your comments!
It's great that it provides an opinionated architecture, such that it might be a good choice in systems integration projects. But it's hardly efficient nor scalable compared to existing alternatives (JVM-based or otherwise).
As already stated in the text, it is a defensive choice. Will you end up with the best possible and most efficient solution? Most likely not. But you will create a solution that works. Also, if you tell someone that your application uses a standard JEE stack, then that person will already know a whole lot about the code without ever having seen it. It's not perfect, but it has a lot of merits.
Yes, I'm fine with opinionated architectures. However, I just felt many of the claims in the articles are exaggerated.
In addition, the landscape is different from 10 years ago. JVM devs are spoilt for choice of frameworks or stack that just works, so I don't see how this is a key differentiator.
Feel free to suggest alternatives then :) I'm not aware of anything comparable on the JVM.
Sure :)
Let's use Spring as a baseline. It's a good framework and Spring Boot had made it effortless to get a project up and running and plugging new functionalities.
In the same breath, I do like Ninja Framework and their focused approach. Reminds me of the Java-based Play 1.x with their hot reload.
If it's simply services you're after (no web UI), a lot of Java shops are really happy with DropWizard.
But of course, they are all servlet-based. Those who seek better performance (throughput and stability under load) would usually go for Netty-based frameworks. It a step up from the servlet's thread-per-request model.
Spring has support for both servlet (Web MVC) and Netty (WebFlux), I've never used WebFlux so I can't really comment on it yet.
With those in mind, I'd go for those akka-http based. Either akka-http for service only or Play Framework for full web framework.
Another framework worthy of mention is vert.x. I haven't used it but I know of people who had a lot of success with it.
Okay, thanks! I've heard about the play framework - mostly rants though. Still, I'll have to check those technologies out to see what they do and how they work. Thank you for the input!
No worries, hope you'll have fun learning about these different approaches. I sure did :)
Apart from frameworks or stacks, another completely different paradigm that I think you might find interesting is eventually consistent systems using EventSourcing + CQRS (Command Query Responsibility Segregation).
It's completely different (and overkill for most use cases), but it shifts your mindset from behaviours of an object to event-driven... Which, I think how things happens in real life, ie. we respond to events.
Thanks for this post.Its an eye opener
Thanks. The architecture proposed here does have its issues and weaknesses, but at least it's something to go by, a "sensible default" so to say.
Awesome ! Looking forward to your next article