[HN Gopher] The Magic of Rails: exploring the principles and tec...
       ___________________________________________________________________
        
       The Magic of Rails: exploring the principles and techniques behind
       the framework
        
       Author : ksec
       Score  : 77 points
       Date   : 2023-04-29 15:41 UTC (7 hours ago)
        
 (HTM) web link (speakerdeck.com)
 (TXT) w3m dump (speakerdeck.com)
        
       | dlisboa wrote:
       | I've been a Rails dev for many, many years, so I'm not shitting
       | on it. My one concern with Rails is human scaling, not so much
       | "web scaling".
       | 
       | A lot of big companies use Rails and are successful at a large
       | human scale. But one thing that is often not talked about is that
       | they have the financial resources to hire the very best
       | programmers in the world, and often they hire the very people who
       | build the framework (e.g. Shopify, GitHub I think had a few
       | members go through it, etc).
       | 
       | This is critical when the biggest questions with Rails is: how to
       | achieve clean code, modularity and separation of concerns; how to
       | achieve high throughput.
       | 
       | It doesn't surprise me that Basecamp says they never have issues
       | with a huge monolith in Rails: they invented the framework and
       | know their way around it. It doesn't surprise me that Shopify
       | doesn't have issues with scalability: they have Rails core team
       | members and Ruby engineers dedicated to creating an entire new
       | Ruby VM.
       | 
       | If the problems with Rails are solved by "throw the best people
       | in the world at it" then it's a self-limited proposition. I have
       | worked on countless Rails apps over the years, not one would pass
       | the "this is just great code" test. They were not built by
       | incompetent programmers. It's just that the "Rails way" needs a
       | very heavy guiding hand behind it. In the real world that is
       | often easy to lose: senior team members leave, you don't have
       | time to rewrite parts of the code, you may not even have the
       | expertise in-house to improve the codebase significantly. Bigger
       | companies don't usually have these problems.
       | 
       | And if you look at big Open Source Rails projects (Discourse,
       | Spree, Gitlab), you'll often see the same patterns: 1000+ line
       | models, non-standard Rails-way ideas like services and operators,
       | hundreds of files all in the same place without any clear
       | modularity... and these are not bad programmers at all. Maybe
       | Rails at human scale is just hard, or maybe there's something
       | about the framework that leads to this.
        
       | [deleted]
        
       | ulizzle wrote:
       | The problems with Rails are the same as with Ruby as it was with
       | Smalltalk: just too easy to make a mess (the nature of dynamic
       | languages), and its community suffers from a nasty case of
       | groupthink.
       | 
       | Notice the cliche "Rails is so much more than a framework."
       | 
       | The same magic that makes one so productive at the beginning
       | (start-up stage) is what comes back to bite you in the ass when
       | the project grows into an actual product; unless you are careful
       | and willing to trade off speed-to-market, which isn't what you
       | want to do with a startup.
       | 
       | Catch-22 because the app has gone off the rails by the time you
       | are successful, and everyone says: "Oh, you shouldn't have done
       | that."
        
         | lawn wrote:
         | Incidentally I feel Rust is the reverse Ruby: more work
         | (sometimes much more work) up front, but the big payoff comes
         | in the long run.
        
           | ulizzle wrote:
           | Many typed languages are like that, but the big difference is
           | that they admit the trade-off. In Ruby on Rails, dissent is a
           | big taboo, so they blame the problems on the devs (the
           | unwashed nameless masses) rather than tackle the problem
           | itself.
           | 
           | That's why you have all these different tools and concepts;
           | since they try to sandpaper over all the magical complexity
           | by adding more complexity, it becomes a no-true Scotsman
           | trivia game.
           | 
           | What trips me up tbh is how tech history repeats itself
           | almost verbatim. The Smalltalk story is very similar but with
           | a different cast.
        
         | haolez wrote:
         | Saying that dynamic languages are prone to make a mess is a
         | kind of groupthink in itself.
        
         | the_gastropod wrote:
         | Frankly, I think the bigger cliche is: "sure, it's easy to get
         | started, but Rails doesn't scale!"
         | 
         | Rails apps are way over represented among large web-based
         | businesses. Shopify, GitHub, Gusto, Airbnb, etc. There are
         | countless examples of Rails scaling beyond what anyone could
         | reasonably expect their web app to need.
        
           | bdcravens wrote:
           | This list cements the idea that without massive budgets Rails
           | becomes a challenge once you reach a certain point. The
           | argument against Rails isn't that it can't scale, but that
           | doing so requires a certain level of complexity that is
           | untenable for certain sizes and types of teams.
           | 
           | Shopify has built massive tooling
           | (https://shopify.engineering/shopify-made-patterns-in-our-
           | rai...). Github was stuck on an old version of Rails for
           | years due to the amount of customization they had done. (It
           | was actually a big deal when they finally were able to run on
           | the latest version: https://github.blog/2018-09-28-upgrading-
           | github-from-rails-3...)
        
           | karmakaze wrote:
           | I've worked with Rails at two companies: 500px and Shopify.
           | The former was what I take to be typical use of gems and
           | monkeypatching magic. I didn't like it, though I ended up
           | doing myself to get other issues under control. (And luckily
           | much new development were as separate services in Go.)
           | 
           | The Ruby/Rails at Shopify is much more sane (by my
           | definition) looking much more like regular API made using a
           | statically typed language (lots of Sorbet type info). There
           | is of course dynamic magic, but tends to be limited rather
           | than preferred, and where feasible static Sorbet type info is
           | generated to match what the magic produces so users of magic
           | can operate as if it was just a static typed library with a
           | bit of DSL. There's enough in-house specifics that I wouldn't
           | even call it Ruby on Rails, but rather Shopify Ruby/Rails and
           | it's constantly evolving. There can be 3 ways of doing
           | something: the old way (being phased out), the current way,
           | and perhaps a new one being tested out in some part of the
           | codebase.
        
           | ulizzle wrote:
           | Those companies are a product of the last wave, when Rails
           | was very popular in tech, especially amongst San Francisco
           | circles. There are also a lot of examples of that size that
           | left Rails or never jumped on that trend. This is also an
           | argument from survivor bias. You have to count the failures
           | too, which we don't have numbers for.
           | 
           | It's not that it can't scale; it's just that it's too easy to
           | make a mess in the way, which would prevent you from doing
           | so.
           | 
           | So what ends up happening is that you pay for mistakes or
           | someone else's, but at the end of the day, you are still on
           | your own.
        
         | ecshafer wrote:
         | Could you share some examples of this?
         | 
         | I am a bit over >1 year with Rails and I don't see this to be
         | the case. There is some "group think" perhaps, but every
         | ecosystem has that (Whats the "pythonic" way or Java way to
         | write x). I work at Shopify which uses Ruby and Rails
         | extensively, and I don't think things have "gone off the
         | rails". We use other technologies where appropriate, but for
         | the core business logic cases, Rails is fantastic.
        
           | ulizzle wrote:
           | You have to measure by time-to-market / team size. How much
           | it costs to maintain the system, how long it takes to ship
           | features, fix bugs, reach milestones, etc; which is something
           | you can't say publicly, and even if the company did, it would
           | be heavily doctored to make a good impression on
           | stakeholders.
           | 
           | That's why I think the argument is a weak appeal to
           | authority. Throw enough money at a problem, and you can scale
           | anything involving computers. Notice how expensive is Heroku.
           | 
           | But you can't add more team members to a project and expect
           | things to go faster, which is where the real problem with
           | Rails lies.
        
           | bdcravens wrote:
           | The sheer amount of tooling that Shopify has built to
           | overcome this is a good example.
           | 
           | https://shopify.engineering/shopify-made-patterns-in-our-
           | rai...
           | 
           | "Going off the rails" isn't an indication that Rails is bad,
           | as much as a claim that it can't fit the needs of a company
           | with either splitting to other technologies ("We use other
           | technologies where appropriate") or painting outside of the
           | Rails lines.
        
             | ecshafer wrote:
             | Any company at scale develops these other solutions to help
             | scale. A company using Java and Spring does the same or C++
             | or whatever. Shopify seems to be unique at the largest (I
             | think) Ruby/Rails shop, so they are leading the way
             | developing a lot of these tools. I don't think that its
             | significantly different than Google making Guava, Map
             | Reduce, etc.
        
         | tenderlove wrote:
         | I hope that you'll watch the recording of the talk when it's
         | released. The context of the "cliche" is with regard to the
         | community, the framework, and why Eileen continues to remain on
         | the core team. It's nothing to do with the design or
         | functionality of the framework itself. :)
        
       | nathants wrote:
       | it's like the t-shirt from happy gilmore: guns don't kill people,
       | i kill people.
       | 
       | for whatever reasons, rails became easy to discover and use.
       | 
       | that so many ended up committing git based crimes with it is not
       | rails fault.
       | 
       | personally i blame education and media. we can do better.
        
       | joshmn wrote:
       | I have been working with Rails for the last forever. I love Ruby,
       | and I love Rails. Part of the reason why I love Rails so much is
       | in slide 9: "Rails is designed to have agnostic interfaces."
       | 
       | One of the reasons why I hate Rails is the steep learning curve.
       | It's really easy to get something out the door with Rails.
       | Whether or not it's maintainable long-term is what's up for
       | debate. There are often 10 ways to get the same result: 1-5 are
       | really bad, 6 and 7 are acceptable, 8 is good, 9 is great, 10 is
       | perfect. Not everything has to be 10, or even 9, or even 8; the
       | fewer 1-5s you have the better.
       | 
       | The official "Getting Started" guides don't help this at all.
       | Granted, they are indeed marketed correctly: they are for getting
       | started. But it lends to this idea that that all Rails
       | applications have to look that way -- the "getting started" way.
       | 
       | Many of my applications (and many of the shops I'm brought in to
       | "better") end up shipping with more than what comes out of the
       | box. This might sound normal to folk on HN -- engineers are
       | supposed to engineer things, after all -- but it's lost on many
       | teams and orgs. ("Many teams and orgs" are largely teams and orgs
       | we have never heard about, and there are plenty of them.)
       | 
       | Taking a peak at my usual interface stack includes commands,
       | components, decorators, forms, inputs, queries, presenters,
       | serializers, and services. This is in addition to the default
       | controllers, helpers, mailers, models, views.
       | 
       | My ultimate takeaway from seeing over a two dozen "this Rails app
       | is painful to use" situations in the last two years is that the
       | developers hadn't extended past the original patterns that were
       | given to them when they originally spun up the app. This largely
       | results in losing a lot of the Rails magic because developers are
       | (unintentionally wrongfully) forced to do things that goes
       | against Rails' expectations.
       | 
       | There are other things besides shipping better abstractions too,
       | obviously. The one that stands out the most is controllers doing
       | too much and becoming God controllers; developers get lazy (or
       | just aren't aware) and simply define routes that are RESTful in
       | the router, but aren't in the actual controller definition. This
       | makes for a tangled mess.
       | 
       | There's a way to make Rails as much of a joy to use as it is when
       | you first hit `rails new` -- it just takes some experience and
       | diligence. That can be said for every framework. But what can't
       | be said for every other framework is that Rails makes it way too
       | easy to write really bad Ruby code that, ultimately, gets you the
       | "right" result. Avoiding those is the hard part.
       | 
       | (I'm currently looking for work in case anyone wants to talk)
        
         | ysavir wrote:
         | > Taking a peak at my usual interface stack includes commands,
         | components, decorators, forms, inputs, queries, presenters,
         | serializers, and services. This is in addition to the default
         | controllers, helpers, mailers, models, views.
         | 
         | Would love to hear a short bit on what each of these does in
         | your Rails codebases! I'm familiar with decorators, queries,
         | presenters, serializers, services, but commands, components,
         | forms, and inputs are new to me. Would be great to see what I'm
         | missing out on.
        
           | joshmn wrote:
           | Sure, here's a brief tour:
           | 
           | Commands -- I usually will ship with Rectify
           | https://github.com/andypike/rectify. It's a great layer for
           | my controller to handle request contexts. You might think
           | this is a glorified service object but I'm not a fan of
           | service objects unless they do just one thing (and are
           | allowed to loudly fail).
           | 
           | Components -- https://viewcomponent.org/ I'm not incredibly
           | sold on them but they do clean things up.
           | 
           | Forms -- Rectify has this shipped but it uses Virtus which is
           | quite old and hasn't been touched in many years. Shipping my
           | own similar is usually something like https://gist.github.com
           | /joshmn/39eb6f302650e09743387710591ab.... Not all of my form
           | attributes will map directly to a model, but I want my form
           | helpers to actually help me so I need some sort of object
           | that _can_.
           | 
           | Inputs -- I'll extend SimpleForm inputs (something I can't
           | live without) to DRY up my forms.
           | 
           | All together, this is typically something like this (the form
           | and command pattern, at least): https://gist.github.com/joshm
           | n/65cfbccc6c64abe6d463ba9708b00... (not tested)
           | 
           | There's usually also an `admin` directory since I also
           | usually ship with ActiveAdmin or Trestle. I've fallen in love
           | with the latter after making it behave more like ActiveAdmin.
           | When I need to drop out of its usual constructs I'll just
           | write a custom controller, but for the majority of
           | administrative stuff I can get 95% of the way there with the
           | DSL of either/or, freeing up time for domain-specific problem
           | solving.
        
         | pyridines wrote:
         | Are there any resources you recommend for people trying to
         | learn this style of Rails development?
        
           | joshmn wrote:
           | I do have a book coming out called Caboose on the Loose
           | (https://leanpub.com/cabooseontheloose) that goes over how I
           | build applications. It'll be for monies, but I plan on
           | uploading it to torrent and piracy sites; included is a page
           | that reads I'm cool if you pirate it. Happy to send an early
           | draft; email is in profile.
           | 
           | Some nuggets here:
           | https://news.ycombinator.com/item?id=35755423
           | 
           | A lot of it has been trying and failing -- a lot of times,
           | across a lot of different applications. Many of which have
           | been my own, but as of the last few years there have been
           | other people's applications too.
           | 
           | The first thing I look for when I go into someone else's
           | Rails app is to grep through `routes.rb` and look for every
           | route drawn that's not `resource` or `resources`. This has
           | proven to be a good indicator of the amount of smells I'll
           | encounter in the application. You can draw every route with
           | `resources` or `resource` and get clean controllers, which
           | leads me to my next point:
           | 
           | Your controllers are the most important part of your
           | application. It's the first and last thing your user touches.
           | Getting them right is the most difficult part of architecting
           | any application. "Fat models skinny controllers" does a
           | disservice to models, though, because they shouldn't be fat,
           | (insert transition)...
           | 
           | Models should represent your database and nothing more.
           | 
           | I could go on and on, and am happy to, but I'll quickly be
           | writing a mini-book here and detract from Eileen's great talk
           | at Railsconf. :)
        
         | nasmorn wrote:
         | Are you a freelancer coming in to help less experienced rails
         | teams solve their maintainability issues? How do you mostly
         | find work? This is probably the work I am most qualified to do
         | as I also work with Rails since 2005. I am a bit worried to be
         | tied so strongly to the stack in my offering but in reality
         | that is what I mostly do.
        
           | joshmn wrote:
           | For the last few years I've been mostly W2. One of my selling
           | points during the interview is that I've solved
           | maintainability problems as team lead/in an architect
           | position. When I have contracted, though, it's usually just
           | word of mouth from people I've worked with before who
           | remember me helping solve their maintainability problems.
        
         | rtheunissen wrote:
         | Replace Rails with Laravel and you get the same problem: the
         | recommended patterns make it easy to get started but eventually
         | work against you when things start getting big and busy.
        
           | gv83 wrote:
           | replace rails and laravel with django and...these frameworks
           | are great, but require great discipline and the ability to
           | factor systems correctly!
           | 
           | but TBH, discipline + correct factoring is kinda the baseline
           | to produce decent systems.
           | 
           | It's still leagues better with django/rails than with
           | "microframeworks" which are basically a giant spool of rope
           | for anything more than a handful of endpoints
        
         | 1123581321 wrote:
         | I've seen developers, even experienced ones, struggle to grok a
         | Rails app when it's been extended like that. Once they're up to
         | speed they appreciate the decisions and contribute to further
         | development. They're just not used to seeing that, as you
         | describe. Have you found ways to make the extended engineering
         | of Rails easier to understand for those used to limiting
         | themselves to the out-of-box conventions?
        
           | joshmn wrote:
           | > Have you found ways to make the extended engineering of
           | Rails easier to understand for those used to limiting
           | themselves to the out-of-box conventions?
           | 
           | Rails comes with a lot of the patterns I implement out of the
           | box. Forms are just ActiveModel objects. Services are just
           | POROs, as are queries. A decorator pattern can be done in 25
           | lines of code (https://gist.github.com/joshmn/87f14dc7d6b45a7
           | 2bd4e3f4fb8d82... Commands are a bit more difficult but
           | anything that can respond to context with flow control
           | handling is easy to grep.
           | 
           | There's a fine line between implementing patterns and
           | implementing patterns that behave as Rails expects them to.
           | Thankfully, as mentioned in Eileen's talk, Rails makes it
           | really easy to do this. While the underlying logic may not be
           | documented on the Rails Getting Started guides, peaking under
           | the hood isn't as intimidating as one would think.
        
       | eximius wrote:
       | Like any good magic trick, it's an illusion. While you're looking
       | over here, I've secretly built an unmaintainable monolith!
       | 
       | Tada!
        
         | nasmorn wrote:
         | As if micro services are inherently maintainable. Those are
         | really orthogonal categories
        
           | ecshafer wrote:
           | Most "microservice" implementations I have seen are just
           | monoliths spread out over many computers. I think breaking
           | services up has a place, but I also think its vastly overdone
           | and the hits to developer productivity, logging ability, are
           | real.
        
         | jeremymcanally wrote:
         | Sounds like you need to hire better magicians. :)
        
           | rtheunissen wrote:
           | A framework is no good if it requires that the engineers
           | working with it are excellent in order to not create a mess.
           | A great framework or language _should_ empower participants
           | with average ability and experience to produce good results.
        
             | joshmn wrote:
             | I think the problem is a little more subtle.
             | 
             | With Rails, you can call `relation.map(&:id)` and
             | `relation.pluck(:id)` and get the same thing -- an array of
             | `id`. But using map is 50x slower because it loads the
             | entire model into memory (ActiveModel is very expensive)
             | before enumerating; pluck fires a query and hits the result
             | set from ActiveRecord -- very inexpensive!
             | 
             | Average ability participants then fall for this foot gun
             | (and others like it) and end up designing things poorly.
             | One overlook quickly turns into accelerant at scale. This
             | isn't unique to Rails, but Ruby -- the delight that it is
             | -- makes it almost too trivial to do.
             | 
             | I've seen this happen at Rails shops many of us have an
             | account on, where I wouldn't consider the people I worked
             | with average ability participants either.
        
               | gls2ro wrote:
               | I dont understand how come a framework will help you
               | avoid that.
               | 
               | You can do a similar performance issue with anything:
               | here is a raw example: give to anyone a non-ORM framework
               | and the chances of someone hitting multiple times the DB
               | to query the same records increases with team size and
               | app scope. I am not sure there is a framework that can
               | protect your colleagues from doing select * and then
               | count the in memory objects instead of doing a count on
               | DB.
        
               | Sivart13 wrote:
               | But if you're going to render those `relation` records in
               | a paginated list anyway, pulling them into memory is
               | superior so you don't hit another DB round trip delay.
               | 
               | Which is to say, there's a lot of ways to do things, and
               | trade offs between the different ways, but isn't that the
               | case with any library or framework?
        
               | joshmn wrote:
               | > But if you're going to render
               | 
               | Sure - if - that's fine and optimal! In larger apps,
               | where there's more complexity, there are so many paths
               | that aren't that trivial and that's where the trouble
               | begins.
        
             | dasil003 wrote:
             | What's an example of a framework that meets this bar? In my
             | experience, the messiness is generally a function of scope,
             | team size and technical ability. Some languages /
             | frameworks give you better or worse tools for managing that
             | scalability, but context matters (right tool for the job)
             | and none can guarantee a good result if the team is weak.
             | What really matters is the technical leadership, who must
             | have both the experience, and sufficient influence, to
             | avoid going down a path of crippling technical debt that
             | eventually strangles the system.
             | 
             | As far as Rails goes, for all it's shortcomings, people
             | forget what web development was like in 2003. The dominant
             | paradigms were overwrought XML-powered J2EE with incredibly
             | low power-to-weight ratio for web development, or
             | unstructured PHP wild west stuff. These days every language
             | has a framework that was heavily influenced (directly or
             | indirectly) by Rails. Sure I wouldn't use Rails everywhere
             | (1000+ engineer team: java, lots of concurrency:
             | elixir/erlang, lower-level large systems: go/rust, etc),
             | but it still has a great sweet spot from the prototype to
             | moderate sized web app / API. Things that become weaknesses
             | as you scale (eg. ActiveRecord pattern) are based on
             | contextual tradeoffs that need to be made thoughtfully
             | versus declaring them table stakes for all web frameworks.
        
       ___________________________________________________________________
       (page generated 2023-04-29 23:02 UTC)