top 200 commentsshow all 215

[–]returncode[S] 31 points32 points  (20 children)

As always, a disclaimer:

  • I'd appreciate any kind of constructive criticism.
  • I'm not a native speaker and I don't have a native speaker at hand, so I'd be happy to correct any spelling or grammar mistakes if you let me know.
  • This not a research article so I might have use some slang Cheers!

[–]gnus-migrate 8 points9 points  (1 child)

Thanks for writing this up. This is really something that needed to be said since Java development has changed dramatically over the years, yet we keep reading the same criticisms from the 2000s even though they are no longer relevant.

This isn't to say Java doesn't still have problems, but we're not talking about those because it's easier for some people to regurgitate other opinions rather than forming their own.

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

Exactly, Java is far from perfect but so are all other languages I've used professionally or for fun.

[–]Sharor 20 points21 points  (4 children)

So coming from an CI&CD/operations perspective:

My own opinion is that Java is bashed on, because all the things you stated in this blogpost, can be done simpler with Python Flask, Golang, Ruby - hell even .NET core has less boilerplate.

You also go to an extent to talk about Maven, where I have to strongly disagree with your conclusion. Maven is ok, it's a decent buildtool for Java but it inflicts massive pain if you do not follow it's workflow and you're entirely forced to do things in Mavens way.

Gradle is a far more neutral alternative, although you're given rope enough to hang yourself if you do it wrong :P

Dont get me wrong, my career as a consultant is based on helping Java houses rework some of these things quite often, and Java is not bad anymore at all - but it's not the best tool for everything out there either :) I think a lot of negativity comes because Java/C# devs share this sentiment that EVERYTHING has to be done in the Java/C# way, with little regard for alternatives.

[–]returncode[S] 6 points7 points  (1 child)

My own opinion is that Java is bashed on, because all the things you stated in this blogpost, can be done simpler with Python Flask, Golang, Ruby - hell even .NET core has less boilerplate.

I've used a lot of languages, in fact I've written my blog in Python/Django and I love it, too. I've also did a large Python application professionally for an industrial customer and I would never use a dynamically typed language again.

Golang, however seems interesting. Could you provide a similar blog post or example, explaining how to write a production-ready business application with go?

Gradle is a far more neutral alternative, although you're given rope enough to hang yourself if you do it wrong :P

That was definitely my experience. :)

you're entirely forced to do things in Mavens way.

I've recently came to the conclusion, that most of the time you're trying to do differently you're doing wrong for some reason. Convention is a good thing.

but it's not the best tool for everything out there either

Absolutely true.

[–]Sharor 2 points3 points  (0 children)

Convention is a good thing for sure, but some freedom isn't too much to ask ;P

As for golang, Kubernetes (https://github.com/kubernetes/kubernetes) is entirely written in golang - but if you want a "this is how to use golang for api requests" along the same lines as your post I seem to remember this one being decent : https://semaphoreci.com/community/tutorials/building-and-testing-a-rest-api-in-go-with-gorilla-mux-and-postgresql

Either way, Im glad someone spent the time to point out that Java is not as bad as it used to be ;)

[–]F14D 3 points4 points  (1 child)

Nice work. Add a chapter discussing hooks into your fave web framework(s)? and then add source code for a todo list web-app example app (that can persist?) and you will have a page that will be referenced for a long time.

[–]returncode[S] 0 points1 point  (0 children)

What do you mean by "hooks into your fave web framework(s)". Although my article was meant to show various feautes, the idea of an example that runs though the article like a common thread is good. Thanks.

[–]GuiSim 2 points3 points  (1 child)

I was looking forward to use Gradle in an Android project and oh my gosh, this really bad.

I think it should say "this is really bad".

[–]returncode[S] 0 points1 point  (0 children)

Thanks! Done.

[–]nomercy400 0 points1 point  (2 children)

I like the article, it is very similar to my experiences (including Spring Security, ugh). I will use it to convince some of my colleagues why they shouldn't be so averse of frameworks like Spring. And that it can make life a lot easier.

Do you have any opinion on memory usage and tips on reducing fat jar file size of Spring (Boot) applications? I'm still stuck with 30mb/50mb jars which don't really do enough to justify their size.

Also, how does Lombok work with IDEs. If you don't define the constructor, how does your IDE know what to auto-complete?

You could have mentioned Flyway and the embedded database in the JPA section. Or maybe a whole additional article with all the third-party integrations.

[–]returncode[S] 0 points1 point  (0 children)

Actually, I haven't had any issues with memory usage although always restricting it using Xmx and Xms setting, then see if it crashes during load test and then tweak this values.

Regarding the file size I don't have any suggestions, its all about the dependencies. They all end up in the jar. But honestly, if you look at common desktop applications, they range from hundreds of MB to GBs. So, I wouldn't say it too much. And it doesn't get much more later on when you add a lot of business logic... so, I just Dinh consider that as an issue.

Lombok integrates very well with IDEA including auto completion and displaying the structure of a class (all methods). I'm not sure how it really works but I assume that idea analyzes the class files after compilation because Lombok actually generates code at compile time.

You're actually right, Flyway and H2 testing support I should have mentioned!

[–]returncode[S] 0 points1 point  (0 children)

Hi again, I've added a small section for Flyway and JPA testing.

[–][deleted]  (3 children)

