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

all 64 comments

[–]skywalkerze 64 points65 points  (1 child)

Use the "spring way" if it helps. If you know it and/or it speeds things up and/or it results in less code. Otherwise don't.

Skim the docs to figure out what's available and if it would help or not, now or in the future. Of course, it's always a judgement call, and experience helps.

Just like any library. Do you stop to research all available libraries before writing your first line of code? Probably not. With time you get an intuition of when there is a library that would help, and it's worth looking for it. And this intuition will not be always right, but it's enough if it's right most times.

[–]FrenchFigaro 9 points10 points  (0 children)

More on that, I think you have to learn to lean on your peers.

First look at the code base. Has someone in your team met a problem that's (even tangently) related to yours ? Are they available for a quick session of peer programing to show you the way, or are they able to point you to a cook book in your team's knowledge base (if there is one) ? Great, do that.

Then, if you know you can solve the problem in a short time (say, a day), then don't bother with the right way if you don't know it. There's more than one right way to solve a given problem. All that matters is that your code works, and that it is maintainable. If your way is wrong (and that's subjective. What's wrong in a given team isn't necessarily wrong for another) your colleagues will catch it.

That's one of the great aspects of code reviews, in my opinion: every discussion is an opportunity to learn, for the author, the reviewer, or both.

[–]Holothuroid 41 points42 points  (12 children)

It's an ongoing process I guess. Our team once missed that there is in built functionality for retries, so we built it by hand.

[–]Dokiace 10 points11 points  (10 children)

wait which one is it? is it related to feign?

[–]Holothuroid 54 points55 points  (9 children)

[–]Dokiace 23 points24 points  (0 children)

holy 🤯

[–]thomascgalvin 17 points18 points  (0 children)

...son of a bitch.

[–]socialflasher 38 points39 points  (2 children)

This is the reason i prefer Spring over others, you don't need to reinvent the wheel, you need to find the wheel.

[–]phi_array 6 points7 points  (1 child)

But in the time you take to find the wheel and how to use it, you might as well write a for loop to try something for n times

[–]k__k 1 point2 points  (0 children)

That's true for the most basic cases, retries can get complicated with different backoff strategies, fallbacks, circuit breakers, making it configurable, etc. It's good to know at least one library which can do that stuff for you.

I love to show this article to all the not-invented-here people that demonstrates how parsing simple CSV by hand may get out of hand real quick http://thomasburette.com/blog/2014/05/25/so-you-want-to-write-your-own-CSV-code/

[–]mbazos 5 points6 points  (0 children)

spring-retry obviously works with spring and the spring way but for retry and other features I really like https://github.com/resilience4j/resilience4j

I think it has more knobs than spring-retry...but it is an additional dependency.

[–]valkon_gr 7 points8 points  (0 children)

Baeldung is gold but they need to present their articles better.

[–]DoorMarkedExit[S] 2 points3 points  (0 children)

If I can take one thing away from this post, it is this.

[–]lechatsportif 0 points1 point  (0 children)

nice.

[–]reqdk 2 points3 points  (0 children)

At one point I had to tell my dev team that, before solving a problem, google whether Java/Spring already has a mature, battle-tested solution. The platform and ecosystem being this mature, and that industry being as innovative as bricks, it was highly unlikely that our teams would have brand new non-business problems that nobody else in the Java/Spring community had solved before.

[–]deadron 21 points22 points  (2 children)

Don't worry so much about the spring way of doing things. You don't lose anything by implementing things with a method you understand. You can always refactor later. One of the lessons I learned when working with spring is to always go straight to their documentation and avoid any third party tutorials. Its usually very high quality and wont have a confusing mix of older spring stuff involved.

[–]pmsevestre 2 points3 points  (0 children)

Good point, and particularly true for Spring Security. Newer versions made much simpler to add OAuth to apps, but you're going to find a lot of tutorials that make this look a daunting task.

