> Yes, the learning curve can be steep, and the “magic” can sometimes be frustrating.
This is possibly the absolute worst combination of factors possible. The learning curve makes it bad to ramp up with, and the magic makes it bad in the long term.
It's a framework that wants to be used for monoliths, and tooling is essential to manage the complexity of large monoliths, but you're stuck with a language that's extremely hostile to tooling, using patterns that make it even more hostile to tooling.
So, really, what you're left with is a framework that's only actually good for the early-mid stages of a project, and only if you're an existing Rails user who doesn't have to pay the ramp up price.
Ruby can parse itself, it has test coverage, vulnerability auditing, SQL auditing, static and runtime analysis and type enforcing tools…
Rails has an incredibly convenient REPL that's built into every dev error page, a one-line integration with every error, analytics, and log-tracking service under the sun, that will give you all of the insight into production runtime for basically zero effort.
You install Sidekiq or GoodJob in a couple of lines of code, and suddenly you have the entire background job system to tap into for any delayed or periodic workflows that can be offloaded, bundled with monitoring and administration UI.
All you need to do is learn how to do software design, but even there Rails starts you off with arguably the best design decisions you can make at early stage: focus on your entry points (controller actions for requests, rake tasks for CLI), and start extracting domain objects as you learn more about your domain.
Am I missing something? Where's the "hostility to tooling"?
You can either have a massive Python project and struggle with a lack of types and a tenseness that becomes unreadable at huge sizes;
A Laravel project that’s PHP, which despite being way, way, better than it used to be (types! traits! union type returns! faster than ruby! weak maps! [0]) still has a few footguns left;
Or you can have a JavaScript monster. The worst of all worlds. Your complexity complaints times 10. A nightmare than in 10 years will make a 2008 PHP project look well-organized. A project that has thousands of packages you’ve never read.
On the edges, you’ve got microservices (which turns into a mess); or you can go fancy with Go and Rust (have fun managing the budget). There’s also, of course, C# and Java, but come now, it’s 2024, you’re probably coupling them to a JavaScript monster anyway.
TL;DR: Every large project becomes a mess. Pick your poison. One is hardly worse than another’s. Best to have the devil you know. Even if you do things perfectly with a FAANG level budget, AWS and Azure still have outages.
I love Rails and Ruby and miss the ecosystem dearly, but the joy dies once you find yourself lost in layers of code without any types or IDE support. This is especially true on large teams.
So what are your options... Sorbet? Does this feel like Ruby?
sig do
params(x: Integer)
.returns(String)
end
How about RBS? Does writing the equivalent of header files for every function and class feel like Ruby?
So unfortunately I'm no longer an evangelist or practitioner.
This has been a big frustration for me as a new engineer in a Rails codebase: my ability to 'discover' how the system works is extremely limited because I can't 'see' a lot of the relationships between code. I've grown comfortable with just searching the entire codebase for a given string to find a relevant class or variable, but it's extremely failure-prone without types or import paths to follow.
I love the syntax and elegance of Ruby, but it really is maddening how difficult it is to hold all the abstractions and state in my head without the mental boundaries that good type support provides.
I often commiserate with a coworker who came from a Java background (and I from Swift/Python) about how frustrating it is when type-based issues leak to prod and cause trouble, or how it lengthens the development process insofar as determining what a given object _is_ at any point in the logical execution.
I really understand how unit testing became so popular, given Rails's historical popularity: there's simply no other way to move with confidence through the codebase without a plethora of specific tests for each individual component.
Dynamically typed languages aren't out in the cold like they used to be with IDE support. Most of the advanced LSP work going on isn't based on explicit types signatures yet they work well. See https://railsatscale.com/2024-07-18-mastering-ruby-code-navi...
It’s a super naive post considering rails+react is almost a standard these days.
He’s using the built in rails front end templates which React can replace trivially in a React+Rails stack and comparing React to all of the rails stack and complaining it can’t do backend which is not where React fits in.
It’s a cringeworthy post. It should not be on the front page.
FWIW, the javascript side of Rails is historically the least settled-upon part of the framework. I'm curious how many current Rails projects use React as an alternative over the current "convention" of Turbo. Or Hotwire. Or even UJS for legacy projects.
One of Rails most under appreciated features is testing. Basically everything you can do in Rails has a way to write an automated test for it. Having good tests is a way to keep momentum as the project grows in complexity.
I love Rails. Every investment I've made in learning it has yielded returns for years. Everytime I learn a new JS framework, its obsolete two years later.
That sounds really interesting. I'm working on a similar autotesting module for my Django project. Would you mind describing essentially how it works and it's capabilities? There are a lot of great ideas in Rails, but I've never had an excuse to learn it.
Ruby/Rails with static type checking is a mediocre experience. I would say it's good enough when starting out, even great. But once you have many teams working on it, you wish for better language strictness, to do safe and widespread refactoring for instance.
ActiveRecord has many limitations when trying to get efficiency from infrastructure (either because you've grown/scaled, or to minimize costs while growing). The main problem is with model instances having actions attached to them, you have to make and jump through hoops to batch the individual callbacks.
Working on a performance improvement project, we discovered that doing ModelClass.new (not doing any I/O and even if that class is empty with no callbacks) is about 400x slower than doing MyClass.new for a plain Ruby class that holds a table's attributes. Processing a thousand of these things in a request with a handful of associated models for each can eat up 100s of ms before doing anything useful.
And even dropping down to using ModelClass.insert_all(array_of_hashes) which bypasses ActiveRecord model instantiation is still slow in the way it generates the SQL before executing it.
You can scale throughput by having many webapp servers (at the cost/constraint of many database connections) but that doesn't help latency per request.
Working at a Rails and MySQL shop is about as close to guaranteed employment as I know as there's always tough problems to solve as a company continues to expand in scope and scale, and always new devs doing their best but still introducing patterns that don't age well.
Hard disagree. "More discussions once more opinionated developers join" is universally true regardless of which frameworks/philosophies you start with. The point of convention being more important than configuration is that it reduces those conversations, because you can rely on the conventions as a default.
If an opinionated developer thinks a different configuration is better, then that helps form the conversation immediately. Everyone is already familiar with the convention, so the discussion only needs to inform everyone about the pros/cons of the alternative.
1. Code is loaded automatically and globally. I’ve had weird bugs caused by someone creating a function with the same name in a completely different file.
2. The module system is strange. Why do my file names and class names need to match? Why can’t i just import the files i want like other languages?
3. Includes (aka mixins) are a bad idea. See below.
4. Many of the language features are designed to hide how code works. Quite often i wonder to myself “where does this variable/function come from?” #1 is also a good example of this.
5. Coming from a typed language, the lack of types makes me feel naked and more prone to screw something up.
6. The strange and elitist opinions of ruby fanboys. Sorry but code terseness is not a panacea and “unless” is terrible. It seems like code readability and understandability are less important to this crowd.
> 1. Code is loaded automatically and globally. I’ve had weird bugs caused by someone creating a function with the same name in a completely different file.
Ruby doesn't have functions. It only has Objects, and methods on those Objects. Generally you won't run into method nuking because generally there's no need to define the same class in different files.
Yes, you can overwrite method definitions on objects, you can even do that dynamically at runtime. Yes, it's a shotgun. No, it's not wrong, it's just another tool in your toolbelt.
> 2. The module system is strange. Why do my file names and class names need to match? Why can’t i just import the files i want like other languages?
You can require whatever you want, named whatever you want. Rails only looks like magic in this regard because it's coded around conventions so that it can abstract away all that boilerplate. Somewhere before you try instantiate MyController, it was require'd into the project for you utilizing those basic language features. `config/application.rb` is a good reading point to start exploring how this works.
A tremendious amount of logic in Rails is derived from how you name things. Don't fight this system, learn it. Fighting it will only be pain and agony, and I promise you there is a reason for why it works the way it does.
There is absolutly nothing stopping you from calling `require 'my_module'` to bring "BobsGreatestModuleEver" into context. You can missmatch all you want. I have no idea _why_ you would want to do that, seems like a bad precident, but go wild. Ruby works this way like any other language.
> 3. Includes (aka mixins) are a bad idea. See below.
> 4. Many of the language features are designed to hide how code works. Quite often i wonder to myself “where does this variable/function come from?” #1 is also a good example of this.
Includes/Mixins are designed to encapsulate shared functionality. Like any effective shotgun if you shoot your feet off you'll be hurting, so don't shoot your feet.
Use your console! If you've got a class with a method and you have no f'n idea where it's defined, just ask it to tell you.
> 5. Coming from a typed language, the lack of types makes me feel naked and more prone to screw something up.
Eh, I think this is one of those tech religious war topics. I've wrangled a lot of typescript and I cannot say that having types have made me feel protected in any way. If anything, TS in particular, it's felt like just _more code_, and I'm a fan of not having any more code that can be helped.
That aside, the Ruby way is Duck typing. If your code is in danger of receiving arbitrary properties, it's very straightforward to protect that code by just inspecting the properties. If it walks like a duck and quacks like a duck, it's probably a duck.
> 6. The strange and elitist opinions of ruby fanboys. Sorry but code terseness is not a panacea and “unless” is terrible. It seems like code readability and understandability are less important to this crowd.
Ruby is _all about_ code readability and developer experience. `return unless some_condition?` is gods greatest gift to programming and I will die on that hill.
It can go to an extreme. Like every language you will meet your code golfers who want to take things way, way too far, but that's not unique to Ruby. That's just a people thing. During PR review it's not abnormal for me to ask for terse code to be expanded into a longer form simply for readability.
One of the biggest issues we have with Rails these days is finding Rails devs (at least where I work). Our next project's backend may very well have to be Node or Python specifically for this reason.
[+] [-] pdpi|1 year ago|reply
This is possibly the absolute worst combination of factors possible. The learning curve makes it bad to ramp up with, and the magic makes it bad in the long term.
It's a framework that wants to be used for monoliths, and tooling is essential to manage the complexity of large monoliths, but you're stuck with a language that's extremely hostile to tooling, using patterns that make it even more hostile to tooling.
So, really, what you're left with is a framework that's only actually good for the early-mid stages of a project, and only if you're an existing Rails user who doesn't have to pay the ramp up price.
[+] [-] hakunin|1 year ago|reply
Rails has an incredibly convenient REPL that's built into every dev error page, a one-line integration with every error, analytics, and log-tracking service under the sun, that will give you all of the insight into production runtime for basically zero effort.
You install Sidekiq or GoodJob in a couple of lines of code, and suddenly you have the entire background job system to tap into for any delayed or periodic workflows that can be offloaded, bundled with monitoring and administration UI.
All you need to do is learn how to do software design, but even there Rails starts you off with arguably the best design decisions you can make at early stage: focus on your entry points (controller actions for requests, rake tasks for CLI), and start extracting domain objects as you learn more about your domain.
Am I missing something? Where's the "hostility to tooling"?
[+] [-] gjsman-1000|1 year ago|reply
You can either have a massive Python project and struggle with a lack of types and a tenseness that becomes unreadable at huge sizes;
A Laravel project that’s PHP, which despite being way, way, better than it used to be (types! traits! union type returns! faster than ruby! weak maps! [0]) still has a few footguns left;
Or you can have a JavaScript monster. The worst of all worlds. Your complexity complaints times 10. A nightmare than in 10 years will make a 2008 PHP project look well-organized. A project that has thousands of packages you’ve never read.
On the edges, you’ve got microservices (which turns into a mess); or you can go fancy with Go and Rust (have fun managing the budget). There’s also, of course, C# and Java, but come now, it’s 2024, you’re probably coupling them to a JavaScript monster anyway.
TL;DR: Every large project becomes a mess. Pick your poison. One is hardly worse than another’s. Best to have the devil you know. Even if you do things perfectly with a FAANG level budget, AWS and Azure still have outages.
[0] https://m.youtube.com/watch?v=ZRV3pBuPxEQ
[+] [-] retrac98|1 year ago|reply
It just feels so much more productive than anything else I’ve ever worked with.
[+] [-] fny|1 year ago|reply
So what are your options... Sorbet? Does this feel like Ruby?
How about RBS? Does writing the equivalent of header files for every function and class feel like Ruby?So unfortunately I'm no longer an evangelist or practitioner.
[+] [-] tenacious_tuna|1 year ago|reply
I love the syntax and elegance of Ruby, but it really is maddening how difficult it is to hold all the abstractions and state in my head without the mental boundaries that good type support provides.
I often commiserate with a coworker who came from a Java background (and I from Swift/Python) about how frustrating it is when type-based issues leak to prod and cause trouble, or how it lengthens the development process insofar as determining what a given object _is_ at any point in the logical execution.
I really understand how unit testing became so popular, given Rails's historical popularity: there's simply no other way to move with confidence through the codebase without a plethora of specific tests for each individual component.
[+] [-] gls2ro|1 year ago|reply
Sorbet may have some warts, but the example you show is simple and easy to understand.
The `sig` is as Ruby as you get IMO:
And when opening that file we can get something like: I do agree about RBS being separate files that is something that can stop a coding flow.[+] [-] haven|1 year ago|reply
[+] [-] rognjen|1 year ago|reply
RubyMine is great.
[+] [-] drchopchop|1 year ago|reply
[+] [-] AnotherGoodName|1 year ago|reply
He’s using the built in rails front end templates which React can replace trivially in a React+Rails stack and comparing React to all of the rails stack and complaining it can’t do backend which is not where React fits in.
It’s a cringeworthy post. It should not be on the front page.
[+] [-] creativeembassy|1 year ago|reply
FWIW, the javascript side of Rails is historically the least settled-upon part of the framework. I'm curious how many current Rails projects use React as an alternative over the current "convention" of Turbo. Or Hotwire. Or even UJS for legacy projects.
[+] [-] hakunin|1 year ago|reply
[+] [-] rognjen|1 year ago|reply
[+] [-] radicalexponent|1 year ago|reply
I love Rails. Every investment I've made in learning it has yielded returns for years. Everytime I learn a new JS framework, its obsolete two years later.
[+] [-] infamia|1 year ago|reply
[+] [-] karmakaze|1 year ago|reply
ActiveRecord has many limitations when trying to get efficiency from infrastructure (either because you've grown/scaled, or to minimize costs while growing). The main problem is with model instances having actions attached to them, you have to make and jump through hoops to batch the individual callbacks.
Working on a performance improvement project, we discovered that doing ModelClass.new (not doing any I/O and even if that class is empty with no callbacks) is about 400x slower than doing MyClass.new for a plain Ruby class that holds a table's attributes. Processing a thousand of these things in a request with a handful of associated models for each can eat up 100s of ms before doing anything useful.
And even dropping down to using ModelClass.insert_all(array_of_hashes) which bypasses ActiveRecord model instantiation is still slow in the way it generates the SQL before executing it.
You can scale throughput by having many webapp servers (at the cost/constraint of many database connections) but that doesn't help latency per request.
Working at a Rails and MySQL shop is about as close to guaranteed employment as I know as there's always tough problems to solve as a company continues to expand in scope and scale, and always new devs doing their best but still introducing patterns that don't age well.
[+] [-] simonw|1 year ago|reply
That's absolutely meant as a compliment!
[+] [-] spleen|1 year ago|reply
However, convention over configuration means quicker delivery for small(er) teams, but more discussions once more opinionated developers join.
[+] [-] creativeembassy|1 year ago|reply
If an opinionated developer thinks a different configuration is better, then that helps form the conversation immediately. Everyone is already familiar with the convention, so the discussion only needs to inform everyone about the pros/cons of the alternative.
[+] [-] et-al|1 year ago|reply
[+] [-] CooCooCaCha|1 year ago|reply
1. Code is loaded automatically and globally. I’ve had weird bugs caused by someone creating a function with the same name in a completely different file.
2. The module system is strange. Why do my file names and class names need to match? Why can’t i just import the files i want like other languages?
3. Includes (aka mixins) are a bad idea. See below.
4. Many of the language features are designed to hide how code works. Quite often i wonder to myself “where does this variable/function come from?” #1 is also a good example of this.
5. Coming from a typed language, the lack of types makes me feel naked and more prone to screw something up.
6. The strange and elitist opinions of ruby fanboys. Sorry but code terseness is not a panacea and “unless” is terrible. It seems like code readability and understandability are less important to this crowd.
[+] [-] titusjohnson|1 year ago|reply
Ruby doesn't have functions. It only has Objects, and methods on those Objects. Generally you won't run into method nuking because generally there's no need to define the same class in different files.
Yes, you can overwrite method definitions on objects, you can even do that dynamically at runtime. Yes, it's a shotgun. No, it's not wrong, it's just another tool in your toolbelt.
> 2. The module system is strange. Why do my file names and class names need to match? Why can’t i just import the files i want like other languages?
You can require whatever you want, named whatever you want. Rails only looks like magic in this regard because it's coded around conventions so that it can abstract away all that boilerplate. Somewhere before you try instantiate MyController, it was require'd into the project for you utilizing those basic language features. `config/application.rb` is a good reading point to start exploring how this works.
A tremendious amount of logic in Rails is derived from how you name things. Don't fight this system, learn it. Fighting it will only be pain and agony, and I promise you there is a reason for why it works the way it does.
There is absolutly nothing stopping you from calling `require 'my_module'` to bring "BobsGreatestModuleEver" into context. You can missmatch all you want. I have no idea _why_ you would want to do that, seems like a bad precident, but go wild. Ruby works this way like any other language.
> 3. Includes (aka mixins) are a bad idea. See below. > 4. Many of the language features are designed to hide how code works. Quite often i wonder to myself “where does this variable/function come from?” #1 is also a good example of this.
Includes/Mixins are designed to encapsulate shared functionality. Like any effective shotgun if you shoot your feet off you'll be hurting, so don't shoot your feet.
Use your console! If you've got a class with a method and you have no f'n idea where it's defined, just ask it to tell you.
> 5. Coming from a typed language, the lack of types makes me feel naked and more prone to screw something up.Eh, I think this is one of those tech religious war topics. I've wrangled a lot of typescript and I cannot say that having types have made me feel protected in any way. If anything, TS in particular, it's felt like just _more code_, and I'm a fan of not having any more code that can be helped.
That aside, the Ruby way is Duck typing. If your code is in danger of receiving arbitrary properties, it's very straightforward to protect that code by just inspecting the properties. If it walks like a duck and quacks like a duck, it's probably a duck.
> 6. The strange and elitist opinions of ruby fanboys. Sorry but code terseness is not a panacea and “unless” is terrible. It seems like code readability and understandability are less important to this crowd.Ruby is _all about_ code readability and developer experience. `return unless some_condition?` is gods greatest gift to programming and I will die on that hill.
It can go to an extreme. Like every language you will meet your code golfers who want to take things way, way too far, but that's not unique to Ruby. That's just a people thing. During PR review it's not abnormal for me to ask for terse code to be expanded into a longer form simply for readability.
[+] [-] jaeming|1 year ago|reply
[+] [-] sastraxi|1 year ago|reply
[+] [-] the_gastropod|1 year ago|reply
[+] [-] Iuz|1 year ago|reply
[+] [-] unknown|1 year ago|reply
[deleted]
[+] [-] unknown|1 year ago|reply
[deleted]
[+] [-] TehShrike|1 year ago|reply
[+] [-] popcalc|1 year ago|reply
[+] [-] Ocerge|1 year ago|reply
[+] [-] unknown|1 year ago|reply
[deleted]