Hacker News new | ask | show | jobs
by adamors 464 days ago
Never got the point of porting X framework from Y language in order to

> simplifying the learning curve for Y language developers

You'll just end up writing the same old patterns in the new language as you did in the old one.

Especially with Go, it's really easier to adopt the existing tooling (most of which is in the standard lib) than to port whatever concepts Laravel/PHP had.

2 comments

Not sure there's a Go equivalent of Laravel, so not sure which tooling you suggest people adopt. If I want an all inclusive MVC (or similar) web development framework with all batteries included - why not build a Go Laravel?

Python has Django

Java has Spring (among others)

C# has asp.net

Ruby has Rails

PHP has Laravel

What does Go have?

Go has a simpler approach that encourages you to express yourself more directly, does away with heavy frameworks that take longer to learn than the language itself, and it encourages you to structure solutions in mechanical sympathy with the problem rather than start with a solution and then try to adapt the problem to a given solution.

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.

But CRUD is a solved problem, and don't forget about essential complexity, which can never be avoided.

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?

> 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.

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#.

If your problem can be solved with CRUD alone, sure. However, that is usually only a starting point. And if you optimize for the smallest and simplest part of a problem just because it comes first, you may not be looking ahead.

It isn't like writing a basic CRUD-application in Go is a lot of code.

We are talking about Laravel. The primary way to interact with your app is either via HTTP requests or not, there is not much in-between, so I don't really get your point.

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?

> 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?

So you are saying this is only possible if you use a large framework? You cannot do this with libraries? That's a very odd position.

JSON has never been a problem as it is part of the standard library. And there are lots of libraries to extend the functionality if you need something the standard library doesn't offer.

Heck, Go even has ASN.1 in the standard library so I can write custom serialization of certificates to satisfy fiddly crypto components that only work with certain representations. And it was surprisingly easy to do. If it is one thing Go is really good for, it is writing robust code for transforming data.

Learn to do things using the standard library first. Then learn what libraries to add and keep a collection of snippets and notes on how to use them so you can apply them quickly when you need them. Learn once, take notes, use again.

> Well, what about converting strings to business data structures safely? What about complex JSON parsing, serialization

Those are solved problems in Go's standard library. And let's be fair: while some frameworks do a lot of stuff, the majority is very bare bones and just automate serialization, so compare with the average. And some even cause even more problems than they solve (Rails mass-assignment).

> CSRF

Available in several routers, if you choose to use a custom one, or in the form of middleware if necessary.

> preventing injections

Which kind? For SQL, database/sql provides the tools necessary for avoiding SQLi, and requires the same care/discipline you'd need on a big-framework app. For XSS just use the builtin facilities of html/template rather than reinventing the wheel.

> session cookies

Library, if it's not in the router of your choosing.

> authN/authZ

Once again, let's be fair. AuthN didn't exist on Rails for 20 years, for example (and is still quite bare bones compared to libraries). AuthZ still doesn't. In Spring and .NET both also require libraries. So just use a Library in Go?

> easy database CRUD operations?

What's that, ORMs? SQL Generators? They do exist in Go.

I‘d encourage you to seriously give Laravel a shot.

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).

Ultimately, you’re going to end up with a framework anyway as your internal hand-rolled solutions congeal into some sort of standard. Only it’ll be all novel and unique, maybe lacking effective documentation, and it’ll take even the most seasoned engineers time to settle in to it.

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.

After 8-9 years of Go and having about 20 smaller and bigger backends under my belt: no, nothing that looks like a framework has emerged. Not in my code or in that of any of my colleagues. What has emerged is consistency in how we structure certain things. But there is no frameworks needed for that.

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.

I agree with the sibling poster.

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).

This whole comment has strong C language “we don’t need a package manager, we write everything ourselves” vibes.

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.

My work has 50 eng teams. We started on django and our internal standards team have depreciated it - no further projects in django. We are applying the strangler pattern the best we can, everything new in Go if we can.

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.

> “we don’t need a package manager, we write everything ourselves” vibes

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.

Go has go. You don’t need a framework when http can do pattern routing and cookies, database/sql can do data, and json is baked in.

It was literally designed to do away with this choice confusion and provide one path to servicedom.

The standard library.

It’s honestly feature rich enough to do most things that the only other dependencies we really need to pull in is some third-party SDKs (e.g. AWS) and our database driver.

