SOA is not an excuse to write procedural Java
This might be the first post that is truly the rant of a young software engineer. Where do I even begin?
I always assumed that any development shop that produced an Anemic Domain Model didn’t do so on purpose. They are hard to avoid, as I know from my experience on The Project. The best intentions are often not sufficient. The best defense, it seems, is diligent refactoring.
One very recent day I was writing a JUnit test method for a co-worker. I needed to know the allowed values of a certain string field of an entity class. Even though I knew it would be fruitless, I read through the code of the class to find a clue…a consistency check of some kind.
Of course, I was greeted by a mere getter and setter. This entire class was littered with them. Why wasn’t there at least a check in the setter: if the incoming value isn’t “foo” or “bar”, cough on it.
Whatever. I’ll go bug the co-worker and waste some time. I asked her why the entity didn’t check to see if this string field was valid. After all, the way the code is written, it could be any string, and surely that wasn’t correct or intended.
I expected to be pointed to some “service” class that might provide the check. Imagine my shock and disgust when she told me that the check was done in the database, so there was no need for the entity to check for validity.
You should understand now that this company made a big deal about their new “enterprise architecture” that separates the UI, data, and the glue that holds it together. This was part of our official training. And now I’m told that a business rule is embedded in the database ON PURPOSE.
The first defense was that if we brought in every single consistency check from the database and into the code, the code would swell in size.
No kidding, I said, I’m not saying you check that a number is a number and a float is a float. There are some rules, like this one, that would best be housed in the same place as the data and other entity logic.
If it were done that way, I wouldn’t've had to bother this co-worker and waste valuable time.
This defense wasn’t flying, and I wasn’t satisfied with the reason. Bewildered, I prodded this co-worker for why it was done this way. Was there a financial deadline to meet? Inadequate analysis and design? Legacy code?
I was met by blank stares, so I presented an alternative to bring the differences into contrast: gee, I don’t know, group the functions that operate on the data with the data itself — you know, object orientation.
“Oh yeah,” she said. “This is the SOA code, so it is service-oriented.”
I gave up there as the horrible truth was revealed: the mantra of SOA was being used as an excuse for domain anemia.
What is going on here is that the domain logic is being kept everywhere but the domain layer: “business process” logic is kept in a thick layer of services, and “entity” logic is kept in the database.
I can sort of understand where this came from. In typical Web Services SOA, an application that is already built will establish some kind of SOAP or XML interface with which to respond to requests.
To do so, it has to flatten any three-dimensional objects it may use internally. By trading documents in plain text, the data can be re-used by many different services.
If you are not in the world of Web Services, you might then want to apply the same principle. Instead of flattening into SOAP or XML, pre-emptively flatten into dumb bags of getters and setters. Keep all the meaningful methods in a separate layer of services so that the dumb bags of getters and setters can be re-used by many different services.
(that is what your shitty entity class looks like to me — a bag of crap)
In both cases, an additional justification is that the logic that lives in the services may change much more often than the structure of the data. So it is only natural to separate them.
This is wrong. SOA is not an excuse to write procedural Java.
If you have parts of your domain that are going to change, separate them within the domain layer. Just three examples follow.
(so you’re so worried about change — and eventually this is all you’ll have left)
Seriously, if you’re so worried about services re-using just the data, then define some Bounded Contexts and build up an Anti-Corruption Layer that will isolate your procedural wasteland from the evils of objects with behavior.
There is almost always certain domain logic that is common to a domain object (part of a Core Domain or Shared Kernel), and that logic will be valid regardless of the context. There is no excuse to rip this logic out and stuff it in some godforesaken class in a separate package, leaving behind a smoldering wasteland of classes that are mere skeletons of their former selves.
Your SOA layer is built on top of your application layer or your domain layer, and is kept thin. It should get its work done in terms of the services / entities / repositories of the layer immediately below it.
I don’t buy this ridiculous argument that the logic is so volatile that it has to be kept absolutely separated from everything else. It is a lame cop-out that old procedural junkies who don’t grok objects use so they don’t have to think.
I don’t blame them. Object orientation is hard. Actually, I do blame them. That is what this post is about. Sometimes it seems like I’m the only one who wants to do things the right way.
As it stands right now, I have to navigate the package structure to maybe find the associated services that operate on some entity class. And guess what? A lot of services are always operating on the same data. So there are certain pieces of logic that operate only one certain pieces of data. Coincidence? Sound like something familiar?
It turns out that someone in the surrounding cubes overheard my attempt to understand why the code was designed in a procedural way that ignored the company’s layering standards, got offended, and complained to my boss. I had to hear about this from my boss and my boss’s boss. Apparently, I have to earn respect by getting work done, so that when I discuss such topics, people will “know me” and “have respect” for what I have to say.
Excuse me. You are not your code. Are these people really so insecure that they get attached to their code that is nearly guaranteed to change in the future? It’s like I’m Sarah Palin and they’re Barack
I was trying to learn because they aren’t giving me enough work to do and they know that because I told them. So how can I earn respect by getting things done if I keep asking them for stuff to do and they come up empty? They tell me “play with the code” or “read documentation”.
Well, that’s what I do, and questions about the design of the code is what I have questions about, and here we are, back where we started. You can’t have it both ways!
So whatever! If they want me to keep my mouth shut and to continue on this course, I am more than happy to do so and watch them do it.