3/12/2026 at 12:38:30 PM
I love Rails, but after working for a few places with huge Rails codebases and then several other places with .NET and other frameworks with actual typing, I just can't go back to Rails for anything that isn't a personal project.Working with a large codebase with an untyped codebase is just a nightmare, even with powerful IDEs like RubyMine that are able to cover some of the paint points. I wonder how good Sorbet is these days, though, especially the RoR experience
by sensanaty
3/12/2026 at 12:57:28 PM
Rust/Loco is unironically the most interesting framework right now.Loco follows up the Rails formula pretty closely, and makes easier to learn Rust by taking care of a load of boilerplate code.
by paride5745
3/12/2026 at 1:47:12 PM
Concur on most interesting! I really hope it works out, but am cautious.It is surprising to me seeing the rust web backend scene; many libraries, server frameworks, and users, but they are all Flask-analogs, without the benefit of the reasonably-robust ecosystem Flask has. My suspicion is that people are using them for micro-services and not websites/webapps, but I haven't been able to get a straight answer on this about how people are using these tools. I.e. even though rust is my favorite overall language and see no reason it couldn't be used for web work, I still use Django.
Axos, Axum, Rocket, Diesel etc, are all IMO not in the same league as Django. My understanding is that addressing this is Loco's Raison d'etre.
Another aspect of the Rust web ecosystem: It's almost fully gone Async.
by the__alchemist
3/12/2026 at 3:08:26 PM
It's quite a gap really.I'll say this, coding agents make the lack of a "batteries included" framework like rails or Django somewhat less daunting.
But "convention over code" and having a default structure / shape for projects is extremely helpful and you feel it when it's missing.
For my last small project I looked at Loco but ended up passing on it because I felt like adoption wasn't great yet. I really hope it takes off, though.
by JeremyNT
3/13/2026 at 4:22:43 PM
It's really hard to get away from ssjs frameworks for front-end, so for my startup it's Axum + Seaorm for "the api" and a Svelte SSR "front end" / view layer.I think rust programers are more likely to want flask/rack than Django/rails.
by aaronblohowiak
3/13/2026 at 3:01:27 AM
I'm at a point now where I'm not even a little interested in new frameworks. I want tried and tested. Preferably something that has been around for 15 years.by greenhatman
3/12/2026 at 3:30:05 PM
I worked with Rails a lot. In my experience, every rails dev who is fanatical about how much they love Rails, also has little to no experience with strong types. Of the ones who later try types, they no longer love Rails. Personally I quit Rails entirely because of lack of types. No, RBS and Sorbet are not even close to good enough.Also, every enterprise rails app I've seen (seven, to date) has been really poorly written/architected in a way that other backends just weren't. Even the fairly new ones felt like legacy code already.
by eudamoniac
3/12/2026 at 8:49:49 PM
I still really like rails. It’s really fun until your codebase reaches a certain size. At that point you better have a large suite of test which becomes a problem of it self because the tests will take forever to complete.I tried sorbet a couple of times and totally get why it’s useful but imo it’s not just lacking (e.g. compared with what can be done with TS or even a simple type system like golang) but it also removes all the fun parts of ruby / rails.
by schlch
3/13/2026 at 7:08:44 PM
Right, the test culture is very silly to me. Thousands of tests and long CI times, basically just doing a poor invention of a compiler. Dynamic types are so much extra work.by eudamoniac
3/12/2026 at 6:23:42 PM
Ruby is a strongly typed language. I think you are confusing strong typing with static typing.by mike_ivanov
3/12/2026 at 9:29:04 PM
And by contrast, C is static but weakly typed.by goatlover
3/12/2026 at 4:31:16 PM
It's not just the untyped problems, the runtime definitions of functions, properties, etc make it nearly impossible to debug unless you have the state of your production data locally. (Or you ssh into your prod server and open up a REPL, load the state and introspect everything there). Good luck debugging locally in a nice IDE. It's a horrific nightmare. I use to love Ruby until I had to debug it live.by rdoherty
3/13/2026 at 2:36:34 AM
Yeah, dynamic typing is one thing, but the magical dynamic imports into the processes globally scoped namespace add another level to debugging difficulty.At least in Python (as a comparison example), imports are only available in the module doing the importing - it's more explicit. You'd have to really work to get the same "everything all at once" as Rails has.
by antod
3/12/2026 at 3:02:17 PM
What is it about large untyped codebases that make it a nightmare?by mattsears
3/12/2026 at 3:23:26 PM
If you make a change to the return types of a function for example you have to manually find all of the different references to that function and fix the code to handle the change. Since there are no compile time errors it's hard to know that you got everything and haven't just caused a bug.by fourseventy
3/12/2026 at 5:42:51 PM
Yes, and the downsides cascade. Because making any change is inherently risky you're kind of forced not to make changes, and instead pile on. So technical debt just grows, and the code becomes harder and harder to reason about. I have this same problem in PHP although it's mostly solved in PHP 8. But touching legacy code is incredibly involved.by array_key_first
3/12/2026 at 3:49:53 PM
Especially with duck-typing, you might also assume that a function that previously returned true-false will work if it now returns a String or nil. Semantically they’re similar, but String conveys more information (did something, here’s details vs did(n’t) do something).But if someone is actually relying on literal true/false instead of truthiness, you now have a bug.
I say this as a Ruby evangelist and apologist, who deeply loves the language and who’s used it professionally and still uses it for virtually all of my personal projects.
by stouset
3/12/2026 at 4:59:27 PM
The best perspective I've seen is that statically typed enforcement is basically a unit test done at compile time.by Salgat
3/12/2026 at 9:25:08 PM
Alan Kay's argument against static typing was it was too limited and didn't capture the domain logic of the sort of types you actually use at a higher level. So you leave it up to the objects to figure out how to handle messages. Given Ruby is a kind of spiritual ancestor of Smalltalk.by goatlover
3/13/2026 at 12:32:50 AM
the problem is that nobody listened to Alan Kay and writes dynamic code the way they'd write static code but without the types.I always liked Rich Hickey's point, that you should program on the inside the way you program on the outside. Over the wire you don't rely on types and make sure the entire internet is in type check harmony, it's on you to verify what you get, and that was what Alan Kay thought objects should do.
That's why I always find these complaints a bit puzzling. Yes in a dynamic language like Ruby, Python, Clojure, Smalltalk you can't impose global meaning, but you're not supposed to. If you have to edit countless of existing code just because some sender changed that's an indication you've ignored the principle of letting the recipient interpret the message. It shouldn't matter what someone else puts in a map, only what you take out of it, same way you don't care if the contents of the post truck change as long as your package is in it.
by Barrin92
3/13/2026 at 1:30:34 AM
That's a terrible solution because then you need a bunch of extra parsing and validation code in every recipient object. This becomes impractical once the code base grows to a certain size and ultimately defeats any possible benefit that might have initially been gained with dynamic typing.by nradov
3/13/2026 at 1:54:31 AM
>then you need a bunch of extra parsing and validation code in every recipient object.that's not a big deal, when we exchange generic information across networks we parse information all the time, in most use cases that's not an expensive operation. The gain is that this results in proper encapsulation, because the flipside of imposing meaning globally is that your entire codebase is one entangled ball, and as you scale a complex system, that tends to cost you more and more.
In the case of the OP where a program "breaks" and has to be recompiled every time some signature propagates through the entire system that is significant cost. Again if you think of a large scale computer network as an analog to a program, what costs more, parsing an input or rebooting and editing the entire system every time we add a field somewhere to a data structure, most consumers of that data don't care about?
this is how we got micro-services, which are nothing else but ways to introduce late binding and dynamism into static environments.
by Barrin92
3/13/2026 at 2:13:04 AM
> when we exchange generic information across networks we parse information all the timeThe goal is to do this parsing exactly once, at the system boundary, and thereafter keep the already-parsed data in a box that has "This has already been parsed and we know it's correct" written on the outside, so that nothing internal needs to worry about that again. And the absolute best kind of box is a type, because it's pretty easy to enforce that the parser function is the only piece of code in the entire system that can create a value of that type, and as soon as you do this, that entire class of problems goes away.
This idea is of using types whose instances can only be created by parser functions is known as Parse, Don't Validate, and while it's possible and useful to apply the general idea in a dynamically typed language, you only get the "We know at compile time that this problem cannot exist" guarantee if you use types.
by akoboldfrying
3/13/2026 at 2:48:54 AM
> The goal is to do this parsing exactly once, at the system boundaryYou are only parsing once at the system boundary, but under the dynamic model every receiver is its own system boundary. Like the earlier comment pointed out, micro services emerged to provide a way to hack Kay's actor model onto languages that don't offer the dynamicism natively. Yes, you are only parsing once in each service, but ultimately you are still parsing many times when you look at the entire program as a whole. "Parse, don't validate" doesn't really change anything.
by 9rx
3/13/2026 at 3:30:10 AM
> but under the dynamic model every receiver is its own system boundaryI'm not claiming that it can't be done that way, I'm claiming that it's better not to do it that way.
You could achieve security by hiring a separate guard to stand outside each room in your office building, but it's cheaper and just as secure to hire a single guard to stand outside the entrance to the building.
>micro services emerged to provide a way to hack Kay's actor model onto languages that don't offer the dynamicism natively
I think microservices emerged for a different reason: to make more efficient use of hardware at scale. (A monolith that does everything is in every way easier to work with.) One downside of microservices is the much-increased system boundary size they imply -- this hole in the type system forces a lot more parsing and makes it harder to reason about the effects of local changes.
by akoboldfrying
3/13/2026 at 4:18:13 AM
> I think microservices emerged for a different reason: to make more efficient use of hardware at scale.Same thing, no? That is exactly was what Kay was talking about. That was his vision: Infinite nodes all interconnected, sending messages to each other. That is why Smalltalk was designed the way it was. While the mainstream Smalltalk implementations got stuck in a single image model, Kay and others did try working on projects to carry the vision forward. Erlang had some success with the same essential concept.
> I'm claiming that it's better not to do it that way.
Is it fundamentally better, or is it only better because the alternative was never fully realized? For something of modern relevance, take LLMs. In your model, you have to have the hardware to run the LLM on your local machine, which for a frontier model is quite the ask. Or you can write all kinds of crazy, convoluted code to pass the work off to another machine. In Kay's world, being able to access an LLM on another machine is a feature built right into the language. Code running on another machine is the same as code running on your own machine.
I'm reminded of what you said about "Parse, don't validate" types. Like you alluded to, you can write all kinds of tests to essentially validate the same properties as the type system, but when the language gives you a type system you get all that for free, which you saw as a benefit. But now it seems you are suggesting it is actually better for the compiler to do very little and that it is best to write your own code to deal with all the things you need.
by 9rx
3/13/2026 at 9:25:13 AM
> I think microservices emerged for a different reason: to make more efficient use of hardware at scale.Scaling different areas of an application is one thing. Being able to use different technology choices for different areas is another, even at low scale. And being able to have teams own individual areas of an application via a reasonably hard boundary is a third.
by robertlagrant
3/12/2026 at 8:07:27 PM
Is that a common issue? I guess I'm having a hard time imagining a scenario that would (a) come up often and (b) be a pain to fix.by weavejester
3/12/2026 at 6:32:52 PM
Anything can return anything and you only realize it at runtime is a massive headache. When you can't keep the entire code base in your head it becomes a liability.I never used Ruby, but Python code bases love mixing in strings that are actually enums and overloading functions that accept all kinds of types. You just had to hope that the documentation was correct to avoid a crash.
Java 1.7 to Python feels very freeing from all the boilerplate. Kotlin, or any other modern language with a well designed standard library, to Python just feels like a bunch of extra mental work and test to write to just avoid brackets.
by Larrikin
3/13/2026 at 2:39:52 AM
When CI/CD becomes your compiler you are in a tough spotby mountainriver
3/12/2026 at 4:35:39 PM
It makes coming up to speed on an existing codebase a slog because you have to trace through everything back to its source. Oh, and because there are magic methods and properties galore, your normal introspection tools in e.g. RubyMine get frequently stymied.by aarestad
3/12/2026 at 2:24:21 PM
Same. Also became a .net developer after almost 20 years of Ruby/Rails.Nowadays C# is anyways much more expressive than before. Meanwhile Ruby is still very slow.
Not to mention how poorly maintained are most Rails projects. People have been "vibe coding" forever.
A well-organized and maintained Rails app is great though. I'd definitely consider working with it again, but it really depends on what company it is.
by thiago_fm
3/12/2026 at 10:38:42 PM
[flagged]by ptak_dev
3/13/2026 at 6:56:04 AM
https://ihp.digitallyinduced.com/ is a rails-inspired framework for Haskell that tries to get the best of both worlds. Highly recommend trying it if you have a weekendby kreyenborgi
3/14/2026 at 7:48:05 PM
Is this still a valid take after the study that came out,showing how Ruby performs way better with agentic coding?by Fire-Dragon-DoL
3/13/2026 at 2:43:53 AM
Also the language/framework is mattering less by the day with agentic coding.Why would anyone ever choose ruby, python, etc when you don’t need to write it?
These languages are undoubtedly dead as of now. Python may live on in ML for a bit but probably not much longer
by mountainriver
3/13/2026 at 2:59:09 AM
Ruby has "undoubtedly" been dead for at least a decade now, or so I've heard. Glad to hear Python is undoubtedly joining the party.by irishloop
3/13/2026 at 3:05:49 AM
Least informed comment Ive read hereby mrits
3/15/2026 at 9:21:22 PM
"Agentic coding has been viable for the last decade"by mountainriver
3/12/2026 at 12:46:01 PM
I’ve worked in two places now with Ruby Sorbet servers. Ruby always drives me nuts how things are just in-scope and we don’t know why or where they came from.I certainly wouldn’t want to go back to working in dynamic languages without typing on top. That takes too much brain power, I’m too old for that now.
I would say Sorbet seems more “basic” than something like Typescript. It handles function calls matching signatures, potential nulls, making sure properties actually exist, that kind of thing. Whereas TS can get quite abstract, and at times you’re fighting to convince it that a value actually is the type you say it is.
TS is very powerful and expressive, to the point that it’s possible to do computation within type code. I’m not convinced I always need that power, or that it’s always more help than hindrance.
by draw_down
3/12/2026 at 2:14:30 PM
> Ruby always drives me nuts how things are just in-scope and we don’t know why or where they came from.irb(main):005:0> Foo.new.method(:bar).source_location => ["tmp/test.rb", 5]
by vidarh
3/12/2026 at 5:40:05 PM
[dead]by draw_down
3/12/2026 at 6:17:29 PM
You appear to be shadow banned. Letting you know since I didn't see anything egregious on a quick scan. Maybe contact HN and plead your case.I vouched for your reply below, and to answer in the meantime:
Yes, it's runtime, but that only matters if your code can't be initialized without unacceptable side effects.
In which case you don't have a functioning test suite either, and have much larger problems.
Otherwise, just load the code you struggle to figure out into irb, or pry, or a simple test script, and print out source-location.
If that is impossible (aside from the fact that codebase is broken beyond all reason), the marginally harder solution is to use ruby-lsp[1] and look up the definitions.
This is only hard if you insist on refusing to use the available - and built in, in the case of source_location - tooling.
by vidarh
3/12/2026 at 1:48:39 PM
> I certainly wouldn’t want to go back to working in dynamic languages without typing on top. That takes too much brain power, I’m too old for that now.> and at times you’re fighting to convince it that a value actually is the type you say it is.
Might just be allocating that brain power to the same task but calling it a different thing.
by wutwutwat
3/12/2026 at 5:14:53 PM
[dead]by 42069party
3/12/2026 at 12:45:48 PM
Are you hand coding?by kshahkshah
3/12/2026 at 12:55:11 PM
Are we that far gone that "hand coding" is a term now? I hope there's an /s missingby h4ch1
3/12/2026 at 1:38:30 PM
I hope "hand coding" is an antonym for "convention coding" or something.by konart
3/12/2026 at 2:07:39 PM
I’m guessing hand coding means, not vibe coding.Did you use AI? .. Nah I hand coded it.
by evolve2k
3/16/2026 at 8:50:38 AM
Well, yes. I was trying to comment in spirit of parent comment.by konart
3/12/2026 at 2:14:50 PM
Real programmers use butterflies. https://xkcd.com/378/by Cyphase
3/12/2026 at 1:14:10 PM
Doesn't matter because LLMs also benefit greatly from typed code bases in that they can run the type checker and fix the problems themselves on a loop.by satvikpendem
3/12/2026 at 1:50:20 PM
I haven’t seen much discussion about this point other than “llm handle languages x y and z because there’s a lot of training data”. Watching Terence Tau using llm for writing proofs in Lean was a real eye opener in this regard.by le-mark
3/12/2026 at 2:16:01 PM
Both Claude and Codex handle Ruby just fine.by vidarh