Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Umm, doesn’t Go do so as well? Personally, I’ve had a better experience working with Go tooling.


I'd say they both optimize for DX, but they come at it from very different angles. Ruby is focused on actually writing the code: making it feel expressive, intuitive, and fun.

Go is more about making it easier to build fast and robust systems. But it really doesn't care if the code itself is ugly and full of boilerplate.

As I've gotten more experience, I've come to really appreciate Go's tradeoffs. It's not as fun up front, but on the other hand, you're less likely to get server alerts at 4am. It really depends what you're building though.


Go ecosystem is generally good. However, given that Go as a language doesn't have any "fancy" (for the lack of a better word) syntactical features you can't create DSL's like this

though Ruby's expressiveness comes at a cost and I'd personally stick with Go in a team but use something like RubyLLM for personal projects


I'm wary of equating "ability to create dsls like this" with "prioritizing developer experience".

Ruby and go each prioritize different parts of the developer experience. Ruby prioritizes the experience of the author of the initial code at the expense of the experience of the maintainer who comes later. Go prioritizes the experience of a maintainer over the experience of the initial author. Both prioritize a developer, both de-prioritize a different developer, and which one makes more sense really depends on the ratio of time spent on writing greenfield code versus maintaining something another human wrote years ago who's long gone.


I disagree with the idea that Go prioritizes the maintainer. More lines of code typically makes maintenance more difficult. Go is easy to read line by line, but the verbosity makes it more challenging to understand the bigger picture.

I find changes in existing Go software often end up spreading far deeper into the app than you'd expect.

The runtime is fantastic, though, so I don't see it losing it's popularity anytime soon.


> More lines of code typically makes maintenance more difficult.

That’s kind of just the surface level of maintenance though. Go is not so much focused on making it easy to read a single file, but on minimizing the chains of abstraction and indirection you need to follow to understand exactly how things work.

It’s much more likely that all the logic and config to do something is right there in that file, or else just one or two “Go to definition” clicks away. You end up with way more boilerplate and repetition, but also looser coupling between files, functions, and components.

Contrast that to a beautiful DSL in Ruby. It’s lovely until it breaks or you need to extend it, and you realize that a small change will require refactoring call sites across a dozen different files. Oh and now this other thing that reused that logic is broken, and we’ve got to update most of the test suite, and so on.


> or else just one or two “Go to definition” clicks away

This is the biggest part of it: maintainers need static analysis and/or (preferably and) very good grepability to help them navigate foreign code. Ruby by its nature makes static analysis essentially impossible to do consistently, whereas Go leans to the opposite extreme.


I've found for years that ctrl-b works pretty damn well in Rubymine as well as Goland. Huge advantage vs other editors 5+ years ago. I wonder if the difference is still as stark in the age of lsps?


Surely you can have semantically the same API in Go:

    // Must[T](T, error) T is necessary because of Go error handling differences
    chat := Must(gollm.Chat().WithModel("claude-3-7-sonnet-20250219"))
    
    resp := Must(chat.Ask("What's the difference between an unexported and an exported struct field?"))
    resp = Must(chat.Ask("Could you give me an example?"))

    resp = Must(chat.Ask("Tell me a story about a Go programmer"))
    for chunk := range resp {  // Requires Go 1.23+ for iterators
        fmt.Print(chunk.Content)
    }

    resp = Must(chat.WithImages("diagram1.png", "diagram2.png").Ask("Compare these diagrams"))

    type Search struct {
        Query string `description:"The search query" required:"true"`
        Limit int    `description:"Max results" default:"5"`
    }
    func (s Search) Execute() ([]string, error) { ... }

    resp = Must(chat.WithTool[Search]().Ask("Find documents about Go 1.23 features"))
And so on. Syntax is different, of course, but semantics (save for language-specific nuances, like error handling and lack of optional arguments) are approximately the same, biggest difference being WithSomething() having to precede Ask()




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: