9 ms·
I remember the days, when the Spring framework was advertised as a lightweight alternative to Enterprise java beans (ejb); now Spring outgrew the pretence of be
by MichaelMoser123 5y ago
I remember the days, when the Spring framework was advertised as a lightweight alternative to Enterprise java beans (ejb); now Spring outgrew the pretence of being lightweight, don't know when that happened. A year and a half ago, i got back to work with java and spring boot, and i was overwhelmed by the prevalence of annotations in spring boot.
To cope with all this, i wrote this little project: https://github.com/MoserMichael/ls-annotations https://github.com/MoserMichael/ls-annotations
It's a decompiler that is listing all annotations, so it becomes easier to grep a text file in order to detect the dependencies between annotations.
it is using the asm library https://asm.ow2.io/ https://asm.ow2.io/ to inspect the bytecode files, so as to extract the class signature, along with the reference and declaration of annotations included in a classpath, or class files included within a directory structure. A limitation/feature is, that it is inspecting already compiled bytecode files.
- geodel 5y agoIndeed. I have a dozen or so microservices supported by team. Most are SpringBoot a couple of them I wrote myself with plain java and embedded tomcat. Needless to say Springboot stuff is rather complicated for such a simple business functionality. Errors are indecipherable being swamped by thousand line framework exception trace. But being an "enterprise standard" framework all projects must be move to this turd of a framework.
- MichaelMoser123 5y agoAnother big difficulty is the handling of depedencies, as spring boot is bringing in gprc, jpa, jdbc and countless other libraries. One really needs a dedicated team to figure out all these issues!
- geodel 5y agoVery true! But management is sold on "best practices" from VMWare suits. So any practical difficulty is just an excuse for not learning the latest, Next generation technologies.
- kaba0 5y agoIt brings in whatever you use. Also, it has a goddamn webpage where you can click together what do you want to use and it will create an initial project for you with the chosen build tool and what not. It hardly gets easier than that.
- royjacobs 5y agoThis isn't true. Spring Boot by itself brings in very little, you can however _add_ GRPC, JPA and JDBC support by adding a library and Spring Boot will even autoconfigure it for you.
- bedobi 5y agoI'm in an enterprise and have successfully lobbied people to use anything other than Spring. Such organizations and teams while rare do exist so don't give up hope! (or just move to a more progressive org)
- heurisko 5y ago> I'm in an enterprise and have successfully lobbied people to use anything other than Spring. I was in a team that used Spring Boot for a greenfield project. The documentation was great, there was tons of help of Stackoverflow (as it's Spring) and the consideration given to testing was first class. Deployment was also easy, as we just created a fat JAR. No application server necessary. It was a great place to work.
- bedobi 5y agoI have also been in multiple organizations where Spring was used, including "modern" Spring Boot and greenfield projects, and people who knew every nook and cranny of Spring. I don't agree with any of the things you bring up. Spring documentation is and has always been poor and the sheer volume of outdated documentation (let alone ways to do the same thing) makes it needlessly difficult to find an answer to any given question. Differences between the real app and real http requests to the app, and using the Spring test application context and Spring HTTP tests, result in tests misleadingly passing when things are actually broken. (or vice versa) This is different to eg DropWizard where you actually boot the app (no different to how it does in a real env ie no "test application context") and make real http requests to it. (not some watered down fake Spring HTTP test requests) Ability to deploy a standalone jar without the need for an application server is hardly unique to Spring. Add in the horribly, horribly ingrained, unidiomatic ways people use Spring (eg sprinkling field autowiring all over the place instead of instead of using constructor injection) etc etc and every codebase is quickly completely ruined vs if it had been implemented in literally any other framework. But! Fortunately for you, the Java community has made their choice, and it's not going to change - Spring is the default and correct option, and anyone who uses any other framework is just stubborn and wrong.
- heurisko 5y ago> Errors are indecipherable being swamped by thousand line framework exception trace Don't you just look at the top lines?
- tpxl 5y agoIf you're lucky and the exception happens in your code directly. If not you're gonna have about 30 lines of interceptors and generators and whatnot before you get to your class. If you call ClassA::foo from ClassB::bar you'll get about 5 lines of interceptors between foo and bar in your stack trace. Debugging is also a nightmare in IntelliJ as step-into and step-out will go through all those interceptors.
- heurisko 5y agoI used Spring Boot and just set debug breakpoints, that way you don't have to step into and out-of, you just press "play" and it moves to the next breakpoint.
- windock 5y agoDebugging bothered me too. But in the end I have configured IntelliJ to skip all the interceptor classes while stepping into. Had to add a whole bunch of classes and packages for that though
- kaba0 5y agoAnd in 99% of cases that little microservice will suddenly need thread pooling, logging, some more advanced db management or God help some random messaging service and you are back to re-implementing the myriad features of spring in a shittier way. It is not an accident that things like ruby on rails are popular. These are well-tested toolboxes with a solution for almost every conceivable problem. There are exceptions where it is not needed, but for business applications those are not numerous.
- epse 5y agoI don't think people have any issues with the fact that spring is batteries included. It seems to me (and this is my personal experience too) that the large amounts of abstraction and indirection through annotations makes the code very hard to parse. It makes it hard to create a mental graph of how it all works together
- touisteur 5y agoLooks like an IDE / language server that unrolls the annotation generated code might be what's missing here. I like my abstractions to be hidden, but I like to be able to peek under the hood. That's one of the problems of C++ templates, sometimes I want to look at the expanded code. The GNAT Ada compiler has an option to output a much-simplified code. Not compilable Ada, but very inspectable unrolled, expanded code. Makes for a great teaching tool. Aaaaaaah this generic mechanism does that! Edit: link https://docs.adacore.com/gnat_ugn-docs/html/gnat_ugn/gnat_ugn/building_executable_programs_with_gnat.html https://docs.adacore.com/gnat_ugn-docs/html/gnat_ugn/gnat_ug... look up -gnatG[=nn]... Good stuff.
- the_gipsy 5y ago> Looks like an IDE / language server that unrolls the annotation generated code might be what's missing here. I think you're missing the point.
- stepbeek 5y agoI found the real challenge to be that it's very difficult - if not impossible - to determine how spring functions simply by reading code and using it. In simpler libraries or frameworks, I normally just read the source to understand how I should be using it. With Spring, I've had to spend a lot of time reading and re-reaading docs to understand what's going on. I think that this is sometimes a hard shift for developers who otherwise have spent their lives with an ability to puzzle out the constructs that they come across.
- pshirshov 5y ago> I have a dozen or so microservices supported by team. Why do you need a dozen of microservices? Why not to use role-based monoliths? Why not to keep your "microservices" as independent modules, pack them as one app and let such app to configure itself with proper set of services and dependencies according to the config or CLI parameters?..
- deleted 5y ago[deleted]
- geodel 5y agoJust a developer there. So not calling shots on overall architecture. And yes we do not need probably 80% of that crap but not in position to make them see reason.
- fnord77 5y agothe pernicious thing about spring is there appears to be 15 different ways to do the same thing. Everyone's idea and enhancement request was thrown in. Plus things got left in that should have been deprecated after better ideas came along or the java language improved to allow new techniques. I'm glad someone is working on a light weight replacement to spring. I had some ideas on a light weight DI framework but never got around to it.
- falcolas 5y ago> the pernicious thing about spring is there appears to be 15 different ways to do the same thing. Oh gods below this. I was half wondering if I was writing Perl with how much TMTOWTDI was floating around in the cesspool of Lombok and Spring.
- lmm 5y agoSpring Boot is not the same thing as Spring, and is indeed recapitulating all of the mistakes of EJB (I guess it's been long enough that the new generation of developers doesn't know about the problems). You can still use vanilla Spring though.
- TedDoesntTalk 5y agoSpring Boot has remoting like EJB did??
- heurisko 5y ago> Spring Boot is not the same thing as Spring Spring Boot is an opinionated way to configure Spring applications. > recapitulating all of the mistakes of EJB Which mistakes is it repeating?
- lmm 5y ago> Spring Boot is an opinionated way to configure Spring applications. If by "configure" you mean "make arbitrary changes to the behaviour of". Spring Boot adds a bunch of spring-boot-specific stuff that can't be replicated in vanilla Spring and isn't supported for use outside Spring Boot (e.g. @ConditionalOnMissingBean and friends are explicitly not supposed to be used in non-boot Spring configurations). This is a long way away from just sugar for an ordinary Spring configuration. > Which mistakes is it repeating? - Huge and incomprehensible - Components can refer to other components in ways that are completely invisible in the code - No way to understand your application's behaviour by just looking at your code, because it can vary drastically depending on the things that are instantiated by the container at runtime. (In EJB this was container-provided services, in Spring Boot it's configurations that are automatically instantiated if they're present on the classpath, without the application ever referring to them at all) - In practice applications depend on implementation details of the framework and cannot safely upgrade or migrate
- pjmlp 5y agoIt is always like that, eventually the revolutionaries become the government they set out to replace and the wheel of time turns again.
- pshirshov 5y agoWell, Spring has multiple fundamental problems. They've chosen wrong language and wrong techniques. Runtime metaprogramming is sick and slow. Though that doesn't mean that anything is wrong with JVM as a platofrm. spring-core can be replaced by, essentially, several hundred lines of LoC: https://izumi.7mind.io/distage/index.html https://izumi.7mind.io/distage/index.html And in fact these lines can do lot more than Spring.
- vbezhenar 5y agoIBM WebSphere Application Server took several minutes to start or stop. Deploying war file took another 10-30 seconds. And you had to restart application server sometimes. Spring Boot application with few controllers starts in 2 seconds on my outdated laptop. Spring is lightweight, compared to old tech. Not the most lightweight, that's for sure. Simple Java web server which uses socket API to server requests, starts in few milliseconds. That's the bar.
- grishka 5y agoI use http://sparkjava.com http://sparkjava.com in my hobby project. It mostly does what I want, but I had to hack it a bit to be able to stream responses. It's also crazy fast and about as lightweight as these things get.
- cies 5y agoAnnotations are a band aid. They easily move what otherwise were compile time errors into runtime errors. The advantage of using them is that you have to write less (repetitive) code. I prefer code without them. They add magic. I dont like magic in my code.
- ragnese 5y agoI honestly think the big issue here is using Java for these use-cases. I know that sounds flame-baity, but I'm being sincere. Java is a very primitive language. For the vast majority of its life, it's basically been C + basic classes + garbage collection. As a result, it's very verbose, which is totally fine for a low-level language. But, when building large, high-level, business apps, it's just a weird fit. I think that's why we see all of these annotation-heavy band-aids on top of Java (Lombok, Spring, JPA, etc)- it's because Java is actually not the right tool for the job, but instead of migrating (or inventing) a better tool, we just sunken-cost-fallacy ourselves to death.
- cies 5y agoI disagree here. Having GC, VM, streams, big stdlib, makes is quite highlevel. It's not very terse (like Ruby maybe), but modern Java is terse enough. To keep a language small is a good thing: less to remember, easier to join the team. Go, Elm, Reason/ReScript, LISPs all go that route. Java misses some things badly. Like being able to have a reference to a method (Jodd has a library fix for this). Or like sum types and pattern matching. But I'm more bitten by features that Java has than what it has not. Overuse of Exceptions (instead of sum types) and Annotations are my biggest pains. You see a lot of Java's shortcomings properly being addressed in Kotlin. Like the getter/setter story. And "standards" like Bean and XML config have given Java a bad rep.
- ragnese 5y ago> I disagree here. Having GC, VM, streams, big stdlib, makes is quite highlevel. I used to think that, too. I probably wont't convince you otherwise, and it really doesn't matter how you or I categorize the language, but I think a solid argument can be made that Java's abstraction power is almost zero, especially if you consider versions older than two or three years (before records, switch expressions, sealed classes, etc). I also think that the ability to differentiate between boxed and unboxed primitives, no concept of immutability/const, primitive synchronization tools like mutexes and raw threads, etc, make a compelling case that Java is not well-suited for thinking at a high level of abstraction. Think about how much code it required in Java to create a value type with four fields before records. You needed to list all four fields and their types in the class body, then you need to list all four fields and their types in the constructor signature, then you need to write `this.foo = foo` four times in the constructor body. Then, depending on your conventions and preferences on mutability, etc, you'll need to write getters and/or setters for the four fields. Then you need to write a custom `equals()` implementation. Then you need to write a custom `hashCode()` implementation. Then you need to write a custom `toString()` implementation. I hope you don't have to update that class, either, because forgetting to change your `equals`, `hashCode`, and `toString` will cause bugs. There's basically no universe where you can convince me that this shouldn't be considered low-level programming. > To keep a language small is a good thing: less to remember, easier to join the team. Go, Elm, Reason/ReScript, LISPs all go that route. I agree! Small/simple is great. But look at how expressive Reason/ReScript/OCaml is/are compared to Java. Same with LISP. They aren't huge languages with endless features being added on all the time, but they allow for much more high-level programming than Java, IMO. > Java misses some things badly. Like being able to have a reference to a method (Jodd has a library fix for this). Or like sum types and pattern matching. To be fair, though, this is not what Java was designed for. Java was initially an object-oriented language. Sum types and pattern matching are not OO. Object-orientation was supposed to be about black-boxes sending "messages" to each other while maintaining their own internal state and invariants. In "true" OOP, you wouldn't have a sum type, because you'd have an object that would exhibit different behavior depending on the implementation. Granted, we're moving away from hardcore OOP as an industry (thank goodness). But, I'd argue that the "problem" isn't Java's lack of sum types and pattern matching, but rather that we're trying to make Java into something it isn't. We should just use a different tool. I'm not in my garage trying to attach a weight to the end of my screwdriver to make it better at driving nails- I'm going to my toolbox to grab a hammer, instead.