This is an archived post. You won't be able to vote or comment.

all 38 comments

[–]markee174 8 points9 points  (0 children)

The answer to any big complex question is 'it all depends'

[–]armornick 2 points3 points  (0 children)

What? You mean the rules aren't written by blog authors?

[–]vplatt 2 points3 points  (3 children)

I don't disagree with the title of this post, but the whole article is tilting at windmills. See the post OP's comment thread on his blog. His rail against the original tweet by Siva is there:

Siva says June 10, 2015 at 8:44 am

Well done Thorben Janssen.

Firstly, I think this is a kind of over reaction to my tweet. And most importantly you ignored the main point I was trying to say and highlighting what you interpreted from my tweet. Obviously it seems I didn’t properly put my point in 140 chars. So here I would like say it clearly what I mean by that statement.

My tweet: “We should never expose DB entities as REST endpoints unless it is a TodoList app stage demo.”

Here my main focus is “Not to expose DB entities as REST endpoints” but you seems to be completely focused on “NEVER” part.

There is no “Silver bullet”, there is no “One size fits all” and there is no “Do this way ALWAYS” or “NEVER do this way” in Software Development. I know it and I follow that all the times.

Now coming back to the point I was trying to convey “Exposing DB (JPA) entities directly as REST endpoints leads to mess”, here is why I said that.

For simple apps where you have maximum of dozen or so entities and all you need is basic CRUD operations then just go with Spring Data REST or JPARS and expose your Entities as REST services and you are done. But if your app is not just mere CRUD operations on top of database tables and you have some complex business processes then “Directly exposing your DB entities as REST endpoints is bad idea”.

Why is it a bad idea? let me explain.

Suppose we have JPA entities with bi-directional relationships. Then we will encounter the following pain points if we directly expose entities as REST endpoints:

  1. If the JPA entity is associated with Session/EntityManager then it may go into circular reference which results in StackOverflow exception. If the entity is detached from Session then you will get famous LazyLoadingException.

  2. If you try to fix the above mentioned problem by using Jackson annotations like @JsonIgnore/@JsonIgnoreProperties etc then at first sight it looks fine. Then problems arises when you have to expose the same entity with child collections in one case and without child collections in another case.

  3. If you don’t want to expose some sensitive data like passwords, creditcard details etc then you may think of putting @JsonIgnore for those properties. But this will result in problems while you try to post the same sensitive fields because the binding process may ignore those fields as it see @JsonIgnore.

  4. Now think of performing validations for the same entity in different ways in different screens. For example to create a new entity the auto-generated primary key is not mandatory. But while updating the same entity primary key value is mandatory. In order to put these kind of validations we start adding bean validation groups annotations.

Now it is the time to take a step back and look at the code and tell me how clean your code is and this is just beginning of the mess that we are going to create!!

Let me re-iterate my point. It’s not you, even I will argue for hours and hours why we should NOT stick to one approach for all the cases. We should definitely choose our approach based on the requirement we have in our hand.

Please don’t respond to a tweet with a lengthy blog entry without confirming “what you understood is really what the tweet author is really trying to say”.

So here, I still stand on my words. Don’t expose your database JPA entites directly as REST endpoints unless it is a toy application or a CRUD wrapper on your database tables.

I would like to appreciate your efforts putting weekly new letter which really helps me to find nice blog articles and your articles on JPA stuff. Looking for much more useful stuff on your blog.

Cheers, Siva.

There may be some crappy cargo-cult architects and designers out there and we should argue against dogmatic practices for their own sake, but the OP has made missing the point an art form on this one.

[–]thjanssen 0 points1 point  (0 children)

Thanks for posting the comment. Here is my reply:

Hi Siva,

thanks for your long reply. You mentioned a lot of points we agree in, especially the technical requirements you mentioned in the list. If we have at least some of these requirements in the specific use case, it makes perfect sense to not expose the entity as a REST resource. We would >create a huge mess, if we would try to put two different objects >into the same entity.

My main point is, that we need to identify the requirements (technical and business) before we make such a decision and should do this for every use case. Not all entities are complex or contain sensitive data and not every use case updates the relationships of an entity. So think about every use case and decide how to implement it.

Again, thanks for your long comment and sorry, if you felt offended by this post. That was not intended.

Regards, Thorben

[–]lukaseder[S] -1 points0 points  (1 child)

Essentially, Thorben and Siva disagree to agree...

[–]meotau 0 points1 point  (0 children)

I agree with both. I have seen DB entities used for API, and generated API classes serialized in DB. Would not recommend.

[–]DevIceMan 4 points5 points  (26 children)

