Java/SpringBoot/etc micro services developers have certain way of doing things and they are certainly going to hit lot of problems with Go. Since I have worked in typical Java/J2EE/Microservices project all my career, I think, for most devs coming from larger Java ecosystem, mapping their existing understanding to Go way of doing things is pretty much impossible.
gRPC and protobuf are just transport and serialization, they have nothing to do with business logic, on the other hand Spring is a heavy, bloated framework.
Most Java frameworks are complicated backed by layers of abstraction and black magic.
btw no framework does not mean you don't use any library, there are some good lib aka micro framework that have everything you need to build modern and decent api servers.
I hear that silly argument "no framework === rewrite everything from scratch" far too often.
There's a giant difference between libraries and frameworks! It's terminology: it's a framework if you build your app inside it. It's a library if you build it inside your app.
The later is fine. The former: I dislike it - even in JavaScript, Ruby, Rust or anything, I wrote a longer post on that[1], which got a lot of discussion on HN. Most of it too in the line of "lol, I use a framework because I don't want to write it all myself", completely missing the crucial first paragraph in which I carefully tried to explain the difference and explain that re-using code != using a framework.
It’s not convincing to just call everyone stupid. Everything is a trade off. You have no idea what those could be in any particular situation so that’s why your whole argument falls apart
Then you focus on construction and coding and ignore everything else a framework offers, which has downstream effects on coding and construction. It’s not all about the code. The coding is actually the easy part
The only projects ppl pay us is for the ones that are so large and complicated that if you don’t use frameworks, you’re going to either die or go crazy
I asked him what is a better way to quickly/easily stand up microservices/apps for clients (90% of my job), if not Django (or Flask/FastAPI, etc).
His response was "django is great, but it could have been written better and in another language" ... well, sure, great... but that doesn't solve my problem, lol.
We use Django for tons of client projects and rarely ever hit the "limitations" wall. It is mostly CRUD apps, so that helps but I would argue the time saved using frameworks in our shop is much more than the time lost spent on working around limitations. I do think the author has good ideas tho, good principals... but if you know your craft well, you know what will/won't work in a framework and how to solve that.
There’s always a better way to do things but we live in a fallen world. Some bullshit will always arise to make your life more complicated.
It’s like you said, when you hit whatever limitation, you’ll have to figure out a way around it.
I wish it were less acceptable to play the "balanced" person in the middle.
If and when there is a balance point, someplace where the actual truth tends to be, imho, it's almost never in the middle.
There are reasons those frameworks (and Golang, too) tend to do things in an opinionated way.
I wish there were more strong opinions lightly/loosely/weakly/gently/another-word-ly held[1]. I think opinions too strongly held is a surer path to there than starting from a place of trying to "meet in the middle."
[1] DDG-ing the term showed a bunch of adverbs of holding! Here are a some:
why it works: https://www.nwea.org/blog/2022/strong-opinions-loosely-held-demystifying-social-emotional-learning/
someone also said something on medium: https://medium.com/@ameet/strong-opinions-weakly-held-a-framework-for-thinking-6530d417e364
contrarians take a stand, too: https://commoncog.com/strong-opinions-weakly-held-is-bad/I’m not trying to meet anyone in the middle. I’m saying use a framework all the time, every time.
> there will be a lot of projects where Django is a very poor choice.
often and lot is crucial - it's opposed to all. Because it implies exactly what you then continue to state: that its our job to figure out if this project is one of those "lot [..] with a poor fit" or one of the ones where it actually, and will remain, a good fit.
But when I say premise is weak, it’s a technical term. Doesn’t mean it’s wrong.
I mean, in this case I do think that, but that’s why you’re getting so much pushback. Even if the premise was right, you’d still be getting pushback.
On the next post, remember to spend extra time there. It always comes back to haunt you.
Remember that the reader is smart but in a rush. The less words the better. Keep it country simple.
Often times you can get away with a subset of functionality which makes for a simple implementation.
> You may feel that building your services without a framework will take ages. Especially if you are coming from other programming languages. I understand that. I had the same feeling a couple of years ago when I started writing in Go. It was an unjustified fear. Not using a framework doesn’t mean that you will need to build everything yourself. There are many proven libraries that provide the functionality you need.
This is not true as blanket statement. It may. But with "a framework" you are bound by the architecture, upgrades, use-cases and so on that this framework covers. And limited by the ones it doesn't.
In practice, choosing a framework on day one of the project, means you cement yourself in architectural choices when you still lack all information about what architectures will be needed. You don't know your problem space.
All you know, for certain, is that his problem space will turn out different than what you thought it would be today. Flexibility to move along as this evolges is critical to "maintainability".
In practice, therefore, you'll quite likely end up with a framework that is severely harming your ability to write maintainable and congruent code over time.
For example, the code below is a complete Spring Boot application with all of the default configuration in place. It will take just a couple of minutes to have this running and it provides quite a lot of features under the hood - which you don't need to worry about.
@SpringBootApplication @RestController public class DemoApplication {
@GetMapping("/helloworld") public String hello() { return "Hello World!"; } }
- when things go wrong
- onboarding newer / more junior devs
For point 1, there are so many layers of abstraction and 20 page stack traces that you could fill an entire log buffer with just one NPE...
Kidding aside, I can't tell you how many times I've wrestled with the auto-configure magic. The reality is you'll include so many "starters" in a medium use app, you won't know whose including what. A polluted Spring container is a real problem. That isn't the only problem, but it's one of the more prominent. You may say "well write cleaner code!" and I would reply that Spring is conducive to writing code that doesn't fit well with the framework, and that's mostly because you have to understand 10+ years of architecture decisions when you want to do anything beyond the basics (That's why we mostly don't reach for the "Spring" way to do things anymore, just the simplest way). All that is to say, there is a reason Spring development has been supported by Spring consultants.
For point two, It's very easy get started but it's very difficult to mature into a fully productive dev. The things juniors and mids struggle with the most is unpacking autowiring and how to resolve those issues, how to properly handle async behavior (especially with Spring fully embracing WebClient and Reactor now), and database connections.
But yeah, outside of all of that, very easy to use, sure.
Because everything in Go is explicit you can actually follow a short series of function calls when debugging instead of staring at a 50-function stack trace with a bunch of obscure Aspect4J magic while you feverishly search the Spring JavaDocs for whatever specific error message you're getting.
Go is a dumb language and I like it. Everything's obvious and you can't get too cute. Now that there are generics the only thing that I'm really jonesing for is a decent collections framework in the standard library... generic map, filter, fold, etc. on slices would be a real boon for productivity IMHO.
It's usually search "baeldung spring <whatever I am trying to figure out>" and I get a nice article telling me how to do it but also explaining it as well so I can have the knowledge in the future.
I think the main author Eugen (there are many now) has a nice book.
My contention is Spring is great for those who have been initiated into it's ways and like to be the members of the Martian priesthood that sing canticles to the Omnissiah, but for those who want to understand what is going on and why Spring is anathema.
Uh no, you forget the part where you have to add a bunch of stuff to your build system (maven or gradle, usually), so it actually knows what to do with this.
You can't just compile that class with java -c, run it, and have a running application the way you could do it with lighter-weight frameworks.
I consider the boilerplate needed to build a main.go file that starts a gRPC listener to be harder.
The irony is that my team shifted from using spring boot to another framework for 'performance reasons'. Each instance only handles ~ 1k tps. Sighs
I think our industry would look a lot different if more companies were keeping their Java apps up to date.
This was my reaction. Every Spring app I've been involved with was a nightmare of gratuitous complexity that was nearly impossible to debug. I'm sure if I were a master of Spring I could figure it out, but that's the nice thing about Go--pretty much any programmer could work out what's happening even if they aren't particularly familiar with Go. You don't have to trace something from XML to Java, and there is basically no magic (maybe the odd bit of Go reflection is the exception to the rule, but it's much less common than in Java/Spring and the "magic" is much less magical).
I believe one thing that really tells the Java world apart from others is the heavy reliance on DI containers like spring/karaf/osgi etc. Once you understand that, everything is simpler.
I would say "believe me" in a face to face conversation, but even then it's proven useless :)
Working with Spring for me has become one of those things like when people suggest to "choose a boring technology" to build something. Yes, that's it. In the positive sense, of course.
There is literally an easy integration with everything you need, the learning curve is relatively smooth, and yes while it's true there are quite a few annotations you need to get used to, I believe after a few days you finally get used to it, and finally it simplifies a lot your development experience rather than making it worse.
For me the only reasons I would pick Go is because of native binaries (smaller footprint, memory, cpu etc), and it's "slim" for simple programs (like Python, but again binaries/native). I also like a lot Go's syntax so that's another pro.
Finally they are both very solid languages with strong tooling and wide communities.
Ps: the cool "new" guy seems to be Quarkus, though :)
“I’m less productive in Go compared to Java Spring” => “the whole world is less productive in Go compared to Java Spring”.
I had to: manually manage sessions and jwt token Implement message flashing
Even reading data from a form was a little too verbose for my liking
A framework is an added friction to picking up a development environment but potentially a huge asset to velocity once people are up to speed. You haven't gotten properly up to speed in that framework and that site's use of the framework. Perhaps you never spend enough time in that domain to really need to pick it up, in which case you'll always pay the "WTF is this?" tax.
But it's equally likely that once a person's up to speed in the framework they're efficiency is greatly enhanced.
A programming language isn't just the syntax of the language; there's also knowing the common idioms of the language, understanding the runtime / build environment, knowing when and how to leverage the standard and extended libraries/package ecosystem, etc. Frameworks fall into the "extended package ecosystem" which is vastly different from language to language, and sometimes _within_ a language if the language is sufficiently mature.
Some of it is "just math" and some of it is understanding the culture.
I agree Spring Boot brings a lot to the table (Spring Security alone, for example), but at the cost of significant downsides.
I see the benefit for larger and more diverse teams, but personally I would choose lighter-weight frameworks and libraries, even if at the cost of having to do more plumbing myself.
I have found Spring Boot to be a step forwards from the old Java EE world in basically every way except for this. Transactional boundaries are somehow more difficult to analyze.
This perfectly explains my problem with the fx library, and why so many java devs seem to gravitate to it
I've been working in Spring framework for years, and don't understand it. I suspect most of the people who develop it don't understand it either, as it's so enormous it's probably impossible for any one human being to really understand it.
I don't understand speculative execution or any of the other deep voodoo that happens in modern CPUs that spend enormous amounts of energy presenting the "I'm a PDP-11/70 with way more memory and bigger registers" lie to programmers.
These days I'm not even sure which part of my computer is running the networking stack, or where my computer is located.
We stand on towers of abstractions, and complain about the ones we're forced to notice. I don't think many people understand "it" these days.
Spring boot does put a layer of abstraction over ordinary “linear” code, but it is not black magic, if you understand its DI part, you will basically understand everything (in short, spring is only allowed to generate new code, not modify existing one. So it works its whole “magic” by generating subclasses at runtime. With this requirement in place, most of its working makes clear sense. It has an internal list of available beans, and you can inject them by type only (@Autowired/@Inject) when it is the only bean of said type, or you may have to be more specific by naming the desired bean. And it is a simple graph of such injects.)
And it is a well-understood convention, above all. I can go to another spring shop and expect to see JPA entities annotated the way I’m used to (which is another very powerful feature. Can it be misused? Sure. Does it save a shitton of time, and less code means less bug? Yep. Plus, before the “ORMs considered harmful” people join us, they were always meant for OLTP, not OLAP, and as a mapping to/from db records, where they absolutely shine. Don’t try to OUTER JOIN on a subquery of whatever with them, but feel free to write your SQL and map its results to a business object).
You don't get type safety for your database queries without jumping through hoops (compare anything it provides to LINQ — it's not even in the same league). Hibernate feels like a significant step-down after Entity Framework (I might be an idiot who doesn't know how to use it, that's entirely possible, but this just proves the point — it was easy to get started with EF, it didn't require a doctoral in ORM studies to become proficient with, it's dead easy to write queries for (thanks to LINQ), and the vast majority of those translate to pretty efficient SQL which is fine for 99% of my queries).
You get lots of behavior decided at runtime (while ASP.NET for the most part is very explicit in its configuration).
It also doesn't use many annotations (most of those I use are fully optional, like adding pretty names to database columns; and those can be configured through explicit method calls).
It does require DI (and IoC containers are swappable if you don't like the default), but I didn't have nearly as many issues with it as when working with Spring projects, whatever the reason may be.
I mean the use cases of that will be limited these days; application architectures have changed to the point where what used to be a module within a Spring application can now be a microservice to be enabled or spun up depending on rules defined outside of the application.
But this is a very superficial point of view, I haven't seriously touched Spring for a decade and, thanks to some experience with Go, I feel like I won't need to either for most modern-day applications.
While Go may not be for everyone or for every application, its mindset of keeping things simple, just use the SDK or some libraries, etc does make for better developers. IMO.
I think it's fine for small teams not to use frameworks, and maybe 200 person engineering orgs are made up of many small teams who just want to agree on a protocol rather than shared framework/platform but once the scale starts to increase you really need to start tightening up and implementing some better standards.
People constantly talk about not being Google, well let me tell you the people scale is all the same, the amount of legacy infra is all the same. If you haven't peaked into the depths of the messy multi-decade enterprise you have no clue. Your 4 year old company that you joined 6 months ago is no comparison to something with a legacy of 3 decades with 2k+ engineeers scattered across a disparate org trying to modernise in the cloud or whatever comes next.
Full disclosure: I work on https://micro.dev - a framework for Go
No-framework Go makes the most sense to me, because a big framework doesn’t make sense for all types of project, and the set of projects where I’d reach for a big framework just doesn’t intersect _at all_ with the set of projects where I’d reach for Go.
When I'm working on personal projects, frameworks don't make sense for me. When I'm trying to engineer something at scale e.g https://m3o.com then I need that standardisation at the platform layer, the framework layer, the API layer.
What I'm saying is that I find business logic-centric API services to be a good fit for larger frameworks that take ownership of more of the low level logic, and I don't find Go to be a good fit for those, at all. Inversely, I find Go to be a much better fit for the more "technical" services (provided we're not at the must-squeeze-every-ounce-of-performance C++/Rust level of requirements), but I also don't want a framework getting in the way.
In my experience the problem with this kind of conversation is that you can actually have a pleasant experience in all permutations of the above. Since people have a ceiling on the number of projects they have worked on for a long enough time to have a reasonable opinion on the approach, they come out of this with massive biases and cannot accept that others have had pleasant experiences on the same tools and team sizes if they have had an unpleasant one.
I _promise_ you that you can absolutely have a relatively long-standing codebase without a framework that is a dream to work on and has been touched by many engineers in a huge corporate setting. Similarly I could show you absolutely unworkable travesties that have to eventually be rewritten despite being written with frameworks that claim to prevent this kind of thing occurring.
Conversely, you can absolutely have a “relatively long-standing codebase” with a framework “that is a dream to work on and has been touched by many engineers in a huge corporate setting.” And I could show you unworkable travesties that have to be eventually rewritten despite being written in library-only microservices that claim (because “micro”) to prevent this kind of thing from occurring.
Whether selection bias from your experience or an appeal to authority, there isn’t much to your argument. To me it just sounds like comparing well managed to poorly managed codebases.
If I have to manage a team, I’d much rather have the framework laying the groundwork for documenting “how we do things” than rolling consistency out ourselves.
For our small-time ops use we ended up on Gin/Gorm/Zap/Opentelemetry + some code for internal SSO and it works fine but I'm slowly thinking of making a wrapper that preconfigures that setup as there is pretty much same boilerplate repeated between many projects.
Ah, so an organization so bloated that you have entire teams "managing platform tooling" (whatever that means) instead of iterating on features customers actually care about.
If you look at the problem more holistically (say "run a reliable service customers want to use") then that metric is just one of many, and more often than not counterproductive vs some other metrics like maintainability and resilience for instance. IME frameworks reflect that and only let you write code fast, or get the hello-world-demo out fast, but neglect the later stages.
I don't know if the conclusion is no framework is better overall, but the frameworks i worked with at least showed mixed results overall.
For instance, when Oauth became popular I was maintaining several apps where the original authors had never dreamed of an alternative login method (email and password had been the norm for longer than any of us had worked as developers).
The Rails apps required a few small config changes which I could get from the documentation then HTML for the "Login with Facebook" button.
The framework-less apps were disasters. Each had their own way of doing things. Some used libraries that were no longer maintained, others had rolled their own authentication workflow or half copied the code from another project.
There is a lot to be said for frameworks when facing an unpredictable future. There is a cost to be paid up front as far as learning the framework but the benefits on the back end are enormous.
What Rails configuration would be pertinent to Oauth? Perhaps you mean the application was already using some kind of third-party authentication library (e.g. Devise) that supported Oauth? If that's the case, weren't you just lucky that the developers happened to choose a library that 1. Was still being maintained. 2. Had already added Oauth support?
Most of the Rails apps I have encountered in my career (especially those predating Oauth popularity) used hand-rolled authentication, so it seems that you could have just as easily fell into the same trap you saw elsewhere. It is not clear how Rails saved you here.
So many hours wasted investigating fringe http2 characteristics causing odd bugs on the platform.
Outside of Go (I assume because it seems pretty popular there) the clients for other languages are so hit and miss.
I had to pipe a json into the python client to configure a grpc client (which seems bad) and it took me a while to dig up the correct incantation.
I like the "contract" that GRPC implies but I am not sure I would choose it again.
It sounds like this would lead to more reinventing the wheel than I'd like to see in a product like a web app/service.
I don't miss the days where I had to deal with random missing or conflicting beans stopping my app from starting. The nice things about a Go app is because the control flow is so exposed, if it compiles you can be pretty sure it is going to run, and if it doesn't compile you can go to the red in your IDE and fix it.
Adding an endpoint is a matter of updating our OpenAPI file and doing `make oapi-gen` for the code generator we use. I think this is a similar level of effort to doing the same with a mvn or gradle command.
The real difference I notice between Go and Spring microservices though is how much easier it is to dev and debug multiple microservices - it is trivial to compile all of our Go microservices and boot some of them up for debugging without eating all of my laptop's RAM, which is especially relevant if I also want to run them in Kubernetes locally.
I will say I do miss some of the niceties of aspect oriented programming with Spring.
Understanding how the framework wires things together is important.
And then what we are left with is a huge, old project vs some new microservice, which would be an unfair comparison in any language
Most of the useful stuff in Spring is just thin wrappers over other libraries (including the standard library) anyway.
Spring is more like traditional application development, where you revisit your code multiple time during its long life cycle. In comparison, Golang is more like spit it out fast and forget. Its syntax is so dumb that you can’t possibly misread the code from any angle, so maintenance is also brain dead simple.
In this aspect, using frameworks in Golang simply defeats the point of using the language, because frameworks make codes harder to read. The language is to be used like C, where (almost) everything is manual and explicit.
That's very much a matter of opinion. In my opinion, making every manual and explicit makes it hard to read if you're trying to do anything vaguely high level, because you lose the forest for the trees.
I didn't need to read the rest of the comment after this.
Assuming this means grpc-go, that's a framework. Perhaps your seemingly negative experience with it actually echoes that the best Go framework is no framework, contrary to your opening position?
Those things were basically first implemented in Java. We could argue about subtle differences between Avro and Protobuf but I'm not aware of any credible competitor to gRPC on the JVM in the last 10 years. Thrift and Avro RPC libraries died out years ago, Akka clusters are rather exotic.
It means literally nothing. A huge company making lots of money has no relation to the quality of its code, processes or tools.
That's not only true for non-tech companies, but even the heavily tech ones whose all products are software.
If you don't like GRPC and Proto, use REST. `http.Client{}`, boom make a call.
Go is built for microsevices. It probably has the best std library for web services of any language.
So much money was wasted writing and maintaining those frameworks that was so flabbergasting.
We are more people, we are more experienced and have a decent engineering culture. Yet we're definitely less productive than the last average, traditional Java Spring Enterprise team I've been in. "Circumventing" a framework restriction (which rarely happens if you stick to good practices) is MUCH less effort than building things yourself from scratch.