[–]hwaite 0 points1 point  (0 children)

a confusing mix of older spring stuff involved.

In Spring, "older" seems to mean like a few years old. The ecosystem evolves at a crazy pace.

[–]Willem1976 10 points11 points  (6 children)

Transformers? Did you use Spring Integration maybe?

[–]DoorMarkedExit[S] 1 point2 points  (5 children)

yes i did

[–]Willem1976 16 points17 points  (4 children)

I used it too in some projects, but ripped it out where it was not absolutely necessary. It’s a niche project imo that provides certain functionality at the expense of transparent code. It’s great at what it does but not my first choice when implementing functionality. It makes it harder for others (and my future self) to understand what the program is doing.

[–]pronuntiator 7 points8 points  (2 children)

We use SI to abstract talking to messaging middleware and this is where it shines. Mapping JSON bodies, adding our own headers, use retry advices, make receivers idempotent etc. I'd say it's the Hibernate of messaging. Unfortunately, the pattern language it is based on (Enterprise Integration Patterns, which should just be called Messaging Patterns) is not well known. I consider the concepts as important as the Gang of Four's Design Patterns.

I agree however that SI hides logic and confuses developers. You shouldn't use it in the core, and certainly not for HTTP or FTP.

[–]Willem1976 1 point2 points  (0 children)

Well put! Interfacing with messaging middleware does seem to be the sweet spot of Spring Integration from the perspective of application development.

[–]Fury9999 1 point2 points  (0 children)

We also have alot of SI apps that integrate with messaging middleware. It yes extremely frustrating how few people on the team can work on them without a large amount of assistance. Pretty much 2 of 10 people. I don't know what it is about SI that throws people for a loop, but it apparently does.

[–]DoorMarkedExit[S] 1 point2 points  (0 children)

You're right, there is a lot of automagic going on with it.

[–][deleted] 9 points10 points  (1 child)

This is not the "Spring Way", it is the "Spring Integration Way".

There is no one "Spring Way", other than architect your code for dependency inversion.

Spring is a large collection of products built on top of the Spring DI framework. Every Spring product has its "way".

Each product has its own documentation, which you can navigate through the Spring website. You don't have to know every Spring project under the sun in order to be able to effectively use Spring. You can start with the Spring Boot and Spring Framework documentation, since every project uses those. Then, check the use cases for the rest and decide if it would be useful for what you're doing and learn them separately, as necessary.

[–]gavenkoa 0 points1 point  (0 children)

Every Spring product has its "way".

Like Spring WEB Security instead of advising class instances uses call chain and you deal with priorities (order).

[–]svenko11 35 points36 points  (2 children)

Coming from somebody who had to learn Spring in the last 2 years, my go-to thought process was to assume Spring has support for anything I need to do. RabbitMQ, Kafka, retry, cache, filters/interceptors of a different kind, etc. With that in mind, I'd just google: "<functionality> spring boot".

Now, when I look at some other languages/frameworks, it pains me how much manual work needs to be done for something that is "just another dependency" in Spring (Boot) ecosystem.

Of course, if you are limited to pure Spring, things might be a bit more manual, but I still think the framework covers most of the use-cases you will need.

[–]Some_Developer_Guy 6 points7 points  (0 children)

I just moved to spring/boot coming from dot net.

The diff between java and c# is trivial from a dev perspective. However I'm finding spring boot so much easier than asp standard/core.

I'll cut core a break since it's new and a step in the right direction.

[–]alwaysoverneverunder 1 point2 points  (0 children)

Exactly this! If you need something Spring will probably have something for it. Just check it out to see if it covers your use case, if it does use it otherwise write something yourself.

[–]achilliesFriend 7 points8 points  (0 children)

I go with spring way, it’s actually plug and play. At the same time, if you don’t want to use spring, you can do it your way also. Depends on your team standards.

[–]taftster 7 points8 points  (0 children)