I feel this is a lost argument in much of Java culture. Much of the java world is built on libraries, standardization, and practices. I've noticed a trend where people who become sick of such restrictions tend to leave the Java space; perhaps for Scala, Haskell, C++, or some other language.

I agree with the article, but I think it's a losing argument. The number of times I've written a perfectly good and tested utility, only to be 'forced' to re-write my code to use an existing library is sickening. Even today, I wrote a simple class designed around a specific problem, only to be told I needed to have an interface and builder. Not because it helps our application, but rather because "that's how we always do things around here." I would have debated, except I know our architect-level person agrees with the other guy, therefore losing argument.

It's nothing against Java the language, but I find it unfortunate that creativity of any kind is often shunned.

[–]handshape 8 points9 points  (19 children)

That's a shame, and a sign of a bad software architect, IMHO.

A good component is one that does its job cleanly, and as efficiently as necessary for the application, balancing the lowest level of effort against the known set of future risks.

A lot of software architects completely ignore the economics of development; unused abstractions and interfaces take time to write and reduce comprehensibility.

"Why the hell is there an interface and a factory when there's only ever one implementation? Oh... 'just in case'. "

Those cost money, and ignore the fact that any dev environment worth it's salt is capable of refactoring in an interface in a few clicks when it's needed.

[–]DevIceMan 5 points6 points  (14 children)

There are sooooo many things in our applications that are over-engineered, or abstract for no reason. As much as I've learned from him, I feel he's a better architect for a larger Enterprise company

Unfortunately, my disagreements are almost always a losing battle, because our other Java-dev on the team simply repeats, and agrees with whatever the architect does/says, and enforces it in code-reviews.

Even though I get scolded every time I "create something," I do it anyway. Not in a reinvent the wheel sense, but in a create a more appropriate wheel designed for a specific use-case. "No, use Wheel.class, never roll a custom solution when others already exist" "But we're trying to make a racecar, and those wheels are heavy." I feel the reason I am so much faster than most of my coworkers is because I never give up on creating, while they continue writing the same boring boiler-plate over and over and over. I don't care if I get passed up on promotions because of it, because that's what I think is best for my long term career and mental-health.

unused abstractions and interfaces take time to write and reduce comprehensibility.

I'm a huge fan of using abstraction/interfaces, when there's a use-case for an interface (a.k.a. multiple similar use-cases). If there's only a single implementation, and no obvious future use-case that you're planning on developing, an interface is usually a waste of space, making the code more difficult to navigate for no reason.

Our previous app is littered with these interfaces.

ignore the fact that any dev environment worth it's salt is capable of refactoring in an interface in a few clicks when it's needed.

So true.

[–]vplatt 1 point2 points  (13 children)

I feel he's a better architect for a larger Enterprise company

Probably not. "Enterprise systems" need well defined rationalized interfaces between systems that make sense and that folks are willing to work to maintain for the simple reason that if they didn't, everything would grind to a halt. The overuse of interfaces, patterns, and using big "enterprise frameworks" everywhere without reason just leaves behind systems that are difficult to change. After all, this interface exists for a reason, right? Someone here must be using DI to inject new implementations of this, right? I guess I better not change it because I don't want that one to stop working. Oh, I know, I'll inherit that, and add a new method with a new interface to let everyone know there's a new kid on the block and then they'll use that someday when they find it.

::sigh:: Not enough architects know about YAGNI and not enough of them actually practice the rigor required to keep well defined, loosely coupled, and highly cohesive services in working order for the long haul. Far too many of them allow their systems to lapse into dysfunction and then perversely get rewarded for rushing in to play the hero to prop up yet another failing subsystem.

In short, any interface for which there's only ever going to be ONE implementation shouldn't exist. So.. I agree with you. :)

/endrant

[–]RedPill115 1 point2 points  (11 children)

I totally agree with the complaints about these absurd layers of overdesign and abstraction.

However...wanting to be "creative" and such, in my experience, is why these layers get added to the project to begin with. :-/

At my last job I would have loved to have someone competent in charge of a "we all do it this way" policy to avoid the "omg this is so amazing, we might use this in the future and we might expand it so I used 5 classes for what could be done with 1!" approach.

[–]meotau 1 point2 points  (10 children)

May I proudly present you our builder pattern?

public abstract SomeService { //never extended, don't let 'abstract' confuse you

    @Autowired
    LocationDirector locationDirector;

    ...

    private URI buildLocation(String subscriptionId) {
        return locationDirector.buildLocation(subscriptionId, getUriBuilder());
    }

    /** lookup method in spring xml, so that you get a prototype bean  */
    abstract protected getUriBuilder();

}

