|
|
|
|
|
by arp242
1876 days ago
|
|
I haven't significantly worked with Rails since 2015, so I'm not up to speed with the current state of things, but in general I found that architecturally Rails can scale mostly okay, although it can be a bit tricky if you're not very familiar with the Rails internals, but it's not overly complex either in my experience. I was never a Rails super-expert either, and I managed to bolt on plenty of stuff for customers' specific needs, and the results worked fairly well and weren't too overly complex. I don't doubt there are certain roadblocks though, and that some things fairly "simple" could be very hard and complex in Rails. I just never encountered them. I've certainly seen a lot more overly complex crappy bespoke solutions when Rails + a few modifications would have been much better. This is like the old Greenspun's tenth rule: "any sufficiently complicated C or Fortran program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp." – there are a lot of "ad hoc, informally-specified, bug-ridden, slow implementations of half of Ruby on Rails" out there. Right now I mostly write web stuff with Go, which is the exact opposite of Ruby/Rails in almost every way. In spite of being so different, I'm fairly comfterable with both approaches, and I'm not entirely sure what I prefer yet (even though I've been doing this in Go for 6 years now); I certainly spent a lot more time on basic stuff that Rails just provides. |
|
What I'm criticising is that a lot of the official guides (and/or DHH himself) often lead to problems down the road. For example, it is encouraged to do things through model callbacks. Except, once you have your send_email logic in a after_create callback and you figure out that you actually need to create users in different contexts too - e.g. in bulk updates if you need to import some data, where you don't want to always send an email - it will be painful to rewrite your code since you have no abstraction where that code should reside. Even DHH recognised this problem, when he pushed through ActiveRecord::Base.suppress [1] which was consided problematic by most everyone else (including the Rails core team). A better architecture would have a "service" or "concern" layer that would handle such things, but "the Rails way" doesn't advocate for anything outside of models, views and controllers. Though, to be fair, many real-world codebases do include such a service layer - but it's done differently everywhere.
There is also no abstraction for request validations. You're supposed to do all your validations in the model layer. But what if you have multiple requests mapping to the same model layer? Maybe the validations you want to run if an admin user updates a table are very distinct from the validations that should be run for a regular user. Again, while you can use ActiveModel objects for that, Rails doesn't particularly encourage this design and you can end up with a lot of coupling between your persistence layer and something which is essentially part of the business layer, and that can be hard to unentangle later.
Another famous problem IMHO is (by default) every single test loading the whole Rails context. This makes fast unit tests basically impossible and therefore TDD painful (which, IMHO, is particularly bad in a dynamically and heavily monkeypatched language - if you don't have static guarantees, you at least want to be able to test your changes quickly).
All of these are things that in other ecosystems - for example Spring - are handled much better. Now, I have criticisms about Spring too (slow boot times, excessive use of reflection, Hibernate is a mess, etc.) but at least it gives you some good tools to cleanly separate different layers of your application. For example, validation is generally done at DTO level, long before any of your data ever hits the database.
[1] https://medium.com/spritle-software/rails-5-activerecord-sup...