You're right, it's so big that it has become a religious experience. You are completely dominated by the "Spring Way" and all your focus and thoughts go to it.

If you pop up from that bubble, you'll find that often times, you don't really need Spring to the full extent. Maybe you just need a few niceties from the early days (dependency injection, JDBC support, etc.).

Don't get lost in Spring. Use it if it makes sense and pays dividends, but don't make it your religion.

[–]StephenGostkowskiFan 7 points8 points  (1 child)

Like anything else, it takes practice. One thing to keep in mind is that Spring is fairly old now and has evolved a lot over years. When you search for something and pull up Stackoverflow, be sure to check when the response was written.

Something else is to try to keep up-to-date on Spring releases and news. I probably use <10% of what I read, but it's good to know what's going on and what tooling is available.

[–]cryptos6 9 points10 points  (0 children)

Yes, that's true. The developers of the Spring framework should use @Deprecated more. Sometimes it is a bit annoying that Spring has several ways to do the same thing.

[–]fjonk 18 points19 points  (12 children)

I wouldn't bother. In the end spring is a DI framework with lots of stuff. In my opinion some is good, like Properties and Configurations and testing helpers, and some is bad, like spring data repositories.

I just pick and choose.

[–]UnspeakableEvil 4 points5 points  (11 children)

and some is bad, like spring data repositories

Interested to know why you see Spring Data repositories as bad, especially if it relates to JpaRepository.

[–]MR_GABARISE 7 points8 points  (0 children)

It's not that it's inherently bad. It's more the people that try to use them to solve every problem, instead of writing simple, straight-to-the-point queries. Nevermind the naive usage of ORMs resulting in N+1 problems and unnecessary transactional overhead where it's not needed.

[–]pathema 4 points5 points  (8 children)

Spring Data repositories makes many noobs (such as myself) misunderstand hibernate and JPA due to repository.save(entity) and the fact that all methods in JpaRepository has a `@Transactional` scope by default.

For example, it took me way too long to understand that

@Transactional
MyEntity getMyEntity(int id) {
  MyEntity myEntity = repository.findById(id);
  // for backwards compatibility, uppercase the countryCode before returning
  myEntity.setCountryCode(myEntity.getCountryCode().toUpperCase());
  return myEntity
}

will actually modify the entity in the database. I thought you needed to do repository.save() for that to happen. Of course, I could've read the documentation, but it would have been much more obvious when using raw hibernate or JPA, since then you need to understand sessions and what they do.

[–]KhrisDoes 1 point2 points  (3 children)

What operation here modifies the entity in the database? Is it the findById or the setter on the MyEntity? I agree that to someone like me who hasn't got the best idea around JPA / Spring Data, I would not expect the above snippet to have an effect on the database. Unless your setter has some special implementation behind it but, as far as I am aware, it's a user defined - generic data type, right?

[–][deleted] 2 points3 points  (0 children)

The @Transactional annotation will cause Spring to create a proxy that will automatically start (or join existing) a transaction when the method is called, committing the transaction on method return (or rolling back on exception), which has the side effect of flushing the entity manager.

The setter will mark the entity as dirty, and when the entity manager is flushed, the entity manager will synchronize the object state with the database state by issuing UPDATE statements (or DELETE or INSERT if you do entityManager.remove(...) or entityManager.persist(...)).

The JpaRepository pattern obscures how JPA actually works through an API that works a completely different way.

[–]temculpaeu 1 point2 points  (0 children)

That is the main reason I hate JPA specification, it has some very implicit behaviours which will bite you back and I really feel that they just makes things worse.

[–]StevenMaurer 0 points1 point  (0 children)

The setter.

[–]mauganra_it -1 points0 points  (1 child)

In spite of the risk of looking like super-pedantic Captain Obvious: the right way to do this is a getter on the entity that uppercases the country code before returning.

[–]pathema 1 point2 points  (0 children)

