The 37signals developer team writes about Rails, Turbo, CSS, and moving their apps off the cloud.
HN commenters cite it in debates over vanilla Rails versus service layers, and over cloud exits. Reactions range from praise to calling one article ridiculous.
I've never read such a ridiculous article. I really wanted to give them the benefit of the doubt but good lord. How is any of this simpler or better? It's like they prefer the pain of 2004 mixed with the worst parts of modern infrastructure. The dream of the 2000s really is alive in DHH's head, isn't it?
TFA links to their cloud spend for 2022[0], wherein lies the rub:
> In total, we spent $3,201,564 on all these cloud services in 2022. That comes out to $266,797 per month. Whew!
> For HEY, the yearly bill was $1,066,150 ($88,846/month) for production workloads only. That one service breaks down into big buckets as follows:
What the actual fuck? THREE MILLION DOLLARS? A million for their email service?? I have seen bills much larger, but for what 37signals does I am shocked. There is surely a ton of low hanging fruit to drop the bill despite the claim that it's as optimized as it can get. No way.
Even then, Hey is $99/year, and they claimed to have 25k users in the first month or so as of 2020, that's nearly $2.5MM. I presume they've grown since then. Another 2020 article[2] mentions 3/4 of their users have the iOS app, and the Android app currently shows "50k+ installs" so let's assume we're talking 200-400k users as a ceiling, ignoring attrition, which would pull $20-40MM. Even if it's half that, the cost doesn't seem unreasonable.
They're spending nearly $90k/mo on Hey. Of that the majority is RDS and OpenSearch. TFA makes it clear they know how to run MySQL, why on…
I'm not going to put this down, because it sounds like they're quite happy with the results. But they haven't written about a few things that I find to be important details:
First, one of the promises of a standardized platform (be it k8s or something else) is that you don't reinvent the wheel for each application. You have one way of doing logging, one way of doing builds/deployments, etc. Now, they have two ways of doing everything (one for their k8s stuff that remains in the cloud, one for what they have migrated). And the stuff in the cloud is the mature, been-using-it-for-years stuff, and the new stuff seemingly hasn't been battle-tested beyond a couple small services.
Now that's fine, and migrating a small service and hanging the Mission Accomplished banner is a win. But it's not a win that says "we're ready to move our big, money-making services off of k8s". My suspicion is that handling the most intensive services means replacing all of the moving parts of k8s with lots of k8s-shaped things, and things which are probably less-easily glued together than k8s things are.
Another thing that strikes me is that if you look at their cloud spend [0], three of their four top services are _managed_ services. You simply will not take RDS and swap it out 1:1 for Percona MySQL, it is not the same for clusters of substance. You will not simply throw Elasticsearch at some linux boxes and get the same result as managed OpenSearch. You will not simply install redis/memcached on…
> * It's my view that MVC (and therefore Rails otb) is not ideal by itself to write a production-ready app, because of the missing service layer.
This is quite the claim. I despise service objects, personally. They end up scattering things around and hurt discoverability. There are other ways to do modelling that scale very well. There are a few blog posts on it, here's one from someone at Basecamp: https://dev.37signals.com/vanilla-rails-is-plenty/
This is of course very OO which I'm not a huge fan of. Elixir's Phoenix framework, for example, uses "contexts" which is meant to group all related functionality. In short they could be considered a "facade."
In any event, if you like services you like services, they can work, but saying MVC isn't enough for production-grade is a bit misguided.
I do agree that model callbacks for doing heavy lifting business processes is not great, though for little things like massaging data into the correct shape is pretty nice.
This was true, but the new Rails Turbo Page Morphing in Turbo 8 changes the game entirely.
I've been using it. The experience is amazing!
Some highlights:
* In 7 lines of code, with no javascript, I had my index and view pages live-updating whenever a model changed on the server! It is spooky good. Nothing against JavaScript, but now I only maintain one ERB view and no SPA. This is a large dev speed multiplier.
* If you have a page with a parent object where you add/delete child items, you make your actions delete/add the child on the server, and once the object is updated, the page just re-renders with no visible redirect/reload.
https://dev.37signals.com/turbo-8-released/
A diff with comments: https://github.com/basecamp/turbo-8-morphing-demo/pull/4/files
This appears to be riding the [Solid Cache](https://dev.37signals.com/solid-cache/) idea that DHH has started espousing. At the core of this idea is that SSD's are sufficiently fast for caching. Sure, this may work for 37signals, but that is because they manage their own hardware. That is the exception and not the rule. And, per [this discussion two weeks ago](https://news.ycombinator.com/item?id=39443679). SSD's aren't as fast for most of us that leverage "the cloud".
Sure, you can do it, but why? I am all for removing complexities in my infrastructure. That said, Memcached and/or Redis are both rock solid and dead simple.
This just seems to be a waist of time 99.999% of use cases.
A focus on morph by default means you don't have an explosion of endpoints and can write programs like the 300 redirect days. [1]
Once you want realtime/collaborative app SSE + morph lets you do that easily. Add streaming compression and this approach is suddenly crazy bandwidth efficient.
For people coming from react this gives you v = f(state) over the wire.
Lastly signals handle the edge cases where an out of bound morph would nuke your ephemeral client side state (mostly text input).
You can do this in htmx but you are fighting the design the whole way. Turbo is a bit better but doesn't have signals.
[1] https://dev.37signals.com/a-happier-happy-path-in-turbo-with-morphing/