I assume you have never used Django or Rails or Laravel then. With these, you get a web application with routing, middleware, schema validation, database connections, an ORM, authentication, sessions, job queues, email sending, distributed caching, dependency injection, logging,secret handling, view template rendering, websockets, metrics, and much more—right after the installation, set up with conventions allowing other developers to get productive immediately.

Comparing that to the go standard library is apples to skyscrapers.

It's so obvious when someone hasn't even looked at those 3 frameworks because they think those are just some simple routing/controllers + ORM, lol. That's like 10% of the total functionality they offer, not counting all the extra stuff provided by their respective ecosystem.

I don't mean to knock on Goravel or things like Apollo, but they got a very very long way to go to even measure up against Django, Rails, or Laravel in terms of functionality.

Almost everything you listed already exists in the standard library.

And for the little that’s not, such as an ORM, there are many third party libraries available if you want to go down that path although it’s not necessary.

There’s nice things about a lot of these frameworks for sure, like ActiveRecord, but you usually just learn the patterns in Go and roll with it. The standard library has its own consistent style.

> Almost everything you listed already exists in the standard library.

That's a bold faced lie. In the list, the only things provided by Go are:

- routing: http.ServeMux has a router but until recently it was usually not used in real applications due to very limited capabilities (they finally added proper patterns in 1.22 which, in my view, finally makes it good enough).

- template: it's not even close to laravel's blade capabilities, but yes Go has good enough templating for most tasks.

> routing, middleware

net/http (even middlewares are just http.HandleFunc)

> database connections

We were using database/sql for the longest of times before switching to pgx since we wanted some convenience functions.

> email sending

net/mail gets you far enough unless you want to scale it.

> logging

log/slog (which is actually production grade compared to log/log)

> view template rendering

text/template, but I also think Laravel is a better choice if that’s your main focus.

Others either need an experimental standard library package (e.g. golang.org/x/crypto/argon2 for stuff like authentication) or finally need third party dependencies. DI is not enforced like other frameworks, but an extremely common pattern in Go.

At this point, do I really want to bring out a whole framework just for the last few requirements?

Just my two cents how we do it in most of our projects at this point (~70 services in Go):

>routing, middleware

ogen (OpenAPI code generator), or a similar library

>database connections

from Go's stdlib mostly

>an ORM

sqlx (a lightweight wrapper around Go's stdlib which allows to hydrate results into structs)

>authentication, sessions

homegrown stuff, due to existing complex legacy stuff

>job queues

RabbitMQ's official Go wrapper (rabbitmq/amqp091-go)

>email sending

we delegate to a few separate VMs which already have postfix installed (and have good reputation)

>dependency injection

manual construction, works fine if split correctly

>logging

sirupsen/logrus (structured logger)

>view template rendering

React

>metrics

official Go wrappers for Prometheus

Some of this stuff is already IMHO industry-standard (the default libs people reach to). To streamline creation of new services, we have a tool which can scaffold your project with all these dependencies already set up.

Im not saying all of this isn’t possible in Go, or somehow worse. My point is that using eg. Laravel, you don’t even need third-party libraries for these things, just the framework. And all of it is built on the same conventions, documented in the same place, with the same API. Scaffolding is built-in too.

All of the time you spent on building your scaffolding tool, researching on the libraries, checking and updating their version regularly; all of that isn’t necessary with a full-stack framework.

Once more: I’m not dismissing Go, or your way to set up projects, I’m just surprised someone would make the comparison to the Go std lib, which is so obviously not on the same level of integration and battery inclusion.

> email sending

It's as simple as calling smtp.SendMail("hostname:smtp", nil, from, to, message)

It’s not. One thing is sending batches of transactional mail to thousands of recipients in a production web application running on a bunch of replicated containers on ephemeral machines, the other is proof that SMTP theoretically works in your programming language.
>job queues

In Go, these are called "channels".

Channels are equivalent to job queues the same way walkie-talkies are equivalent to emails.
We now have GO's equivalent of Rails and Go's equivalent of Laravel. Apparently Go's way is "start with the standard lib and glue whatever you need on top".
> If I want an all inclusive MVC (or similar) web development framework with all batteries included

I think that maybe you shouldn't want that. Go is a simple language with a very extensive standard library. It's quite easy to do most things you would want by just writing some code, leveraging the standard library, and maybe including a handful of external libraries. Frameworks are not needed and will eventually just get in the way.

> It's quite easy to do most things you would want by just writing some code

OK, I want a similar thing to ActiveRecord - with all the features, is that quite simple to build?

Now you'll tell me I probably don't want an ORM at all. But lets say I do, lets say many people find value in these things.

> I want a similar thing to ActiveRecord

First of all, you shouldn't be using Go, because it's not the language where you do those kinds of things.

I personally believe ActiveRecord is a gigantic anti-pattern and should be avoided at all costs (by anyone, ever). And I also happen to have had very bad experiences with ORM and feel like most of the time they are not needed at all. So yes. But even if you want an ORM, there's a few popular ORM libraries. You can just include one and start using it, no need to use a framework for that (for ActiveRecord I wouldn't know).
Even when using frameworks, typically Go devs, from what I see, prefer something simpler, like Fiber or Echo. Then they plug any libraries the like on top of it.
I live Django, but you cant compare it to Latavel, which is much more extensive
JavaScript (Too many to list)

