7 ms·
The usual response to this complaint in the Ruby/Rails community is that optimizing for nanoseconds, or even milliseconds doesn't matter when the same operation
by brunosutic 10mo ago
The usual response to this complaint in the Ruby/Rails community is that optimizing for nanoseconds, or even milliseconds doesn't matter when the same operation also involves multiple database queries or API calls.
Let's take this example from the article:
Billing::Plan.find_or_create_all_by_attrs!(
1.month => {standard: 10, pro: 50, enterprise: 100},
1.year => {standard: 100, pro: 500, enterprise: 1000}
)
This ensures six billing plans are created. That means 6 DB queries and 6 Stripe API queries, at a minimum.
- dlisboa 10mo ago> The usual response to this complaint in the Ruby/Rails community is that optimizing for nanoseconds, or even milliseconds doesn't matter when the same operation also involves multiple database queries or API calls The problem with that logic is that it’s pervasive: people have that same attitude everywhere even if no IO is being done. That’s how we get multi gigabyte processes. The whole language (and Rails) also pushes you towards a less efficient path. For instance you’re probably iterating over those six plans and inserting them individually in the DB. Another approach would’ve been to accumulate all of them in memory then build and perform a single query. That’s not something people really consider because it’s “micro” optimization and makes the code look worse. But if you miss out on hundreds of these micro optimizations then you get a worse system. In a general sense optimizing Ruby is indeed futile: any optimization is dwarfed by just choosing a different language. I say all this as someone who has worked with it for two decades, I like the language, it’s just laughably inefficient.
- radanskoric 10mo agoHave you used it over the last few years? It has it been rapidly improving, mainly because Shopify put a team full time on it. It doesn’t take a lot of people to optimize a VM/interpreter it just has to be the right people. And the question is always “fast enough for what?” Different languages are more suitable for different types of projects. I wouldn’t code a rendering engine in Ruby but for web apps it’s amazing.
- dlisboa 10mo agoYes, every web app I’ve worked on the past ~18 years has been with Rails. I’ve seen it all except an efficient app. Sure, Ruby and Rails never bankrupted these companies but they’d all have been better off with something else. Certain cloud bills would’ve been much smaller for sure. Those optimizations to the VM are just very workload specific and become less relevant today when you’re using containers and fractional CPU/mem. It also doesn’t take much for a dev to write the wrong code and make them irrelevant again. Even if you get everything right you’re leaving so much performance on the table it feels like crumbs. For small web apps Rails is fine though. I just never worked on one. The issue is perhaps no one threw the code away when it got big.
- radanskoric 10mo agoCan you explain why you say they would be better off? What else would be a better choice and why?
- whstl 10mo agoNot GP but I can answer: Rails apps can get very expensive server wise because the “IO is slow anyways” attitude means more servers will be needed to serve the same amount of requests. For a specific bad case I worked at, the cloud bill was the same cost of 15 senior developers. And it was an app without external users (I was actually responsible for the external parts of it, it was isolated and not in Rails). Excessive abstraction at the ORM can also make it extremely difficult to optimize db queries, so each user request can trigger way more DB queries than necessary, and this will require more db power. I have seen this happening over and over due to abstraction layers such as Trailblazer, but anything that is too layered clean-code style will cause issues and requires constant observation. And refactoring is made difficult due to “magic”. Even LLMs might find it too much. Another problem with the slowness is that it slows down local development too. The biggest test suite I ever saw took 2 hours to run in a 60-machine cluster, so 120 hours of CI. Impossible to run locally, so major refactoring was borderline impossible without a huge feedback cycle. The solution for the slow development ends up being hiring more developers, of course, with each one responsible for a smaller part of the app. In other companies these kind of features I saw would be written by people over days, not by team over months. The terseness of both Ruby and Rails is also IMO countered by the culture of turning 10-line methods into bigger classes and using methods and instance variables instead of local variables. So it also hurts both readability (because now you have 5x more lines than needed) but also hurts optimization and stresses the garbage collection. If you know this, you know. I have seen this in code from North+Latin American, European and Japanese companies, so it’s not isolated cases. If you don’t know I can provide examples. I have seen this happening with other tech too, of course, but with Rails it happens much much faster IME. It is also 100% preventable, of course, however a lot of advice on how to prevent these problems will clash with Ruby/Rails traditions and culture. These are just examples out of personal experience, but definitely not isolated cases IMO.
- boredtofears 10mo ago> For instance you’re probably iterating over those six plans and inserting them individually in the DB. Another approach would’ve been to accumulate all of them in memory then build and perform a single query. That’s not something people really consider because it’s “micro” optimization and makes the code look worse. This same pitfall exists in every language. This has nothing to do with Ruby.
- AlphaSite 10mo agoeh. Ruby makes it easy to do the wrong thing. imo.
- boredtofears 10mo agoMaybe, but this isn’t one of the ways it does.
- em-bee 10mo agoi find this structure a bit odd. i would have gone for the following pattern: Billing::Plan.find_or_create_all_by_attrs!( standard => {1.month: 10, 1.year: 100}, pro => {1.month: 50, 1.year: 500}, enterprise => {1.month: 100, 1.year: 1000} )
- brunosutic 10mo agoThis is supported and would work with no implementation changes. The "Friendly Attributes" idea is very flexible. Just a small Ruby syntax correction for your example: Billing::Plan.find_or_create_all_by_attrs!( standard: {1.month => 10, 1.year => 100}, ... )
- whstl 10mo agoThis attitude towards wastefulness is how you have web apps that could run in a single machine but struggle to run in a server cluster. And after a couple years even Postgres is struggling because the amount of queries is too massive because of abstractions that don’t lend themselves to optimization. Also it’s how you have codebases that could be maintained by two or three suddenly needing dozens because the testing suite needs hours to run and people even celebrate when there’s no tests in sight. Just anecdotal personal experience. But I saw this happening inside at least 4 successful companies that started with Rails but didn’t care about those problems, and ended up wanting/having to move to something else.
- fny 10mo agoThe reality is most companies and products never blow bast the point of needed to ditch Rails. The argument made at the time was scaling horizontally is cheaper than hiring new devs, and you probably will never need to scale that much horizontally. Test suite bloat is a different problem that stems from the lack of incremental typing which I think is what ultimately killed Ruby and Rails. Any big Rails codebase can be a nightmare to grok unless people have been diligent about documenting what different methods return.
- obiefernandez 10mo agoNothing has “killed Ruby on Rails”. Ridiculous comment.
- fny 10mo agoI'm honored to have you of all people make that comment. But with all due respect the excitement and job market for Ruby isn't anything close to what it used to be: [0]: https://trends.google.com/trends/explore?date=all&q=%2Fm%2F0505cl&hl=en-US https://trends.google.com/trends/explore?date=all&q=%2Fm%2F0...
- cortesoft 10mo agoAgain, though, these bottlenecks are because of how the system queries the database, not how methods are dispatched. I agree on the ORM abstractions causing huge performance issues, but it has nothing to do with Ruby’s dynamic method declarations.