Big frameworks are extremely limiting. They also make escape harder when you realize how limiting they are.
I tried to like various frameworks during my time as a Java developer, but they always end up costing projects more than what they save. In terms of time, clarity, performance, adaptability and maintainability. Decades ago I too used to think they might help, but I was never able to observe any real positive effects over time.
You can always do better when you start with the domain you are solving and work from there rather than trying to adapt your domain to some generic solution.
The reason Go feels more productive than Java is because in Go the community seems to understand this fairly well. So the whole ecosystem is built around libraries that are easy to compose rather than frameworks that try to coerce you.
Big frameworks are not really helpful. At best, they are occasionally fashionable, which tricks people into thinking they are better off solving problems the wrong way around.
Reinventing that basic logic takes a lot of code and time for a bug-ridden, worse, half-implementation. And on top it will be completely home-grown, any new hire will have to learn it from the barely existing internal "documentation" that wasn't touched in years - making not only initial development multiple times more costly, but every subsequent maintainance as well.
Meanwhile I can just add 3 annotations in Spring/RoR/Django and have solved the problem in a way that a competent new hire will instantly be familiar with.
Also, even the supposed benefits are questionable at best - mechanical sympathy? Like, most of these frameworks sit on top of a highly efficient C web server that just calls some business code for nanoseconds and that's all the "overhead". Python and ruby backends are all over the web and they perform completely fine, even though these are interpreted languages. Java/c# won't even have that problem. I have seen plenty terribly performaning home-grown solution which were designed by a "smart" software astronaut - it's almost like writing a proper web server is a different skill set than typical CRUD business apps.
And lastly, Go feels more productive because it is chock-full of boilerplate. So you can type and type and feel you are so productive, meanwhile in another language you would have just added an annotation and 2 lines and called it a day - it's just a psychological "trick". And "libraries that are easy to compose"? Like, which language has an ecosystem with libraries that are hard to compose? What tools do Go have that would aid in that? I would argue that a more expressive language have way better tools to help with code composition, wouldn't it?
If you're building apps that are understandable to new hires, you're right: it's all just boilerplate CRUD.
> Python and ruby backends are all over the web and they perform completely fine
Python certainly doesn't. I've got one inherited service running in Python/Django, and it quickly grows to 1GB per worker, and even then manages to be so slow larger queries time out. I've written two new services in go, they get more traffic, and they run in 20-60MB, with peaks over 200MB. I can run both services and multiple development versions on a 2 CPU, 4GB machine with room to spare.
> in another language you would have just added an annotation and 2 lines and called it a day
I sincerely doubt that. The only boilerplate in go is the error handling. The rest is comparable to Java/C#.
It isn't like writing a basic CRUD-application in Go is a lot of code.
There is a very well defined architecture for the CRUD part that gives itself to "frameworkification". That part is free to call out to any other business code you deem necessary, this is such a surface you can trivially build on. Your software does complex route planning? Sure, have an endpoint that specifies a config and call out to however complex logic you need, and return the result (or just that you are working on it, and another endpoint will later be available for the results or whatever). But not everything gives rise to such stable surfaces.
> writing a basic CRUD in Go
Well, what about converting strings to business data structures safely? What about complex JSON parsing, serialization, CSRF, preventing injections, session cookies, authN/authZ, easy database CRUD operations?
I’d fundamentally disagree on it being harder to learn than the language itself.
> You can always do better when you start with the domain you are solving and work from there rather than trying to adapt your domain to some generic solution.
I’d even agree! In my view this as a reason to go pro-Laravel and similar opinionated frameworks. They allow you to focus on what actually matters, which is your specific business logic.
Define your data models and the rest follows automatically. Use API Platform to automatically generate a REST API from just your models. Need custom logic in there? Use middleware or define your own routes. You’re really not being hindered by the framework in any way I can think of.
Laravel is truly a beast and IMO not comparable to older Java frameworks.
You don’t have to use these features tho. You don’t have to use the ORM and you could even write your own routing if you really wanted to. To me, this is what makes a good framework: providing everything out of the box for 80/20 solutions and provide appropriate escape hatches if you ever need to do something entirely custom.
Want a react frontend? Use Intertia and get started writing UI and interactivity instead of setting up data flows. Want automatic backends? Use Filament and get Schema-based forms and tables for free.
But I have yet to encounter web app use-cases that go beyond of what Laravel could handle.
Something like this in the Go world would make a great addition, provided there are alternatives and escape hatches present (idk if that’s the case).
Many good frameworks actually started that way, with the open source community stepping in to support. Suddenly loads more people know it and you can depend on that spread of knowledge.
To that extent it’s not that frameworks are unhelpful, they are in fact force multipliers for solutions in the same problem space (e.g saas web dev).
In a similar vein, I think I’d much rather build a game in Godot or Unreal than start framework-free with SDL.
And it is not for lack of asking myself if I wouldn't be more effective if I distilled the practices into some framework. I've had plenty of ideas for frameworks and I always end up throwing them away. The way I structure things is so minimal anyway that there really isn't that much you can gain by creating a framework.
The closest I come is tooling to kickstart projects by using a template driven code generation approach. But that's mostly possible because the way I do things is consistent enough that I can generate the initial code for things like the model types and whatever crud and API I need.
In my 35+ years as a professional developer I have yet to see frameworks actually being force multipliers over time. They tend to have a small window where they look attractive. Then they tend to become a liability at some point.
This post underestimates how much custom code and structure ends up in larger projects that use a framework, or even game engines.
Every single medium-to-big project I worked on for the last 25 years had a different structure and code style, regardless of using a framework or not. Other than the folder structure for the basic structures (often the M, the V and the C), everything would be different. There would be folders for different new "things", but these "things" are always different. Plus with multiple modules for encapsulating business logic that rarely had anything from the framework itself (except as leaky abstractions), different libraries for managing the business logic, etc.
Sure, trivial CRUD apps will always gonna look similar. But at this scale it doesn't matter much
And Go is actually refreshing in this regard, because people actually try to avoid those crazy abstractions. Rails is possibly the worst of the bunch, because it requires way too many third-party libraries for basic stuff (authentication and authorization), and I once even had to order a paid book to get documentation on a specific framework that the previous team who built the app used but didn't provide any documentation online whatsoever (Trailblazer, for the curious).
The benefit of something like Django is it provides strong convention, loosely enforced. Everyone on your team needs to know one thing. Everyone can understand the convention, understand each other’s code, new features get added the same way. But it’s also loosely enforced, it’s just Python. So when you need to split from the framework’s convention, you have unlimited escape hatches.
If you want a case study, see Instagram.
The django code is so intertwined and full of circular imports. Custom db managers to handle our multiple dbs with read-replica routing, custom caching solutions, and everything inherits from something and base classes have insane child-type checks and methods that are only used in one child class. And due to the ease of passing query sets around, we have complex and slow joins and n+1 queries everywhere. And object properties that are actually methods that call and cache from the db, so sneaky n+1.
The unlimited escape hatches in python has turned into welded spaghetti making development and organizational velocity slow.
Then I'm afraid you misunderstood.
Frameworks is not the only way to build things efficiently. It is actually possible to build things using libraries and consistent ways of structuring things.
Also, we're talking about Go, so please use Go examples. Django isn't interesting in this context. Have a look at how you'd leverage the standard library, and perhaps a couple of libraries in Go to do the same.