Why we're sticking with Ruby on Rails
about.gitlab.com
about.gitlab.com
Correct. Don't use tools aimed for Google levels of complexity if you're not dealing with Google levels of complexity.
Is it a good idea? Depends.
On the plus side: You have one underlying runtime and orchestration layer, with a lot of useful primitives (including and especially around deployments).
On the negative: You introduce yet another layer of complexity and abstraction.
The real advice is “don’t run stacks that make trade-offs or give up guarantees to be able to scale to a size you’re not at or solve problems you don’t have.”
We switched to k8s early on in the company and that little bit of work to get it operating with HPAs, etc has paid off in dividends over time.
Serverless is amazing when you use it the way its intended. Its not there to replace your entire ec2 workload.
my view is that if you are not on serverless, you are wasting resources that could otherwise been dedicated to building out domain knowledge
our team focuses on optimizing each function and less on devops/scaling. the plumbing work is gone and all we do is now translate business requirements. security concerns are also largely removed.
its a great time to be on serverless, it had to overcome lot of doubt but it is here to stay. no need to pay $5 / month either for your weekend projects. even if your project hits front page, it will still work, the billing is not even that bad for what you are getting.
> building out domain knowledge
What about all the knowledge that is contained in applications, services and libraries that run on RDBMs?
I'm serious, one of the reasons I shy away from serverless is I want to put together components at a higher level than functions. But maybe I'm missing something?
What advances in Serverless platforms like AWS Lambda prevent the need for configuring VPCs?
I haven't gotten into Kubernetes at all, but from what I've heard the bespoke-bash-scripts problem is largely solved in that world, so I've been toying with exploring it for our next project (still hosted on Fargate).
Serverless is not a silver bullet.
A lot of complexity we add to these systems is about fairness. Fair is always about narrowing the gap between best and worst case run times and trying to keep the result close to expectations, and being able to defend it when they don’t match.
unpredictable billing - this is why you setup billing alerts and not an issue unless you hit HN front page
vendor lock in - you can take your functions and upload it to google, azure, cloudflare
That said, for my own projects I don't go that route because when it is my own money I need the certainty of cost that something like a $10 droplet gives.
I know serverless will be much cheaper (probably almost free) for most likely loads, but if I'm hit with the extremely unlikely loads I'd rather a small droplet that struggles and dies than a performant serverless system that spins up my bill as well as my resources.
We’ve talked many times before about how ridiculous their amount of hardware is. There are really only two arguments for “why” that make sense to me: One, they are succeeding in spite of a very large degree of excess hardware. Two, all that hardware is about advertising.
Schadenfreude wants it to be #1, but I suspect it’s actually #2. And I hope that some day - soon - “overtracking your users” becomes a hot button topic in consumer safety, maybe not as serious as industrial pollution but pretty close.
Does that mean you should write microservices for your toy? Probably not. But the trade-off calculus for microservices is not scale. It is a lot of things. If you had an application that was extremely trivial to run as decoupled services, and the boundaries between them are not liable to change much, maybe you really should use microservices from zero, and benefit from better failure isolation among other things. But yes, probably not.
Still, I think the idea that microservices are not really a great idea is a flimsy justification for Ruby on Rails in general. It's fair enough to say that if your language, framework and library choices are working for you and your product, you aren't beholden to justify them really. That said, that doesn't mean they couldn't be better with different decisions, and it's sincerely hard to determine that. Sometimes, I get the feeling that articles in this vein are just as much about convincing the authors that they made the right choice as it is convincing anyone else. But it's not really that important, since I don't really feel you actually need to convince much of anyone, if you like your decision.
They don't need to convince us random HN readers, that's true.
But they do need to convince new hires, potential clients, and internal stakeholders that Rails is still the right choice. If you've ever worked on a large Rails SaaS app you know this subject comes up a lot.
Now when the subject comes up they can just send folks a link to the blog post, it's very convenient to have around for this purpose.
Having Google levels of traffic is another thing, but it's easy enough to get Google levels of complexity.
Sure it is interesting to see the historic reasons for Ruby but these days PHP is a very different language with an arguably much better optional typing story than Ruby. The community has matured quite a bit and there is lot's of people doing "enterprise-level" work. The whole comparison doesn't hold true for modern PHP.
In fact it would be interesting to reflect on the promises that Ruby on Rails made. Approachability and developer productivity it absolutely delivered but "not messy" ugh not exactly. It requires quite a bit of discipline and experience for projects to not get messy.
I don't mean to say Ruby on Rails is a bad choice. If you are invested in the ecosystem there is no reason to change (except when you want something like Elixir maybe). On the other hand other languages have long caught up and have their own rails-style frameworks that are not much worse. It is not that much of a unique selling point anymore.
Fully agree on the microservice part though.
Is Java hard to use? I don't think so. Is PHP messy? Before the restructuring that happened from PHP 7, not so much. In fact, it's pretty good now.
Are Ruby and RoR easy to use and well structured? They can be, if you are careful and stay on the well beaten path.
As always, for small applications, RoR is a breeze to use. But once you leave toy land, the heavy amount of helpful magic comes around to kill you. Oh you thought you were calling this function with that name in that file over there? Nope, magic code loading decided to pass your call to that implementation instead. (a.k.a. monkey patching is evil) Let's not talk about dependency management and the constant shuffles due to abandoned gems. Let's not talk about nasty upgrades from one major release of Rails to another.
But of course, I am being mean. The truth is that we, developers, make a mess of anything and when it becomes unbearable, we blame the tool and move on to another tool that grew from the ashes of other tools we abandoned previously.
And hence, things like Laravel are born and grow out of the lessons learned with RoR (among others).
As for Java, my Lord, the archeology of web frameworks based on it makes the archeology of life on earth seems simplistic. I survived servlets, JSPs, Spring, JSF, Struts, GWT, yada, yada, yada, generations of attempts at getting it right, growing on the putrefied corpses of failed attempts at not getting wrong.
I think it's progress at work, but sometimes it looks like a pendulum.
But Node.js, sweet node, how I love and detest thee.
And also https://news.ycombinator.com/item?id=32004219 , https://news.ycombinator.com/item?id=31684529
I agree to split into services where “you’r have to do that anyway”.
But adding services where part A of the monolith needs to use part B where a library would do the job seems odd.
If you are trying to solve a specific scaling issue, then sure, but this is rare.
The schema and generated classes could be a shared common library that different teams can work on (maybe with some architecture obersight)
Or if using schema-less each library “knows” it’s own json formats
Then you get nice things like atomic transactions across multiple “services”. You also have no network concerns.
You can pull out microservices for things that need special attention. Such as a spikey-load service that might need to run as a lambda.
Version management is a solved problem. Use your languages package manager and semantic versions.
I concede you need to stick to one language. Ish. You have C FFIs. A .NET app could reference a dll written in C++ or Rust. But yeah not as flexible as services. Although there are inbetween things like RPC.
So now you have in practice is a distributed monolith, with brittle, ad-hoc dependencies between services. A symptom is that most features require touching many MS.
It's much easier to start with a monolith and refactor it into microservices later than it is to refactor microservices written in different languages by different teams into a single codebase.
You could, of course, create this as a service. And then make possibly hundreds of calls to this service to generate a single web page.
Or, you can provide a library that does this, and the calls are cheap, reliable, and predictable.
Of course, if it is a service, the caller would locally the cache the information needed to make all the calls, do a batch call to the service, and then backfill in all the links. This then precludes generating and sending the page as you go, and creates the possibility for an explosion in complexity if a simple change in requirements that causes the arguments for the URL generation to be dependent on another service/library call.
Not everything should be a service call.
If you build a car and send each team off to find the best parts in isolation and screw them together, you don't have the best car, you likely have something that doesn't even drive, because the parts don't fit. The performance of a system is in the interaction of its parts, not the sum of the performance of its parts taken individually.
Teams can never operate independently because it only ever makes sense to improve a part if it improves the functioning of the entire system. The whole problem with the microservices approach it that it optimizes the wrong thing.
It's absolutely necessary for very large organizations though. The alternative of trying to centrally plan the IT operations of an organization of, say, 500,000, gets to be quickly intractable.
Groups try to do it with frameworks like SAFe and while that may help a little bit, in the end you need to treat different parts of the organization as individual silos that are able to control and execute on their specific mission set within the wider org. Otherwise the complexity of the problem set they're dealing with makes it impossible to do anything without breaking other systems or teams.
For some reason, I feel this is somewhat of a scapegoat and fails in practice. But I don't have enough experience.
I think serverless is fantastic on the other hand[1]. I had a web application where I was parsing shapefiles to then import them into SQL Server. These files could be massive and take longer to process than they took to upload. As a result I figured that it might make more sense to create a serverless function in Azure to parse them once they were uploaded to blob storage. This was very easy to implement and transparent. If you are using something like Azure and want efficient ways to process your data without doing it all in your monolithic application and blocking your users, or creating a thread in the background which makes me a little uncomfortable, then serverless is a godsend.
I think Microservice architecture if I had to pin where it might make sense would be for APIs. I would then emphasize on versioning each microservice API. If you do a microservice architecture for APIs you can update parts of your API without taking the whole beast down (unless you use something like Erlang or slots in the case of Azure Web Apps, where it forwards new requests to new slot). I think this might be a reasonable use case for microservices. For a normal website though, I think monolithic with some serverless helper functions (if needed) is probably good enough otherwise.
[1] Note: Let's not confuse microservices for serverless, because it's not necessarily the same thing, although some people use serverless to achieve the microservice architecture, serverless functions can do so much more!
The reason your monolith is a mess is because your organization has low standards on code quality and doesn't value it. It is not willing to invest in it, and probably your department didn't acquire the skills and habits to produce clean code in cheap manner. The developers who are used to good code usually leave you out of frustration. No one likes to be unproductive, especially productive people.
> We need to convert to microservices.
Sounds like a cool shiny new approach enabling better scaling and organization.
> We need to refactor this mess.
Sounds like complaining, why is it a mess anyways?
These two things may essentially be doing the same thing, organizing/breaking up the code logically, one just might sound more appealing to management.
“grug wonder why big brain take hardest problem, factoring system correctly, and introduce network call too”
Someone with a monolith that embeds the database could claim those who use MySQL failed to achieve modular monolithic.
Mobile App. Start with Service Workers and PWA and decide then if you need an app.
Whereas with Rails your stack traces are much longer and there's a lot more machinery each request has to go through. Rails has a lot more abstraction in general (you can blame Ruby's powerful reflection capabilities on that), but I found that I have to go delving into Rails' internals very little.
What you get with Django but not with Rails:
- An admin panel out of the box
- Python (which is a big win for me personally)
- Authentication out of the box, but still fairly basic
- A robust library of third party packages that benefits from python being used much broader than the web space.
- Class based views (this is the biggest thing I miss, by _far_)
- Better LSP support
- Django REST framework (rails isn't _quite_ as good but you can get kinda close by leveraging resourceful routing and the serializers that ship with rails)
What you get with Rails but not with Django:
- Websocket support out of the box (but not the greatest performance. A third party drop in replacement [Anycable] makes it much better)
- First party API for background jobs (but it requires a third party background job system to wrap, like sidekiq)
- First party integration of a JS solution (import maps)
- Second party integration of a JS bundler (js-bundling, written by rails authors but not included by default)
- Hotwire (although Django trivially integrates w/ a comparable technology, htmx, Hotwire is still pretty dope)
- Rspec and the rest of the Rails testing ecosystem (guard, VCR, factory_bot, capybara). Python has ports of some but not all.
In my mind, Django adopted just two things, I'd be very happy. I'd love to see a better async story in Django that would enable web sockets and stuff. And the second thing I'd love to see is a better story out of the box for playing nice with frontend build chains. And, as a distant third, I'd like to see an html-over-the-wire technology like HTMX favored and some light integration in Django to recognize some headers so it can switch between sending just template segments or if it should send one w/ the layout included. The testing ecosystem I don't think is possible for Django to lift on it's own and I'm prepared to miss it while I'm away. That other stuff, though, is unfairly aging Django imo.
I don't think any of React/Vue/Svelte are nearly as compromised and have nearly as big of a pit of failure. I find React a good option with an active ecosystem. React especially isn't ashamed of and doesn't hide its learning curve like Angular tries to, and that learning curve is especially designed to more often than not lead towards pits of success.
so maybe I'm just lazy but even though I've tried to jump on the whole FRP train (back when it was blowing up around ~2012-2013 .. there was a great tutorial about it and I caaaaan't fiiiiiiind it now but I spent hours going down memory lane thanks to HN's upvote history :D), but I don't really use it or feel the need for it. TS and a nice Result type (a la Rust), the standard Angular Input/Output bindings, dependency injection, a nice template language, and ... things are smooth and easy.
Most of the complexity is fiddling with business requirements, validation (the usual mapping backend data to frontend data), somehow performance was never a problem.
And compared to Angular I spent tooo much time fiddling with props in React, fighting with people and their half assed components, their ignorance of TS, and so on :)
I do wish that there was a larger culture of TS usage in the larger React ecosystem. But also I'm still comfortable writing my @types/ modules in DefinitelyTyped if I absolutely need to and want to contribute that work to others. That's generally a good recommendation, if you find an untyped React component check the DT issue tracker for it and post a request if there's isn't already an open one. A couple of "Hacktoberfests" I've contributed @types for requests on there, and I know there are others that are watching it more than just once every October or so.
Standard Angular Input/Output bindings are some of my problems with Angular. It's a worst of both worlds situation where some things use RxJS and other things use imperative proxies and the performance weirdness of Zone.js and the weird things it does to Promises and RxJS.
I also personally don't like the template language. I think it was a terrible mistake that the template language uses .HTML file extensions. I think that sends too many designers a false sense of security with the template language and I've had to correct so many things.
> somehow performance was never a problem
Everyone has different performance considerations. I still have a tree-shake and keep bundles as small as possible mindset. I also developed a lot of skills doing performance work in RxJS on Cycle.js projects and redux-observable "sagas" on the React side (and RX backends in C#/.NET). So I notice a lot more things to nitpick than the average casual RxJS user. That's a big reason I keep referring to how Angular uses it as a "pit of failure": it sets up casual RxJS users and junior developers to have a bad performance time, and in some cases not realize that they have bad performance. The biggest for instance are very slow memory leaks that will never impact a developer in the middle of an edit/compile/debug cycle because the app never runs for long enough at a time in that cycle (and the developer often has plenty of RAM anyway compared to the average user), but absolutely will drive end users crazy when they have to hard refresh the tab every few hours/minutes and neither the user or the developer will understand why that performance problem exists.
The blog post is here: http://blog.worldmaker.net/2021/06/26/angular/
This is my open source library attempting to wrangle some RxJS best practices out of Angular component design and its standard Inputs/Outputs/Template Bindings: https://worldmaker.net/angular-pharkas/
For sure, I won't clap for how great modern JS bundle sizes are, but I found that most of the time what dependency we use matters a lot more for bundle size than how I load and what and where.
> I still have a tree-shake and keep bundles as small as possible mindset.
I also aim for this. Though just recently on the current project we're working on reducing downloaded content size happened when I finally went ahead and compressed the unnecessarily large background images, fonts. (Plus edited the CSS to prefer the smaller font file.)
So all in all, I think over the years I positioned myself to work on smaller projects where all the biggest concerns were completely outside the frontend library, and I wanted something with built-in TS, and so Angular became the trusted choice :)
Thanks for the link! (haven't got time to read it yet :D)
Granted in a startup worrying about next week is wasted cycles but I don't think rails is so much more productive as to justify switching away from an existing stack (whether Laravel, Django, .NET or whatever. While Rails was a paradigm shift when it was new most all other languages and frameworks have adopted large amounts of the lessons from Rails). I'd urge you to give C# a second chance
What you need to do is figure out what the application is doing. Identify what the best language is for that task and just micro service it.
Move complicated tasks into smaller services. Don't compound the complexity into a monolith whatever you do!
You can get best resource utilization by containerizing an application. Most people say just multithread it Puma ruby whateves... you will go into coherency hell if your app is not designed inherentlt around the idea of puma. Just use unicorn and run it as a container. Right size it for that scale out accordingly.
But maybe you need to drive over a mountain pass and the pinto has snow tires on it.
What is Hotwire , though?
> Strada standardizes the way that web and native parts of a mobile hybrid application talk to each other via HTML bridge attributes. This makes it easy to progressively level-up web interactions with native replacements.
Strada will premiere in 2022
Hotwire is an alternative approach to building modern web applications without using much JavaScript by sending HTML instead of JSON over the wire. This makes for fast first-load pages, keeps template rendering on the server, and allows for a simpler, more productive development experience in any programming language, without sacrificing any of the speed or responsiveness associated with a traditional single-page application.
Like wanting people to send money to me by means of PayBack (bonus points), instead of PayPal, and vice versa at the supermarket's checkout counter.
It is. Nothing comes close. It's a shame there's such a stigma around it otherwise.
I do think that we're seeing the pendulum start to swing from microservices/cloud/PaaS everything back towards simple architectures and simple deployments and I'm hoping Rails sees a bit of a renaissance with that.
> Rails seems a little harder to share code between the web app and mobile apps
I've personally never seen this done well, ever. At least not in a way that the amount of code that can actually be usefully shared is worth the effort.
Laravel is as easy and productive.
Dear lord !! That sounds horrible.
This is such a dogmatic statement, showing a very biased opinion here. And it also depends what perspective you have.
The reduction of complexity for developers writing and reading the system, is at the expense of an increase complexity when running the system... Which is a trade-off a lot of companies are fine with.
At the end of the day modularity should _not_ be defined in terms of the interface between modules.
With a service oriented architecture (micro or otherwise) the boundaries are enforced much more strictly by definition so can't be changed or worked around that easily
Example dependency for Django: https://www.flickr.com/photos/51035630876@N01/4364929942
In my own rails projects I’ve helped mediate this by compiling ruby from source with jemalloc, but honestly I don’t have the mental bandwidth to hack into their whole omnibus thing, so I just switched over to gitea instead.
Also went with gitea. Runs on a potato. If you have few enough users you can stick with SQLite to make it stupid-easy to deploy and administrate.
I'm on the tools team of a mid-size company and gitlab works very well for our 200ish developers. The only real pain point for us is the difficulty of upgrading combined with the high tempo release cadence.
---
Our team is based on Ruby on Rails. A bunch of us lament "still being on Rails". We have a few small services in alternative languages. However, everyone we serious consider moving off rails, the list of things we'd lose just grows exponentially. We can never justify it.
Starter list:
* Built in blog/binary storage
* Built in migrations
* Built in models and relationship management. Seriously, it's so freaking easy to define rails models.
* Standards for segmentation
* Gems for just about everything
* Admin panel
----
I hope we'll eventually be out-scaling Rails - but for now I'd much rather pay an extra $100/month for the next server up.
Tests confirm correct results. The fact that they also confirm expected types is a free side effect.
...
> I had to fallback to using `any
What? Are you sure you worked with Java?
EDIT: This is also not really a Rails issue per se, but maybe architectural.
For most online businesses, the operating cost of servers is small relative to the costs of support, sales, marketing and R&D.
So, yes rails is slower, but it usually isn't slow in a way that is much of a negative for the business.
What really moves the needle is R&D effectiveness. If your servers cost 2x with rails but your devs also produce 2x, that is a trade that is a good one for many businesses (especially startups and saas companies)
That's just not true.
The vast majority of time for most web apps is spent in database calls. A typical runner up on time spent is remote system calls, which, if you accept the monolith tenet that maybe you don't need those, are minimised in a Rails app.
If your app does anything meaningful, typically, that "meaningful stuff" so massively dwarfs the part of the time "in Rails" that worrying about the framework time is optimizing the wrong order of magnitude. I base this claim on looking at multiple real-world Java, Node, and Rails apps in New Relic, and during performance testing. Hint: the rails app outperformed both.
Oh, wait--do you mean server costs? If you are talking about 2-3x more in servers, perhaps.
Have you compared dev salaries to server costs, though? Here again, you'd be optimizing a small cost when you should be optimizing the big costs that matter.
Which is why I wouldn't reach for a webserver that can only handle one request at a time per process
I'm interested in what impracticalities are involved in our threaded deployment of Rails?
It’s good that you used the word “usually”, w.r.t Gitlab it definitely feels slow. It’s not just a cost problem.
"Oh, this route takes 6 seconds to load. Why is that? OH, because it's making ten thousand database calls."
https://hn.algolia.com/?dateRange=all&page=0&prefix=true&que...
You're prob thinking of this one.
It was by GitLab, but not on their own site: https://thenewstack.io/why-were-sticking-with-ruby-on-rails-...
But for individual engineers, going all in on Rails is likely a poor career move, in the US at least. It's rapidly becoming a commodity skill and salaries seem stagnant.
no monolithic design or throw turds on a wall to see what sticks
fact is K.I.S.S and everything will be fine
rails will just mean it the container will be as bloated as python containers
don't and I mean it don't post deploy load rails... always compile
Lets say a node fails over dies kaput. In a proper scalable solution the service would come back almost instantly. You have some sort golden ami and leverage containers no post deploy comfiguration.
Even cheaper Lambda with API gateway. Now entirely dependant on API design but often works well.
You probably should focus on really understanding the problem your software is trying to solve first, your next few versions(iterations) will be to adjust your solution you thought would work. But you usually only understand the problem and the shortcomings of your solution (software) after the first few version.
All while you probably haven't even considered product-market-fit or talked to a few customers.
Focus on scalability day 1, definitely a big no in my book !
Release cadances are important toward maintaining stability and vulnerabilities. Without a maintained application you lose availability.
You are still asking where does scalability fall in? There are several points for building a scalable system.
One is a design on load. So if you work on a ruby application you will know that typically unicorn is single threaded unless you want to do something like sidecart nginx. Not always the best.
Going toward infrastructure with a ruby system. Someone might say oh lets stand up an instance let puppet manage it.
This is where someone just decided to use an orchestration system that typically supports ruby. The flaw in this is that if you are leverage a non-binary deploy and forcing the need to use gems at setup on an application you create a massive potential for drift to exist across your instances.
Suddenly you say I will use ansible to run scripts to verify the host and applications run and that they didn't lose coherency.
The flaw with this is that you just overly complicated your system and likely dug yourself a mile of tech debt.
What you would use is a scalable system be it lambda or containerized solution liek kubernetes.
One of the biggest wins is speed and deploy cycles too. Kubernetes and lambdas are scalable solutions.
So as an application organically grows in load a scalable system will allow organic resizing on the basiss of demand ensuring that it maintains availability.
You should embed one reliability engineer on a team who can also code.
E.g. start with a VPS. With most offerings, they are pretty reliable. If you need, make a failover cluster of two to make updates with very short downtime easier. You can add load-balancing and downtime-less updates capability later as it will make the whole system quite a bit more complex in most cases that are somewhat interesting.
Of course, if you just have a static website or something more or less state-less, doing the right thing from the get go is way easier. I have more interesting, stateful applications in mind here.