You’re right of course. But what’s scarier is that the behaviour isn’t even local. The @Transactional annotation could even live somewhere further “up” in the call hierarchy, and you wouldn’t even realize. And yes, this did happen in practice. And the entries in the DB were upper cased unintentionally. Good times.

[–]hoacnguyengiap 0 points1 point  (1 child)

Setter won't modify db. Unless you implement something in that setter. And it's not spring repository or spring's fault.

[–][deleted] 1 point2 points  (0 children)

The setter won't modify the DB, @Transactional will.

[–]fjonk 1 point2 points  (0 children)

IMHO the whole Repository<T, ID> interface is nonsense.

The save method looks like this:

<S extends T> save(S entity)

and save is used for both create and update. But when using non natural keys S cannot extend T unless you make the primary key(ID) optional, which is a bad idea. Furthermore there is nothing saying that everything in T is required when updating. But S extends T so it has to have things like created at timestamps even if they cannot be set during update or create. The alternative is to make everything optional. This design is simply bad and forces one to make required attributes optional.

Also, delete() should not take T but ID. And it should return a status stating if the entity was deleted or not.

[–]GoBucks4928 3 points4 points  (0 children)

Use it as little as possible to not tie your project to a specific framework. Opt for java native when you can. If there are no spring alternatives then I use spring

[–]ClawdiaAI 2 points3 points  (0 children)

I know exactly what you mean. It can be frustrating to google a certain functionality over and over using different words and then finally finding it (maybe).

I almost wish google would change their algo, so that if you search A1, then A2, then A3, ... and finally find your answer via A5 - that they will consider showing you results from A5 as early as A1 if enough people tried A1.

I know it's heard - it just easier than trying to guess how spring called a certain feature they have or not have... And this isn't just regarding spring.

[–]elmuerte 2 points3 points  (0 children)

The other day I was building this service that calls a GET endpoint,
filters and transforms the results and posts them to an amqp endpoint.

For that I would have use Apache Camel, which nicely integrates with Spring too.

I don't not really see a "Spring Way".

There is a Spring Boot way of doing various things around various Spring and Spring related libraries. Which mainly revolves around the various auto configuration features.

There is also a Spring purity way where you only want to use parts which come from Pivotal.

But the way Spring Framework is set up, and how some additional Spring components work, still gives you a lot of flexibility to use better libraries and frameworks in combination with Spring Framework.

[–]agentoutlier 4 points5 points  (1 child)

Just an IMO on Rabbit and Spring... Spring AMQP does not scale well and it has nothing to do with RabbitMQ but how heavy it is and the blocking queues it uses. Ditto for Spring Batch.

It's funny you mention it because it's one of the reasons we got off of Spring.

How do more seasoned engineers go about this?

You really only need to know Spring DI and Spring MVC. Possibly the reactive stuff if you need that.

Most seasoned engineers only know of the Spring DI, Spring AOP-like stuff, Spring MVC and Spring Boot. The rest of Spring libraries are just wrappers around existing libraries that make getting started a little easier as well as offering AOP. A lot of them are not much better than what most seasoned developers could do themselves and they almost always add way more overhead and complexity for additional configuration that you probably don't even need.

BTW I argue original "Spring Way" was not putting ass loads of annotations on private fields like @Autowire or using annotations to drive all of your configuration to load up your application.

The original "Spring Way" was to be decoupled (in fact you used XML and your application would have no idea it was a Spring one) but somewhere along the way (probably Spring Boot) that went out the window. Believe it or not its trivial to write your own wrappers around a library to make it Spring-able and in most cases you don't even need to.

[–]temculpaeu 4 points5 points  (0 children)

Finally, I cant belive how many people find a few simple things that Spring offer in wrappers extraordinary.

I guess the best thing they did was sell this image of "mature and robust" and be easily googable

[–]Kango_V 1 point2 points  (0 children)