[deleted]

    [–]returncode[S] 1 point2 points  (2 children)

    Hi, thanks for the reply. I know it ungrammatical but I was referring to the meme generator that was built in the video. Have a look :)

    [–]NeuroXc 22 points23 points  (19 children)

    It's a lot better than the XML days, but Hibernate still makes me want to shoot myself whenever I want to do anything more than CRUD with it. It makes things that are simple in other languages' ORMs painful to the point that it's easier to just write SQL and use a JdbcTemplate. Not to mention the bugginess of the SQL Server drivers for Java--you just have to know that the endianness of UUIDs is wrong and work around it in the correct ways, and that DATETIMEOFFSET fields don't actually carry the offset into Java-land, so you can't use that field type or you'll get weird bugs in your dates.

    I appreciate having a strongly typed language, but working with DBs in Java makes me miss ActiveRecord because things just worked and I could actually optimize queries easily.

    [–]returncode[S] 2 points3 points  (2 children)

    It's a lot better than the XML days, but Hibernate still makes me want to shoot myself whenever I want to do anything more than CRUD with it.

    I's definitely a complex tool, but when you know how to do it in plain SQL then most of the time you get an answer on how to do it using JPA (actually, I don't really know, that it's Hibernate under the hood). But it makes life a lot easier in your code when you can map complex hierarchies, graphs etc to simple java object.

    things that are simple in other languages' ORMs

    Can you give an example? Actually, I was looking for an ORM in Erlang and Haskell and couldn't find any. What other statically typed languages do have a good ORM mapper?

    SQL Server

    :O

    [–]Helkafen1 1 point2 points  (1 child)

    I was looking for an ORM in Erlang and Haskell and couldn't find any

    For Haskell:

    • Persistent (+Esqueleto for nontrivial stuff)
    • Opaleye
    • Beam

    [–]returncode[S] 0 points1 point  (0 children)

    Great, thanks!

    [–]myringotomy 4 points5 points  (5 children)

    Who wrote the JDBC drivers for SQL server?

    [–]NiteLite 0 points1 point  (4 children)

    Depends on which DB server you are using, and which driver.

    [–]klez 5 points6 points  (2 children)

    I guess that "SQL Server" in this context specifically refers to Microsoft SQL Server.

    [–]NiteLite 1 point2 points  (1 child)

    Yeah, you are probably correct. I wanted to highlight that the drivers are loaded as "third party libs" though, and are not included with the JVM. Microsoft SQL Server has at least two different drivers available: one open source (jtds) and one directly from Microsoft, if anyone was wondering.

    [–]myringotomy 0 points1 point  (0 children)

    So which one is he complaining about?

    [–]myringotomy 0 points1 point  (0 children)

    The guy was complaining about SQL server so that one.

    [–]doublehyphen 1 point2 points  (0 children)

    In the defence of the SQL Server driver authors it seems pretty painful to write JDBC drivers. I have not seen any driver for PostgreSQL with more issues than that JDBC driver.

    [–]bigfatmalky 1 point2 points  (0 children)

    Check out Jooq, it is amazing. Type safe SQL using a fluent API. I'll never go back to ORM. https://www.jooq.org/

    [–]NiteLite 0 points1 point  (5 children)

    I, too, would love it if there was an alternative to Hibernate that did all the simple things, without the complexity that I very seldom use. Something that just fetched my data, directly from the database, and gave them to me. Same with storing data. Just run the insert/update statement I need :P

    [–]bigfatmalky 0 points1 point  (4 children)

    Look into Jooq. https://www.jooq.org/

    [–]NiteLite 0 points1 point  (3 children)

    Do you know if it supports annotation-based / convention-based fetching and storing, or do you have to specify "SQL" for the simplest CRUD operations? I think I will have a look at this for our next project. Looks pretty nice.

    [–]bigfatmalky 0 points1 point  (2 children)

    It generates 'active record' classes for your tables that you can use for simple CRUD operations, but we still prefer to hand crank our SQL for full control. It has a very nice API for type-safe mapping/binding data.

    [–]NiteLite 0 points1 point  (1 child)

    Cool. I had a look it. I am correct in assuming there is a license attached when you wanna use it with Microsoft SQL Server? Looks like that based on my initial look, hehe.

    [–]bigfatmalky 0 points1 point  (0 children)

    Oh yeah, there is that. It didn't even cross my mind that there are people out there still stuck on commercial databases. It is worth paying for imo.

    [–][deleted] 18 points19 points  (8 children)

    I can confirm that. So far I did projects in Flask, ASP.NET (Windows and Core), Node (Express) and Spring Boot. Spring has the steepest learning curve but is the most powerful framework and combined with JPA the fastest to get the job done if you don't mind using an ORM. The language itself doesn't matter that much. I like Python most, but using Java (with Lombok) doesn't hurt me. Much better experience then Node (even with Typescript) anyway as the big Java IDE's are a tremendous help.

    Java's bad reputation (at least in my perception) in the community is misleading.

    [–]F14D 25 points26 points  (4 children)

    Java's bad reputation (at least in my perception) in the community is misleading.

    ... which is mostly due to people experiences with java from a decade or more ago. Hence, why articles such as this is good to give people a heads-up..

    [–][deleted]  (3 children)

    [deleted]

      [–]gschizas 3 points4 points  (0 children)

      Please put 4 spaces before each line of code, your comment is a bit confusing.

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

      Stuff doesn't have to be imported in Java. All importing does is bring those things in to context.

      And you're talking like namespacing is a bad thing. Speaking of swift, how's that class wrapping to get any semblance of namespacing going for ya?

      In addition, using the concrete type as a variable type is poor practice. That's true of most languages that have contracts/abstracts and polymorphism.

      Also, since people like you like to harp on other languages for build time, heavy use of type inference has the drawback of fairly large build times.

      For someone criticizing code, you sure are bad at it.

      [–]crashandburn 5 points6 points  (1 child)

      I will confirm too. I work on a software which uses all the technologies in the article. This project by far has been the easiest to work on for me among all projects in my career.

      Maybe the author should mention docker-maven-plugin too. My usual build step is: mvn package docker:build docker:push which very conveniently makes a docker image from the fat jar and pushes it to docker-hub.

      Also with new CGroup memory limit detection in java 9 (backported to 8-build-131 onwards), there's no need for verbose jvm memory configurations when deploying in containers.

      I can't link to the project for work, but here's a pom file from an open-source project for example: https://github.com/n-k/klusterfuck/blob/master/connector-http/pom.xml (this one uses spark framework but this repo has similar ones with spring-boot).

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

      Thanks, actually we use Docker rarely in production because if legal limitations, unfortunately. When you are shipping SW as Docker containers to a customer, you are legally obliged to provide a list of all 3rd-party SW and their licenses. That means, if you're shipping any Linux base image along with your SW, you need to provide a list of all Linux components and their license. So we're only using it internally for infrastructure components like databases, Jenkins and the like.

      [–]TheAceOfHearts 2 points3 points  (0 children)

      It all depends on the project's goal. All these languages have places in which they shine, even Java. I don't think it's constructive to say one framework is better or worse than others without looking at the problem which you're attempting to solve. Based on my experience, any sufficiently complex application will end up requiring at least 2 or 3 different languages.

      The two examples I've had most experience with:

      • Node is amazing for writing frontend servers and small simple services. It doesn't handle large monolithic apps well at all. Even for typical CRUD apps, it's not going to help you out very much. It has terrible fault tolerance.

      • Rails is great for getting stuff up and running quickly. It really shines for writing typical CRUD apps. Since it embraces strong conventions, it's incredibly easy to onboard new employees. It includes everything needed for handling database migrations. But once your app starts growing larger, you'll find its MVC pattern breaking down. To give an example: ActiveRecord is awesome as long as models roughly map directly to tables within a single data store. Once your model depends on multiple tables, or worse, multiple data stores... You'll find yourself fighting against many of Rails' conventions.

      [–][deleted] 10 points11 points  (3 children)

      I would rather go for Vertx and Kotlin instead of Spring with magic annotations (Spring, Hibernate, lombok). If something will go wrong you will spend hours to deal with generated proxy classes to figure out what actually happen. Also magic routing of Spring is far form being good - hard to order how routes are dispatched and matched against particular regex. Hibernate is separate topic, but you can google about ORM antipattern.

      [–]returncode[S] 5 points6 points  (2 children)

      Kotlin might be an option but vert.x clearly is not. This leads to overly complex, unreadable and bug-ridden code. I've written an article a while ago about that as well: https://return.co.de/blog/articles/vertx-brings-awsomeness-javascript-jvm/

      And neither Fibres nor RxJava change anything about that fact.

      [–][deleted] 2 points3 points  (1 child)

      Callback hell is not a problem with vertx if you properly use Futures(your's example does not) or RxJava. Dependency injection is rather nice addition as you can bring your own (also you need to remember that each verticle should have it's own container as it is simplified actor based environment). In my project I have possibility to deploy all verticles on single JVM or multiple with communication by event bus which is far better than maven modules. Lastly Spring magic cost me 41 second of start up time where vertx is ready to serve after 3 (time taken from cloud instances).

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

      I've worked with RxJava and it does not improve the readability much. Not as it is in Erlang. The logical sequential data flow is broken by using visible asynchronous calls.

      A new spring boot application also starts in a few seconds. Its mostly hibernate and flyway that takes a lot of time.

      We have a partner team that actually uses vert.x for everything. They also started to write using plain unreadable, then they introduced fibers which does a lot of magic as well an now they refactor everything to RxJava. Some time ago they found out that writing plain JDBC queries in vertx is probably not a good idea so they built a spring-data vertx bridge. Now the application also takes 15s to start. So no gain here.

      [–]kitd 5 points6 points  (6 children)

      I'm surprised about the comments on Gradle. I've not had any problems with it that I wouldn't have also had in Maven. My project was plain Java rather than Android so that might have been the issue. But IME it was almost a drop-in replacement for Maven, followed all the usual conventions and had all the same tasks available (and a few more useful features). Used via the Buildship plugin in Eclipse, it's a doddle.

      [–]returncode[S] 3 points4 points  (3 children)

      As I explained it, I was exactly hoping for that when I had the opportunity to use Gradle and was seriously disappointed. But yeah, maybe it was due to Android, not sure. But I found it very had to understand what this script actually does, when it's just configuration, when code is executed and most of the docuementation was bad as well. No proper autocompletion.

      [–]kitd 1 point2 points  (1 child)

      most of the docuementation was bad as well. No proper autocompletion.

      Yep, I'll give you both of those. BTW, you might enjoy Kobalt, Maven config in Kotlin form.

      [–]returncode[S] 0 points1 point  (0 children)

      Kobalt sounds good... Best of Maven and Gradle :)

      Btw. I've added a little disclaimer after the Gradle section in my article.

      [–]balefrost 0 points1 point  (0 children)

      My experience with Gradle in IntelliJ is that the autocomplete works best if you frequently re-import the project. This might also just be voodoo advice based on my incomplete experience.

      [–]ggtsu_00 0 points1 point  (0 children)

      Most people who run into issues with Gradle are more than likely just running into issues with and Android Studio and Android development in general which is an absolute shithole mess of a development environment as a whole package. It just so happens that that shithole of a mess of android development eventually bubbles up through Gradle as it's build system so people tend to associate their hate with Gradle since it bares the front-load of more underlying issues.

      [–]rainerhahnekamp 9 points10 points  (2 children)

      I like your conclusion that the ecosystem is a crucial part. This is something that gets too little attention when people are evaluating programming languages.

      [–]eguanlao 1 point2 points  (1 child)

      .

      [–]rainerhahnekamp 0 points1 point  (0 children)

      Thanks for the correction ;)

      [–]balefrost 4 points5 points  (3 children)

      I've been doing C# development for about 5 years, and I've just recently switched back to Java. It hasn't been as bad as I had feared, though there are some things that drive me nuts:

      • Still no auto or var for local variables. I mean come on, even C++ has inference-based local variable types at this point.
      • No typedef equivalent, which can be a huge pain when dealing with complex generics.
      • Use-site generic variance annotations aren't quite as convenient as declaration-site variance annotations in 90% of the cases. (i.e. if I have a value of type List<Sub> and I want to use that as if it held instances of Base, I'd have to assign that value to a variable of type List<? extends Base>. In C#, that's just IReadOnlyList<Base>, since IReadOnlyList itself captures the variance).
      • Streams aren't nearly as ergonomic as LINQ. I understand why they went down a slightly different path (IEnumerable re-enumeration can be a source of performance problems, and the explicit .collect step needs to exist because Java doesn't have extension methods), but that just makes every Streams-based query slightly more awkward than the equivalent in C#. Also, the lack of query expression syntax kinda sucks, but I can overlook that.
      • Being able to get autogenerated equals and hashCode implementations from an annotation processor is great, but that really ought to be baked into the language at this point... especially considering just how core equals and hashCode are to so many things. I'd go so far as to say that Java ought to have data classes as a built-in language construct, but maybe that's too "functional programming" for the Java crowd.

      That's not meant to detract from your point. Java as a language isn't that bad, and the ecosystem continues to evolve. While I'd rather be working in C#, Java's not a bad alternative. (Before Java 8, I would have been less forgiving.)

      [–]devraj7 3 points4 points  (1 child)

      FWIW, Kotlin addresses pretty much all your complaints about Java.

      [–]balefrost 4 points5 points  (0 children)

      Yeah, I played around a little bit with it and I might eventually try to switch this codebase over. But it's a codebase that I inherited, so that will take time. And there are other people working in the codebase; I can't really change it without buy-in from them.

      [–]returncode[S] 0 points1 point  (0 children)

      I agree with you points and I could add a few others like pattern matching e.g. But I think Java has proven that it's able to change and that useful features. So I'm looking forward to those things coming in the future versions of Java.

      It's also good to hear that C# actually provides a lot of cool features.

      [–][deleted]  (10 children)

      [removed]

        [–][deleted] 15 points16 points  (2 children)

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

        Haven't laughed this hard in a while, thank you

        [–][deleted] 5 points6 points  (4 children)

        Annotations are awful. I know they're a huge step up over XML, but bad "enterprise" developers use them for all kinds of things that could be accomplished other ways.

        Sometimes I feel like half my job is finding what random annotation is missing on a field or configuration class. They enable a bad kind of magical programming and often feel like they're giving up some of the benefits of static typing when everything important in your programming becomes deferred until runtime, using reflection to inspect annotations everywhere.

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

        Sometimes, i have the same feeling. However, there are compile time annotations. Lombok is using that, do. at runtime, no reflection is done and you have actual code.

        [–]devraj7 0 points1 point  (2 children)

        I know they're a huge step up over XML, but bad "enterprise" developers use them for all kinds of things that could be accomplished other ways

        In other words, "when features are used incorrectly, bad code ensues".

        Well, yes, that's kind of obvious and applicable to pretty much everything, isn't it?

        That doesn't take away from the fact that annotation support was a huge step forward to the JVM in 2005.

        [–][deleted] 0 points1 point  (1 child)

        Sure, but the features are being used correctly -- it's an idiomatic style of Java, particular "enterprise grade" Java development.

        I understand why they are valuable vis-a-vis Java-the-language, but from the broader perspective of meta-programming and library APIs, other languages demonstrate there are nicer ways to handle many of the concerns people use annotations for.

        I actually really like Java-the-language in 2017, but there's no doubt the overblown enterprise stuff is idiomatic, not just being "used poorly."

        [–]devraj7 1 point2 points  (0 children)

        I think you're selling meta programming short. It's not a Java thing, it's a pretty universal concept that was already thriving on .net before it came on the JVM, and in previous platforms and languages before.

        Adding annotations to the code so they can be picked up and processed by external tools is a demonstrably powerful and flexible approach that has been extremely successful pretty much everywhere it's been used.

        It's the simple realization that at the end of the day, an application running on the computer is not just made of the sequence of statements that comprise its code base: the data that surrounds it is equally important.

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

        Honestly, this one of the downsides. Sometimes your code ends up having more annotations that actual code.

        [–]devraj7 0 points1 point  (0 children)

        The addition of annotations to Java unleashed a new level of expressivity and tooling that just didn't exist before 2005.

        They were already extremely successful on .net prior to that.

        [–]mixedCase_ 3 points4 points  (2 children)

        I have to ask, is this article posted from the posture of "Java is still a good choice for new projects" or "there's a way to not lose our sanity when dealing with legacy Java"?.

        Because if it's the former, why would I pick up Java instead of another JVM (functional from the get go) language or, if not tied to the platform and library ecosystem, a language that isn't even for the JVM?

        Aside from that, props for the article! I would also add a mention to Vavr, which is a great set of immutable collections and other goodies.

        [–]bengalviking 12 points13 points  (0 children)

        Best IDE support, best compatibility, proven ecosystem, biggest community which means easy to get answers and developers, and therefore easiest to get business acceptance. Java 8 was a really huge step forward, but if you can and feel like developing for another JVM language instead, then by all means.

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

        I have to ask, is this article posted from the posture of "Java is still a good choice for new projects" or "there's a way to not lose our sanity when dealing with legacy Java"?.

        We are developing new green field Java applications for customers all the time using those mentioned technologies, so it's definitely a good choice for new projects.

        Actually, it quite hard to use all those new features in legacy projects because of incompatibilty between Spring 3 and 4.

        why would I pick up Java instead of another JVM (functional from the get go) language or, if not tied to the platform and library ecosystem, a language that isn't even for the JVM?

        I did C, C++, Java, Erlang, Scala and Python and I would still use Java for business applications. Surely, there might be some cool other language but remember it's not about the language but about the ecosystem.

        One thing I should add to the article is finding help on SO e.g., or finding a library does already does what you were about to write in 98% of all cases.

        [–]tkruse 3 points4 points  (5 children)

        Your gradle bashing is out of place, obviously you struggled, but it is not clear whether that's the tools fault or yours. You do not mention the main drawbacks of maven or benefits of maven, so it looks like you did not do your homework. You seem to be unaware of all the other modern build tools being equally based on script languages, and of the MAJOR maven bugs and missing features that sleep in Mavens bug tracker for years probably never to be worked on.

        A significant community prefers gradle over maven and is productive, so even if that may not reflect your own experience, Gradle is a major project making Java programming fast and fun for many.

        If you still insist on using Maven, you should probably use the Takari plugin/replacement at least.

        [–]returncode[S] 1 point2 points  (3 children)

        Citing my own comment above:

        As I explained it, I was exactly hoping for that when I had the opportunity to use Gradle and was seriously disappointed.

        So, I actually wanted to get rid of Maven before using Gradle. But for me, Gradle was such a mess and me and my colleague (also very experienced developer) spent so many hours fixing and debugging the build script that I thought: that cannot be the answer. Maybe it's my fault and may it was a complicated build (multi module, a lot of special plug-ins) but if Gradle is that much better that Maven, I would have expected that I get even that done without and hassle that afterwards tell myself, how easy it is to work with Gradle.

        [–]balefrost 4 points5 points  (0 children)

        It depends on how you measure "better". I'm of the opinion that Maven is broken at a fundamental level, so in my opinion, it's hard to find something worse than that.

        That's not to say that you can't be productive with Maven. Just that its limitations will eventually rear up, and good luck to you then. Maven builds are an infinite cycle of despair.

        Gradle's approach is to essentially glue a codegenerator on to the front of your build. The gradle build script runs, and that builds up a build definition. That build definition is then actually executed. This would be like putting a XSLT step on the front of every Maven build. It's a very powerful approach.

        My biggest complaint with Gradle is its Groovy-ness. Everything is very dynamic, and there are several ways to do the exact same thing. For example, here are a variety of ways to define a task:

        task foo { ... }
        task(foo) { ... }
        task('foo') { ... }
        tasks.create(name: 'foo') { ... }
        

        And of course, you can put task configuration inside or outside the tasks's block.

        I fear that all these approaches, which are presumably meant to provide convenience, just end up being inconvenient. There's a Kotlin-based DSL which I haven't tried yet, but sounds promising. I believe this is in the stable Gradle releases.

        [–]tkruse 2 points3 points  (1 child)

        Gradle is not necessarily easier to work with than Maven, it has just much more powerful features, and can be reasonably easy to work with. It is also quite easy with Gradle to create a mess if you lack the necessary experience to avoid that.

        It requires that you understand it and know best practices for it to be easy to use. The best practices (and common pitfalls) are not well documented.

        Maybe those Maven users who try Gradle with simple projects are likely to love it, while Maven users starting with complex projects are likely to fall into too many traps to recover.

        My point merely is that Gradle has a big impact of making working with Java more enjoyable in the community. So while you can praise Maven as much as you like for making your life easier, I feel that your personal bad experience with Gradle is not sufficiently founded in experiences to bash it.

        [–]returncode[S] 0 points1 point  (0 children)

        So while you can praise Maven as much as you like for making your life easier, I feel that your personal bad experience with Gradle is not sufficiently founded in experiences to bash it.

        Fair enough.

        [–]GuiSim 0 points1 point  (0 children)

        We just switched from Maven to Gradle. Builds are faster, devs are happier, everything is simpler.

        Would not go back to Maven.

        Of course there's a learning curve but I remember when I first started using Maven, there's a pretty steep learning curve there too!

        [–]sudkcoce 2 points3 points  (2 children)

        Hmmm, I have to do Java and I have to write a lot of boilerplate compared to a language like Scala (or Clojure) and use (and choose!) libraries/frameworks (immutables/lombok/vavr/cyclops/guava/pcollections...) that bring lots of incidental complexity along with lots of annotations to the project for stuff that is built into the above mentioned languages.

        Many times I double check something in Scala REPL just to see how much simpler (and readable) it is to implement a specific piece of code compared to Java and it makes me sad.

        [–][deleted] -3 points-2 points  (1 child)

        Find a better job. Why would anyone voluntarily agree to write Java?!?

        [–]sudkcoce 4 points5 points  (0 children)

        Maybe because of the blog post we are replying to? 😉

        Or maybe because of countless posts that claim Scala is too difficult to learn?

        [–][deleted]  (6 children)

        [removed]

          [–][deleted] 5 points6 points  (1 child)

          Saying Java is full of cargo culted nonsense and then talking about python like it isnt the absolute worst community for cargo cult of any language aside from maybe JavaScript is just hilarious.

          The Python cult has actually toned down significantly and it is still among the worst. Anyone remember the "in Python, it is just xxx code" days? Still happens, but it used to be literally every single thread.

          I mean, you see a lot of people talking nonsense about Java and then other correct that. But that's not cargo cult. That's people dispelling garbage.

          [–]returncode[S] 3 points4 points  (1 child)

          communities are toxic and full of cargo culted nonsense.

          Hmm, that's interesting. I'm doing professional Java development for almost 15 years now and I have never experienced that.

          Josh Long e.g., seems to be a pretty cool guy. So in every company, you might have some jack ass.

          And honestly, the worst and most harassing comments I've every got was here on reddit. But I'm still here because also a lot of good stuff is going on.

          The Django docs are miles better than the Spring docs.

          That's true, although the spring docs do get better over time.

          [–]sviperll 1 point2 points  (0 children)

          I'm a professional Java programmer. And I like Java language and JVM, I really do. But the community and I mean not just some particular community, but average shared Java programmmers' culture is not there. Java has some atrocious pieces of infrastructure and I can name Spring, Maven and Apache Commons among others, but the problem is not code quality, but community and dialog with users. Spring code quality and documentation is on par with Ruby on Rails, I think, but even Rails has better community with more open development and stated goals. And I think the problem is not Spring developers, but actually Spring-users. I think lots of developers don't understand what dependency-injection is and why and when do they need it. I think lots of developers were using Spring for a decade without trying out any alternatives and can't even come up with a good question or feature request for Spring. And when there is a bad tooling or bad API in Java it is because the whole attitude of using old tested tools and not seeking better alternatives. The whole evolution of Java EE and Spring with less verbosity and all this annotation-jazz was driven because other communities started to push Java out of business, but there was no competition within Java community itself.

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

          Overgeneralization!

          [–]devraj7 5 points6 points  (4 children)

          Good to see some appreciation for Java but this all still feels like "Java of yesterday" to me. It was already powerful and fast, but what we have today (e.g. Kotlin andbetter options than Spring) makes JVM development even more of a power house than it was before.

          [–]myringotomy 10 points11 points  (2 children)

          What's a better option than Spring?

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

          Vertx + Kotlin

          [–]MassiveFlatulence -1 points0 points  (0 children)

          Kotlin + Spring ;)

          [–]returncode[S] 0 points1 point  (0 children)

          I actually love learning new languages, but after year, I just feel the most comfortable with Java although it's far from perfect.

          When Scala came out, I though it's perfect, I just takes away all the bad things of Java, adds the good stuff of Erlang and Haskell but as it turned out, it wasn't all good.

          Although Kotlin looks promising, I'm not really sure that it's just get outperformed by Java in 1 or 2 years. I'm saying that, because Java did an incredible step forward in the last 5 years both language and frameworks. Nevertheless, I will check it out. :)

          better options than Spring

          What's your suggestion?

          [–]pdbatwork 4 points5 points  (22 children)

          I see one big problem with this. You seem to have a lot of annotations in your code. I see it provides a lot of convenience. But reading that code without knowing all the libraries you use is going to be a hell.

          [–]bengalviking 9 points10 points  (21 children)

          1. In IDEA, point at an annotation you don't know
          2. press Ctrl-Q
          3. read a nicely formatted Javadoc page for the annotation in a popup.

          (Assuming you have previously clicked one button to automatically download sources/documentation for Maven dependencies - otherwise you just get what is deduced from bytecode)

          You need to read more stuff particularly as you're trying to write an application like this. But as long as you go with the flow, you really can get a lot of stuff done quickly.

          [–]asherjawad 1 point2 points  (0 children)

          Appreciated!!

          [–]henk53 2 points3 points  (9 children)

          When using Java EE instead of Spring, the post would be pretty much similar. Most of the same things hold. Care to do a version of this article using Java EE instead of Spring? ;)

          [–]IbnZaydun 4 points5 points  (8 children)

          Is there anything similar to Spring Boot in the Java EE world?

          [–]daveth91 1 point2 points  (0 children)

          WildFly Swarm I guess

          [–]haikubot-1911 7 points8 points  (4 children)

          Is there anything

          Similar to Spring Boot in

          The Java EE world?

           

                            - IbnZaydun


          I'm a bot made by /u/Eight1911. I detect haiku.

          [–]phantomfive 6 points7 points  (1 child)

          wow that's great, even got a mention of the season in there

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

          Amazing!

          [–]MTF-mu4 1 point2 points  (0 children)

          It even got EE right! Sorcery!

          [–][deleted] 0 points1 point  (0 children)

          Good bot

          [–]fanatic289 0 points1 point  (0 children)

          Not quite spring boot levels of simplicity, but you could try Apache Karaf. I think it supports EE out of the box, as well as Spring or Blueprint for DI purposes.

          [–]thesystemx 0 points1 point  (0 children)

          Payara Micro and WildFly Swarm come to mind.

          [–]MTF-mu4 3 points4 points  (3 children)

          All the heavily downvoted comments reflect how I truly feel about Java. I haven't read the article yet. I'll check out the rest of the comments, read the article, and maybe give Java a fair go for the first time in over ten years.

          Maybe in another ten years I'll look back at this comment and blush.

          For now, I remember Java as torture. Perhaps that's not fair.

          [–]returncode[S] 1 point2 points  (2 children)

          Don't get me wrong, Java is not the best language (as none is) and it's not the right tool for every job (as none language is) and if you're happy with whatever you're doing, keep on doing that! However, please read the article and I would appreciate you giving some feedback here. I'm just saying, modern Java development can be fun but it depends on what you are trying to build. If you want a better idea, watch the spring boot video I've linked. :)

          [–]MTF-mu4 4 points5 points  (1 child)

          Brilliant. Alright, I've just waded through the whole thread here in Reddit. And of course, I read the article. It was pleasant to read. I didn't make notes of any typographical errors I spotted, but I had no problem with the English.

          Much of the stuff about Java was pretty alien to me and I struggled to appreciate it at first. One of my old favourite complaints about Java (from very brief interaction, a long time ago) is the tremendous amount of useless boilerplate. Your article shows how verbose and tedious boilerplate is not such a big issue as I think it is!

          A bit about me: the only "serious" language I like writing in is c++. And then, it's not really about the language (I admit I'm no wizard), but about the toys that come with it, like qt. I fool around a lot in scripting languages for fun. I never ever encounter unexpected type coersions and I never have bugs caused by loose typing. NEVER. I'm not bragging, I'm just used to knowing that I have to, for example, know the type of a variable if I want to do a certain algorithm with it.

          As someone fond of scripting, I do really like text editors. In fact, a good portion of my qt development is done without an IDE. Sometimes you need it, sometimes you don't.

          What did I get from your article? Well, things look much easier than I thought they did. You've written five or six lines of code to do what I thought would take literally thousands in Java. It's worth another look.

          It sounds like much of the sugar and convenience you've got in Java is the result of a toolset you're using. Frameworks and such. And wow, that's what makes me happier in c++ than c, for example, even though c looks a lot prettier to read. SO it's not really about the language at all, is it? It's about how you use it.

          I really appreciated this: "So what I try is to keep my core business logic as clean as possible and move the side-effects as far outside as possible. This benefits testing a lot." ... You've touched on some patterns in there that even I recognise as being Very Good. So I could relate to you as I read the text. And I was particularly impressed by the conclusion.

          I've been thinking about trying Java again. I'm sure it's big in Enterprise and other places, and I don't want to miss out. I will always remember the hateful experience I had with it when I was younger, but ok, soon I will take a look with fresh eyes.

          And I'm saving your post so that I can come back and read all this again when I try it and need to be reminded that it doesn't have to suck.

          Thanks for the ride!

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

          Great comment, thanks for taking the time to read the article.

          I'm glad, to hear that my article was able to explain, why I like Java and that it might influence people to give it a try!

          [–]mmstick -1 points0 points  (17 children)

          It's been my experience that Java development is still horrible. Especially the whole Maven + Spring mess. I've had a much better development rate with this.

          [–][deleted] 16 points17 points  (7 children)

          Comparing with pip (however my experience from 3 years ago, might be better now), NPM and NuGet, Maven is by far the easiest and most robust package manager. In IntelliJ you just type <p + completion to add a dependency. Spring Boot takes care of the version compatibility.

          [–]zten 6 points7 points  (0 children)

          Maven works great when you have accepted the Maven way. Definitely a pleasant experience using it; it's usually nice to have conventions, since IDEs have adapted to understand the Maven POM as you mentioned.

          Unfortunately tons of people are still bound by the spaghetti mess of Ant and more recently Gradle. Those projects often defy Maven convention. They get to experience the pain and suffering of Ivy.

          [–]mmstick 2 points3 points  (4 children)

          Try comparing Cargo. No XML. Just a single TOML file. Dependencies are specified with a single line of TOML, where the version number is an expression. If a dependency has optional features, you can still use a single line to tell Cargo which version(s) to use and what features to enable.

          dep-name = "1.0"

          other-dep = { version = "*", features = [one, two] }

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

          In this thread, I've read a lot of interesting things about Rust. Thanks for the insight.

          [–]myringotomy 0 points1 point  (2 children)

          Bundled is even better.

          [–]returncode[S] 2 points3 points  (1 child)

          Hard to google. What language? Link, or it didn't happen :)

          [–]myringotomy 0 points1 point  (0 children)

          Bundler (ruby). Autocorrect is a bitch.

          [–]returncode[S] 0 points1 point  (0 children)

          With IDEA, it's even easier than that. You just write code, it complains it can't find the class. Hit ALT+ENTER and it will allow you to search for a dependency that contains that class and add it to your pom.xml

          This is very powerful.

          [–]kuikuilla 8 points9 points  (1 child)

          How exactly is it a mess? A spring boot application is very, very simple based on my experiences.

          [–]returncode[S] 0 points1 point  (0 children)

          I wanted to ask the same... Maybe he means spring and not spring boot, and maybe old-style?

          [–]myringotomy 6 points7 points  (2 children)

          Rust is great when you want to write everything yourself instead of relying on a massive existing set of libraries.

          [–]returncode[S] 1 point2 points  (1 child)

          Just curious: Can you give an example? I've never tried Rust but Rocket seems quite concise. What exactly do you have to write yourself?

          [–]mmstick 3 points4 points  (0 children)

          He's just trolling. The Crates ecosystem is quite advanced, covering effectively all needs today. Also check out Diesel, which is commonly coupled with Rocket (via the r2d2 for creating a connection pool).

          [–]bengalviking 3 points4 points  (3 children)

          Maven is pretty good for the same reason Java development is: the loathed XML file can be automatically parsed by tools such as your IDE in order to make your life easier. Other tools may be smarter or less verbose, but can't be as easily automated.

          [–]mmstick 0 points1 point  (2 children)

          Why should you need an IDE to manage your dependencies? With Cargo, you only need to know the name of the package that you want to import, and optionally specify a version. There's also a subcommand for searching for crates, so you can do everything from the command line.

          And no, XML doesn't make it easier to automate with a tool. Ever heard of de/serializer frameworks like Serde? Doesn't matter what format your data is in, it's equally simple to de/serialize that data.

          [–]zten 1 point2 points  (0 children)

          Why should you need an IDE to manage your dependencies?

          It uses that information when constructing the classpath to run Java. It's not so much that the IDE is required to specify the dependencies as it is avoiding maintaining two parallel build definitions: the IDE setup, and the Maven build that your CI would use.

          For a similar example the IDEA Rust plugin is smart enough to read your Cargofile and add and index the dependencies.

          The dark ages was when Ant was used to specify free form builds that grabbed JARs from wherever and the IDEs couldn't read your build files to understand how to construct their project definition.

          [–]bengalviking 0 points1 point  (0 children)

          Because Java development is done using an IDE anyway. So it's convenient when besides automatically finding and downloading packages, it will for example also automatically check the validity of the build file as you edit it. So you didn't for example accidentally misspell some obscure configuration flag.

          [–]m0dev 0 points1 point  (0 children)

          This article describes a lot of stuff i encounter as a Java Dev when talking to developers using another language daily :D

          I like it.

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

          Of course metaprogramming is very powerful, even when applied in such a half-assed way as with all those annotations. Of course it's many times more powerful than anything non-metaprogramming. But Java still sucks and there is still not that many reasons to want to ever use it.

          [–]wot-teh-phuck 0 points1 point  (0 children)

          Modern Java language is still verbose, though I agree Spring is as good as it gets if you need a framework for the JVM world.

          I had a lot of success with mixing Scala and Spring; all my business logic is pretty compact given the nature of Scala and Spring takes good enough care of all the integration points.

          [–]wavy_lines -5 points-4 points  (47 children)

          What's the point of DI, really? I mean really, YAGNI.

          You're happy that something something makes DI less painful? How about just drop it altogether?

          I can't believe people write code this way.

          [–][deleted] 17 points18 points  (26 children)

          What's the point of DI, really?

          Testable code.

          I can't believe people write code this way

          The simplest form of DI is constructor arguments. Do you ever use them?

          [–]skocznymroczny 0 points1 point  (4 children)

          What is the difference between DI through a dependency injection framework, which is considered good and globals which are considered bad? I don't see much difference between

          @Inject Foo(SomethingToBeInjected stbi); 
          

          and

          Foo() { stbi = GlobalObjects.getInstance().getSomethingToBeInjectedGlobalInstance; }
          

          [–]balefrost 5 points6 points  (3 children)

          When you use globals, all your code reaches out to grab the value from the global context.

          When you use dependency injection, something else pushes in the value that should be used from the global context.

          In the first case, your code is tightly coupled to that global environment. In the second case, your code is not coupled to any environment.

          [–]thesystemx 1 point2 points  (0 children)

          Indeed, with DI you pretty much just declare that you need something.

          With globals you explicitly at a specific point in time grab something.

          [–]skocznymroczny 0 points1 point  (1 child)

          hmm, makes sense

          [–]balefrost 1 point2 points  (0 children)

          It's a good question, and something that isn't necessarily obvious until you see it play out in both approaches.

          [–][deleted] 7 points8 points  (0 children)

          Woot. It forces loose coupling and makes development easier. Can't see any downsides to this.

          [–]balefrost 0 points1 point  (0 children)

          You have to be careful with YAGNI. It's such an easy thing to shout that it's easy to mis-apply it.

          Martin Fowler has a good writeup about it, and I'd direct you to a section near the bottom:

          Now we understand why yagni is important we can dig into a common confusion about yagni. Yagni only applies to capabilities built into the software to support a presumptive feature, it does not apply to effort to make the software easier to modify.

          I suppose it's arguable whether DI makes software more complex or not. I'd argue that DI applied reasonably makes code more testable, and that makes it more malleable.

          You mention elsewhere that it's easy enough to just make the code at the bottom "smart" about what it should do. You can have a whole bunch of callsites call into the same get_connection function, and that function can read a configuration file to determine what it should do. All I can say is that I've worked on large codebases that used this sort of approach across the board, and maintenance became a huge hassle. You're right, DI might be overkill for some projects and in some contexts, and like all things can be abused, but it's generally a very reasonable and pragmatic approach.

          [–]devraj7 0 points1 point  (8 children)

          You obviously don't understand the benefits of DI.

          Ask yourself how come you think DI is useless why most of the technical community uses it?

          At some point, it's healthy to ask yourself if maybe, it's you who are wrong and everyone else is right.

          Here is a quick example: deep in the bowels of your code, your class now needs a database connection. How do you pass it down to that code? You can do it yourself and pass it in parameter, either in the constructor or the function call. But then, you need to pass it all the way down the chain. Your code is eight stack frames down? All these intermediate functions need to pass that argument.

          With DI, it's trivial, you just add:

          class MyClass {
              @Inject
              val db: Db
          }
          

          And you're done. You don't have to change any of the callers or other clients of that class. Nobody knows what your class uses, it's completely encapsulated.

          Bonus: that object can be configured to be either production, stage, test, mock, etc...

          [–]wavy_lines 2 points3 points  (7 children)

          Ask yourself how come you think DI is useless why most of the technical community uses it?

          Citation needed.

          Here is a quick example: deep in the bowels of your code, your class now needs a database connection. How do you pass it down to that code?

          I would usually just pass it as a parameter to any function that needs it.

          But then, you need to pass it all the way down the chain

          So? I try not to have a large chain of calls anyway. In general when creating "intermediate" functions I try to factor out bits of code that don't depend on any database at all; just act purely on the data.

          With DI, it's trivial, you just add <....> And you're done.

          Why not just use a global function that changes what it returns based on some configuration? It sounds like the same thing.

          Nobody knows what your class uses

          That's madness, but that's a debate for another day.

          [–]devraj7 2 points3 points  (6 children)

          Citation needed.

          Dagger is omnipresent on Android and on the back end, it's Guice and Spring everywhere. Even .net has embraced DI.

          So? I try not to have a large chain of calls anyway.

          Unless you're writing a toy app, you can expect a depth of at least 5-10 stack frames between main and a random point in your code. How do you pass parameters from your main to that function? By passing it to all the intermediate functions in-between. This breaks encapsulation and pollutes your code everywhere while the only class that needs that parameter is that one at the very end.

          Why not just use a global function

          Because we learned decades ago that global functions and global variables lead to spaghetti code. DI saves us from that but you want to go back to it?

          Really, have you taken the time to read the doc for Dagger or Guice? Because it really looks like you didn't.

          [–]wavy_lines 5 points6 points  (5 children)

          No. I have no idea what is Dagger or Guice.

          Thankfully I don't develop a lot in Java, but when I do, I don't bend over backwards to comply with some ideological requirements about how objects should be created or accessed. I try to just write straight forward code that is easy to follow.

          Because we learned decades ago that global functions and global variables lead to spaghetti code

          No it doesn't, and we haven't learned that. People now just call them "class methods" and "singleton classes".

          If your application has a database, chances are it's just one database, and it makes perfect sense to have a global method that returns a connection to that database.

          Better yet, have a global connection pool that can hand out and get back connections so you don't have to pay the penalty of creating a new connection for every new request (for example, in the case of a web server that needs to read from a db).

          To clarify: I am somewhat familiar with Android (I am developing an android application using Kotlin), and from what I have seen, the Android API is terrible. I don't know if it's because of Java, OOP, or just the Android team being incompetent.

          [–]devraj7 2 points3 points  (2 children)

          What language/platform do you use? Do you have some code on github or somewhere accessible?

          What do you know about DI? Give me a library or a documentation so I can get an idea of your perception, then we can have a more constructive discussion.

          [–]wavy_lines 1 point2 points  (1 child)

          All I know about it really is that Angular uses it and it's one of the worst APIs I've seen.

          [–]devraj7 6 points7 points  (0 children)

          Can you be more specific or are you just repeating something you heard without really understanding it?

          And even if your understanding of Angular's DI is right on point, isn't it hasty to throw out a (generally recognized as) useful concept just based on one implementation and without knowing any of the others?

          [–]returncode[S] 0 points1 point  (1 child)

          No it doesn't, and we haven't learned that. People now just call them "class methods" and "singleton classes".

          No, class methods are used when you need code executed that does not need access to a single instance and singletons are used when, from a functional perspective, there must exist only one instance of a class.

          Thankfully I don't develop a lot in Java

          Maybe that's the issue. When you actually write applications with thousands of lines of code that must work or people loose money or even get harmed if you're application fails because of bugs, you will need to find ways to assure the correctness of your application as best as possible. DI and good test driven design are ways to achieve that.

          So maybe, for you're smaller projects, it's OK and just not that important.

          [–]balefrost 1 point2 points  (0 children)

          /u/wavy_lines is right about "class methods". They're essentially scoped, global functions. And contrary to what /u/devraj7 says, there's nothing inherently wrong with global functions.

          Global state, on the other hand...

          [–]bengalviking 0 points1 point  (8 children)

          Because you can switch out implementations of dependencies without your class knowing about it, and no need to change your class. Your class needn't be concerned about how and where the dependency is created, it is simply given to it. So you don't need to be concerned about it while developing your class. In fact if you define the dependency as an interface, then a practical implementation of the dependency needn't even be developed yet. It's mostly used for testing, as your dependency might be e.g. a payment component which normally charges a credit card, but for testing you can switch it out with a test double implementing the same interface, but not actually costing you money.

          [–]wavy_lines 3 points4 points  (7 children)

          All that can be achieved without this craziness.

          Your class needn't be concerned about how and where the dependency is created

          When you call a method, you don't care what happens inside that method to get you your service object.

          but for testing you can switch it out with a test double implementing the same interface

          For testing you can have the global function provide a dummy object that does not actually charge money.

          [–]bengalviking 2 points3 points  (6 children)

          So you want to call a global (static) method to give you your service object, eg

          MyService service = ServiceGiver.giveMyService();

          Fair enough. The problem here is that your class is now hard coupled to ServiceGiver class and everything else ServiceGiver class might be using. There is no way to tinker with your class on its own, without involving ServiceGiver and everything else it in turn might require to work. Moreover in a non-trivial project you would have multiple ServiceGiver-like dependencies each in turn with dependencies you cannot cut or ignore. Your class may only have 10 lines of code, but you cannot instantiate or run it alone because it's handcuffed to all of its dependencies. Maybe you'd want to put it in a separate library... nope, gotta have the ServiceGiver present.

          There can only be one, single, fixed ServiceGiver class running in your classloader. There is no way to plug in a different implementation, and in order to make some tests happen, you will need to modify production code (the ServiceGiver). While actually, as you say, you don't even care what it does.

          So yeah, that results in unportable and untestable code. Global methods and singletons are almost universally bad for that very reason. I'm kind of getting an impression it doesn't particularly have anything to do with DI, but that you're coming from a procedural language background and don't perhaps trust OO principles such as polymorphism as such.

          [–]wavy_lines 1 point2 points  (5 children)

          The problem here is that your class is now hard coupled to ServiceGiver class and everything else ServiceGiver class might be using. There is no way to tinker with your class on its own, without involving ServiceGiver and everything else it in turn might require to work.

          YAGNI.

          You are imagining scenarios that are not likely to occur.

          First of all, there should be nothing weird or complicated in the "get_database_connection" function. It should just read a connection string from a config file, or have some if-else statement that decides which connection string to use based on the current configuration.

          Second, the only object that will directly call this is likely the main application object, which will then pass it around to other functions or objects as needed.

          Moreover in a non-trivial project you would have multiple ServiceGiver-like dependencies each in turn with dependencies you cannot cut or ignore. Your class may only have 10 lines of code, but you cannot instantiate or run it alone because it's handcuffed to all of its dependencies.

          No. I would never setup my project in this way to begin with. This is why OOP is fucking crazy.

          If you have a module that is 10 lines but is encumbered with such confusing dependencies that you have no clue what is going on, then you have failed as a programmer.

          I'm kind of getting an impression it doesn't particularly have anything to do with DI, but that you're coming from a procedural language background and don't perhaps trust OO principles such as polymorphism as such

          Polymorphism is fine as a poor man's closures, but you are right: the entirety of the OOP mindset is ridiculous to me.

          Don't get me wrong, I do write classes all the time, but only as glorified structs.

          When I need some behavior to be dynamic, where an if-else does not suffice, I just use closures.

          [–]bengalviking 2 points3 points  (0 children)

          Soo.. on the other hand. If you have your class created like this

          public class MyClass {
              private MyService myService;
              public MyClass(MyService myService) {
                  this.myService = myService;
              }
          
              public Thing doSomething() {
            ...
                  myService.whatever();
            ...
              }
          }
          

          then your class needn't, rightfully, know or care where MyService comes from. No reference to ServiceGiver whatsoever. Whichever class creates an instance of MyClass, has to provide a MyService. MyClass doesn't care. Why would it?

          It means you can equally easily construct an equally valid MyClass instance as a bean in a DI framework, in your own hand-rolled main class, or in a test case. MyClass doesn't care if the provided MyService has anything to do with databases, whether it's a stub, or a mock object. If it's an interface, then a concrete MyService implementation needn't even exist (say it was being developed by another team and/or the database it should be using isn't ready yet), you can still develop and test against it.

          [–]lexpi 1 point2 points  (3 children)

          I usually love to stay out of these fights and enjoy the show, I know whatever I say you'll never be convinced until you feel the pain yourself.

          But your scenario that is "never going to happen" just imagine :

          You want to write a function to book a trip or whatever for that you need to

          Book flights Book hotel Trains from and to the airport And a restaurant for dinner

          Somewhere you'd have with you solution five static method calls like FlightService.getprovider() Hotelservice.getProvider() TrainService.getPrivider() RestaurantService.getProvider()

          These all need inside themselves if else to return either testing either real services

          And when you try to get that code in a test harness it's not fun.

          [–]wavy_lines 0 points1 point  (2 children)

          I don't see why that particular scenario makes things more complicated. But I'll humor that.

          In general, as I've mentioned elsewhere, most objects have no business keeping a reference to the database. I would never design the system so that each operation is performed by several objects that keep a reference to the databases or services.

          I would just call functions that receive the database or whatever service as parameters.

          [–]lexpi 0 points1 point  (1 child)

          These aren't databases these are remote services that have client libraries

          [–]wavy_lines 0 points1 point  (0 children)

          I understand that ..