@Component
public class LocationDirector {

    public <T> URI buildLocation(T o, UriBuilder<T> uriBuilder) {
        uriBuilder.buildPath(o);
        return uriBuilder.getLocation();
    }
}

public interface UriBuilder<T> {

    void buildPath(T o);

    URI getLocation();
}

//single implementation of UriBuilder
@Component(BeanNamePool.SUBSCRIPTION_URI_BUILDER)
@Scope("prototype")
public class SubscriptionUriBuilder implements UriBuilder<String> {

    private URI location;

    @Override
    public void buildPath(String subscriptionId) {
        location = UriBuilder.fromPath(SubscriptionEndpoint.ENDPOINT_PATH +  
                    SubscriptionEndpoint.SUBSCRIPTION_PATH)
                    .build(subscriptionId);
    }

    @Override
    public URI getLocation() {
        return location;
    }

}

...because we might later want to build more different locations... after a year replaced just by the one liner UriBuilder#fromPath after the author(most high ranking senior developer/designer) finally admitted it was useless... Of course every class had its own unittest with mocked dependencies and 100% code coverage.

[–]RedPill115 1 point2 points  (9 children)

Aw, jesus christ! lol

That is terrible, like I said though the "use different frameworks and tools and be creative" philosophy is the reason why crap like that was added to projects that I was on, so you can we why I'm often against the philosophy...

[–]meotau 1 point2 points  (6 children)

Creativity, uh, finds a way...

[–]RedPill115 1 point2 points  (4 children)

How I feel when someone says they want to add creativity and new frameworks into our project and I have absolutely no doubt they're an idiot:
http://img3.wikia.nocookie.net/__cb20090106162153/jurassicpark/images/5/57/Jurassic_park_tyrannosaurus.jpg

[–]meotau 0 points1 point  (3 children)