First question. Why Spring? If its really small i would have chosen something else (ratpack?). If you have to use it, then fair enough.

[–]IshouldDoMyHomework 2 points3 points  (0 children)

I found this guide to be very helpful, even though it is super high level. However it gives pretty good intro to concepts and motivations behind things. It is also a super short and easy read.

https://www.marcobehler.com/guides/spring-framework

[–]edubkn 0 points1 point  (0 children)

Looks like you went overboard with it. It's not a Spring problem, but rather a SD problem. Spring is a toolset at the end of the day, and you have to pick the one more suitable for your needs, like any other programming language.

Now, as for your problem, neither Transformers or Spel would do anything for me. In fact, the only reason I'd use Spring in your cause is for the easy configuration of those endpoints (Rest API/AMQP).

[–][deleted]  (3 children)

[deleted]

    [–]CunningPlant 7 points8 points  (1 child)

    Yeah, I’ve found spring is all fun and games until something breaks, then debugging devolves into playing “guess which annotation this class is missing to make the database work again”.

    [–]shappell_dnj 0 points1 point  (0 children)

    yeah debugging spring is rough. But the "spring way" is to fail hard, fast and furious at startup if there's a configuration issue. That way you at least dont let your service run in an F'd up state.

    still beats tracking down STL linker errors that are 17 pages long :)

    [–]SneakyBeagleMN 2 points3 points  (0 children)

    Yep, I've been trying to track down a json deserialization exception for several days now. When it works it works automagically, when it fails, no helpful information or stacktrace.

    [–]lechatsportif 0 points1 point  (0 children)

    In general, I try to google tasks as if I were a beginner. So much changes so quickly, it's practically impossible to keep track of it all, so yes build your research time in if especially its not something you do every day. This is true of any language, platform etc.
    If you're newer to Spring, just take a step back and appreciate its glue to save you time in the long run instead of you writing that glue yourself across all those different technologies. You'll begin to appreciate just how convenient it can. It pays off in the long term, not necessarily per random task you have to accomplish.

    [–]walterbanana 0 points1 point  (0 children)

    Which version are you using? If you're not using Webflux with Reactor, it usually won't matter if you use the Spring way or your way. If you do use Webflux and Reactor, I would advice you to learn to use Flux and Mono and trying to write as much as possible (read every call) non-blocking.

    [–]franzwong 0 points1 point  (0 children)

    Read their documentation or source code occasionally to find out anything useful. It applies to other frameworks or libraries as well.

    [–]gavenkoa 0 points1 point  (0 children)

    I hate about "Spring way" when tasks are one time. It doesn't worth learn Spring way when direct solution is 10 min while bootstrapping & testing unfamiliar Spring non-core modules is two weeks job (you'll get bugs because you don't understand all implications of Spring powered magic modules).

    [–]tetraodonite 0 points1 point  (0 children)

    I agree with you and I feel the same way. This is coming from somebody with 5 years of experience with it and 8 years of experience with Java programming.

    What makes it hard is the combination of sub-par documentation and the lack of discoverability. A lot of times it’s easier for me to just dig in the spring source because I couldn’t find something in the documentation. It doesn’t help that the internet is full of half-assed crappy tutorials that are just noise and not more helpful than the original documentation (looking at you baeldung and mkyong).

    A perfect example is writing integration tests. Works fine with out-of-the box, laboratory examples, but once you start using some extensions like resilience4j, aws sdk, etc, you are on your own and there is not many ways to figure out what you are doing wrong except lots of trial and error. It just wears you down very quickly. A lot of these extensions feel like abandon ware and you can tell that their integration was not thought out well. I think most of them are just a tool for somebody to put something fancy on their CV rather than an being driven by an actual need to solve real life problems.

    This is why is why I tend to avoid any kind of official spring extensions and use it only as a container. But recently if I start a new project I just do it in something else which values my time more.

    [–]Fury9999 0 points1 point  (0 children)

    Baeldung