TypeScript has NestJS (among others)

Elixir has Phoenix

go has go, and for ORM, it is better to go with sqlc.
In my experience building the site with Go (Echo) with Postgres and a vanilla frontend from scratch, I realised that maintaining my codebase as a solo developer for a medium-sized platform was challenging. At one point, it became unmaintainable, and I had to rewrite it three times. The third time? I switched to the Astro web framework, and it solved all my problems.

Go is indeed easy to get started with, but it's different when dealing with server-side rendering and not a single-page application where Go is a backend.

Can you go into a bit more detail about what became challenging and what Astro helped you solve?
At first, my goal was to go pure with vanilla JavaScript and CSS, hand-coding Echo routing, authentication, secure cookies, etc., using Go libraries—and I did just that. But as a solo developer managing both backend (Go + SQLC) and frontend (vanilla JS + CSS), it became overwhelming. My co-founders had no concrete feature roadmap, throwing in whatever they thought was good, and our UI/UX designer was stuck with a buggy Marvelous app. Managing both sides while constantly adapting to shifting requirements became exhausting.

To ease the burden, I introduced Alpine.js, which helped, but the real challenge was juggling Go and TypeScript for different parts of the stack. When the team decided to revamp the site with a new Figma design, I switched to Astro after the release of Astro 2.0—it simplified frontend development and allowed me to gradually move away from Go. This wasn’t just about adopting a new language with old patterns; it was about making my workload sustainable while improving maintainability.

A month later (after three years), bad news—they ran out of funding and had no time for marketing. On top of that, I have vision problems (genetic and post-cataract surgery), making job options limited. But one thing I’ve gained from this experience is a strong grasp of frontend performance optimisation—JavaScript, Tailwind CSS, HTML, and responsive images. There are millions of poorly optimised websites that Astro could improve. At least in Singapore, where we have great internet connectivity, I can keep refining my skills.

Astro solved:

- Same codebase: Both frontend and backend with TypeScript, meaning I no longer have to write routers whenever we add a new category.

- Optimisations: Reducing JavaScript and loading JavaScript as a module for better security.

- Maintainability: Go HTML templating was harder to maintain; I prefer Astro’s JSX-like syntax.

- Performance: If I need performance, Bun can be as performant as Go, which is a bonus.

- Reusability: Lots of UI and Astro components can be reuse.

- Productive (Future): I’m waiting for Vite (Rolldown) to speed up my build times. Evan You has lots of ideas for Rolldown plugins.

- Community: Of course, an active community that is improving Astro so we don’t have to reinvent the wheel, with lots of sensible features by default, including Starlight for docs. I proposed to the Echo maintainer to adopt it over Docusaurus, but I was turned down.

The frontend is always going to be a pain since you have to deal with JS in some form, and a culture of ever increasing complexity until people give up and rewrite everything and throw away years of work.

When you have Go, I don't see how switching to JS/TS comes with any benefit on the backend.

At some point I would have liked to meet people who struggle using Go on the backend and learn what their process is and how they structure things. I've written quite a few backend systems in Go for a variety of domains (anything from PKI systems to industrial automation and various real-time streaming systems). Surely people who struggle must either do something that is very different from what I do, or be sensitive to entirely different issues than I am.

This is an LLM response if ever there was one.
Wgats your Point?