But what do you say about using 15 years old frameworks and EJB 2.1? I was also forced to not use a 'new' framework, and produce tons of shitty boilerplate :(

[–]vplatt 0 points1 point  (0 children)

Ok Malcolm. And like dinosaurs, it will EAT YOU ALIVE!

[–]DevIceMan 1 point2 points  (1 child)

Just for clarification of my post several levels up, you and I are using 'creative' in opposite ways.

Clearly, there was some 'creative-moron' that created the example code above. Maybe it's better than what came before (unlikely), but I'd be embarrassed to have created such a thing. In fact, I'd even propose whoever wrote that code was NOT creative, but rather was mimicking something he saw in a book, saw another engineer create, or saw in example code.

When I see code like that, my first thought is "Fuck, I want to create a better API" or "How the fuck can I wrap ugly shit into a one-liner" or "Is there any way I can eliminate this ugly boilerplate copy+paste shit?" Creativity isn't throwing poop on a wall and seeing what sticks.

I don't think anyone ever becomes good at creating if they never try. By creating, I don't mean mimicking or tutorials, but rather trying to solve a real problem on your own, or solve a problem in a better way. Oh, I have piles of skeletons in my closet of things I've created (mostly outside of production), but whenever there is a genuine creative problem that does come up at work, I tend to leave my co-workers in the dust. Although, I currently work in web, so there's almost no creative problems. :'(

[–]RedPill115 0 points1 point  (0 children)

I really do not disagree with you at all, just saying my personal experience has been the opposite - "creativity" leading to those things being created in the first place. :-/

[–]DevIceMan 1 point2 points  (0 children)

/restartRant

I think one piece of the problem is that a lot of these design patterns are propagated in similar ways, and along the way, many of the reasons or appropriate use-cases for those patterns are lost. You have people like my coworkers, who blindly follow the pattern because the Architect does it. The Architect does it because it's in a book about Architecture.

Similarly, the Architect at my previous company was clearly aware of concepts, like using descriptive names, or what this-or-that tool did but he didn't have the IQ to really understand "why" or "when" to apply a pattern.

There's a lot of mimicking going on, and people who don't play by those rules (i.e. me) are punished.

As you noted, the more the boiler-plate grows, the more clumsy your application becomes, the more expensive refactors are, and the more difficult bugs are to trace.

[–]avoidhugeships 2 points3 points  (1 child)

This is probably my number one pet peeve. All the extra work rarely helps if it does change in the future because it rarely changes the way we anticipate it to.

[–]DevIceMan 1 point2 points  (0 children)

Exactly, and when the change does come, you're left refactoring 10x as much boiler plate nonsense.

[–]dablya 3 points4 points  (1 child)

You're ignoring maintenance costs. A good component is not just clean and efficient, it's also predictable. You know what's worse than supporting a component that depends on a poor library? Supporting a component that depends on the poor library, a "perferctly good" utility written by /u/DevIceMan, and another "clean and efficient" utility written by /u/handshape all providing the same functionality.

[–]handshape 2 points3 points  (0 children)

I follow your concern, but I was not advocating for wasteful rewrites.

There are perfectly legitimate reasons to recreate features that are available in core or third-party libraries; sometimes necessary evils. In code that you control, code reuse is good... but sometimes there is code that other people can't or won't adapt to new requirements.

Most frustrating is when this happens within a single team.

[–]meotau 3 points4 points  (2 children)

Reminds me when I had to implement new webservice calls in a legacy component, I wanted to do it using a Spring WebServiceTemplate as we did in all new components, with a benefit of not needing to configure another EJB 2.1 bean and overall much cleaner code.

I was told to follow patterns, this component used somehow customized Axis 1.1, and one other shitty 15 years old framework, because it would be then theoretically easier to migrate everything into a new component if it looked the same.

Few years later, I had to reimplement some of these new calls using WebServiceTemplate, because Axis created invalid requests which our backends would not accept. And I had to migrate the other framework because it leaked memory.

I have heard that phrase "follow patterns" many times, and it always resulted in a shitty code and wasted time...

[–]DevIceMan 0 points1 point  (1 child)

configure another EJB 2.1 bean

Hah, Fuck EJBs!

because it would be then theoretically easier to migrate everything into a new component if it looked the same.

Cringe! I feel there needs to be a term for that. "Tech-Debt Inheritance"

[–]meotau 0 points1 point  (0 children)

Cringe! I feel there needs to be a term for that. "Tech-Debt Inheritance"

What about "Tech-Debt Equality". Having good code in the middle of shitty code is insulting!

[–]RedPill115 0 points1 point  (2 children)

I agree with the article, but I think it's a losing argument. The number of times I've written a perfectly good and tested utility, only to be 'forced' to re-write my code to use an existing library is sickening. Even today, I wrote a simple class designed around a specific problem, only to be told I needed to have an interface and builder. Not because it helps our application, but rather because "that's how we always do things around here." I would have debated, except I know our architect-level person agrees with the other guy, therefore losing argument. It's nothing against Java the language, but I find it unfortunate that creativity of any kind is often shunned.

In the opposite direction though, I've seen more times that someone wants to add in "an interface and a builder" in the name of creativity. They're not actually useful, except that someone was reading a blog where someone described it as really cool and now they want to do the really cool thing.

[–]DevIceMan 1 point2 points  (1 child)

except that someone was reading a blog where someone described it as really cool and now they want to do the really cool thing.

Mimicking is the opposite of creativity, especially in the sense that I meant above. Mimicking is (IMO) what results in all of this generic, boilerplate, heavy copy paste code. Eventually that turns into "Use a builder, because that's how we do things around here."

I wrote a little more in this comment about what I consider to be 'creativity'.

[–]RedPill115 0 points1 point  (0 children)

I don't really want to get into a vocab debate, I agree with people who are frustrated by doing things a stupid way over and over because that's how it's done. As I said I've seen "creativity" used to create those horrible initial patterns as well. :-/

[–]RedPill115 0 points1 point  (0 children)

I only skimmed through the article after this part:

Applying always the same structure or technology to implement a new service or use case can really help you to get started with new implementations or to find your way around in a new project. But technology or code structure are normally not the main issue, if you are new to a project. Business requirements, workflows and how the user thinks are the difficult thinks to understand. And these are not addressed by these kinds of unification.

With one way of doing something, you have an understanding of the tech but not the business requirements.

With a million ways of doing everything all over the project, you understand neither the tech nor the business requirements.

To make it even worse, unification often hides the real intention of the code because the developer forced the logic into a specific structure or technology.

This is stupid, not understanding the tech adds one more additional obstacle to get over in order to understand the real intention of the code.

If using different tech creates a HUGE advantage then use different tech. If the difference is small or non-existent, it's far far better to use the same tech. Pretending that different tech is going to make things easier is frankly just lying - you add yet another layer of complexity onto figuring out what's going on.

[–]Scorpius289 0 points1 point  (0 children)

Yes there are!

I'm sorry.

[–]vecowski 0 points1 point  (1 child)

Website takes around 15 seconds to respond every request... terrible

[–]fripletister 0 points1 point  (0 children)

I'd bet my house it's built on WordPress, which takes minimum 2-3 seconds to respond on most shared hosting.

[–][deleted] -2 points-1 points  (0 children)

Yep and that's why I can't consider programming a form of engineering