Some friends just notified us that this is trending.
Let me know if you have any questions/comments/feedback about the work! It was a great project, I wish we had more budget so that we could spend some time with ruzzy and the C extensions as there's probably some things to be unearthed there with ASAN and UBSAN.
As for the comments on Spring/Elixir/Django/Phoenix, they're on our wish list every year but we're always limited by funding. It's about what the communities, foundations, and agencies can and will support. We are always working toward getting larger grants where we can work fully independently on whatever we want, but so far that hasn't materialized.
> "X41 recommends to disallow the creation of un-escaped SqlLiteral objects with user input in favor of a complete model of SQL"
Rails already has a sufficient model of SQL in its Arel layer. Complete? Not exactly, because SQL is never implemented by the standard, but certainly sufficient, and very composable and extensible. Sadly the core team killed off the public documentation of Arel a few majors ago. Nevertheless I still use Arel whenever Active Record doesn't expose enough of the model, such as expressing left-open intervals as inequalities¹. Sometimes incorrectly called a "private API", but it's not anyone's private possession, Arel is just undocumented in recent releases.
The recommendation's language is also just a touch naive, because it's nigh-impossible to outright disallow developers doing practically whatever they want to in Ruby, there's no isolated sandbox. The question is what incentives are in place to stop them wanting to.
Active Record already has excellent support for bound values via the predicate builder, and it's only egregiously bad code that concatenates raw user-supplied values directly into query strings. Nevertheless for those few remaining places in the API where this could happen inadvertently such as #calculate, a variant recommendation - similar in spirit, but not identical - might be that where it doesn't already, Active Record treats raw strings supplied as requiring escape unless explictly wrapped with Arel.sql(), or just accept an Arel node/AST (many already do on the QT). That is, force the developer to confess their sin in writing, or do it relationally.
But IMO the wizards shouldn't keep Arel locked up in the tower, either.
> The recommendation is also a touch naive as framed, because it's nigh-impossible to outright disallow developers doing practically whatever they want to in Ruby
Sure but defaults matter.
Nothing is truly private in most languages. In C/C++, you can poke raw memory. In rust you can transmute. In Java you can override the classloader and edit classes before they’re passed to the JVM and so on. But most environments have a golden path for getting things done which most developers will walk. This is exactly what removing documentation does - it signals to developers that some API isn’t part of the expected golden path.
Every sql library needs ways to pass raw sql strings to the database. (Just as every browser framework needs a way to embed raw html strings). But it should require you to explicitly acknowledge you’re doing something unsafe. Rust’s unsafe keyword. React’s unsafelySetInnerHTML, and so on. It’s not about denying it. It’s about making the obvious thing safe and the unsafe thing not obvious.
Thats good news! I'm a huge fan or Rails but a little surprised of such little vulnerabilities tbh. Would have expected more for such large codebase. But happy to hear it aint!
I don't think it's meant to be a complete audit of the codebase, and in fact this is alluded to in the final report [0] (though the wording is strange—perhaps they forgot to update it from an earlier report):
> Due to the size of Ruby on Rails, it will not be possible to cover all the tests and tasks in the following test plan. The tests performed will be covered in the final report along with suggestions on what to focus on in future audits.
I feel like these sorts of audits are usually performed on individual applications rather than "mature" already widely used frameworks. I've got the sense that they are meant to give confidence that the developers knew what they were doing (since they focus on typical vulnerabilities that good developers should know about), rather than proving anything about the code base. Still better than nothing.
Wordpress is similar. The core project is quite battle tested, but the plugin ecosystem opens admins up to problems. With any system that allows modular code additions, the weakest attack area gets exponentially larger.
It's funny that Rails generates params for parameters passed to it for GET, HEAD and DELETE requests, even though it shouldn't. I think I've noticed this before when debugging but never thought much of it. In a poorly coded application (e.g. globally detecting params on in a `before_action`) it definitely could be become an issue.
After programming with elixir and phoenix for a few years (with many prior years of rails experience) I have a hard time seeing why one would choose rails.
Elixir is more performant, has compiler safety guarantees that are only getting better as types are introduced, is actually designed from the ground up for web dev (being based on the Erlang VM), and... it's just way more fun (subjective I know). Elixir is what I always wished Ruby was, and I couldn't be more excited about the coming type inference.
Programming with Elixir makes me feel like Ruby is a previous generation language, much like Ruby made me feel that way about Cobol or Fortran, it really is that stark.
> is actually designed from the ground up for web dev (being based on the Erlang VM)
Nit: this makes it sounds like the BEAM was designed for web dev, which it was not. Erlang came out of Ericsson and was built for telecoms (OTP stands for Open Telecom Platform), which is where its unique set of trade-offs comes from. Many of those trade-offs make a ton of sense for web but that's not because it was designed for web, it's because there's overlap between the fields.
One way to see the difference between telecoms and web is to ask yourself when was the last time that you were working on a project with an availability SLA of 9 nines (1/3 of a second of downtime per year) or even 6 nines (32s per year). Some web dev has that, but most doesn't come close, and if that's not you then Erlang wasn't built for you (though you may still find you like it for other reasons!).
Very true it is actually designed for telecoms, but like you mentioned the distinction is so small it's not really even a stretch to say it is purpose built with at least the general architecture of web in mind.
In the grand scheme of things, if we're considering everything from web to bridge building, yeah, the distinction is small. But within the world of software engineering specifically it's not all that small and it's worth being precise when we're talking about it.
Whatsapp and telecoms have a lot in common, so no one questions that they benefited a ton from the BEAM.
Airbnb, though? The main similarity is that they both send large quantities of signal over wires.
Again, none of this is to stop you from liking the BEAM, but when we're talking about professional software engineering it pays to be explicit about what the design constraints were for the products that you're using so that you can make sure that your own design constraints are not in conflict with theirs.
no. in the modern web world you often have persistent client server connections, which make it a distributed system out the gate. the most inefficient way to deal with this is to go stateless, and without smart architecture to deal with unreliable connection, it's really your best choice (and, it's fine).
since BEAM gives you smart disconnection handling, web stuff built in elixir gives you the ability to build on client-server distributed without too much headache and with good defaults.
but look, if you want a concrete example of why this sucks. how much do you hate it when you push changes to your PR on github and the CI checks on browser tab are still not updated with the new CI that has been triggered? you've got to refresh first.
if they had built github in elixir instead of ruby would almost certainly have this sync isdur solved. in maybe two or three lines of code.
And if you need that kind of persistent immediately reactive connection and are willing to pay the price, go for it! If that's truly a requirement for you then you're in the subset of web that overlaps substantially with telecoms.
I'm not cautioning against making the calculated decision that realtime is a core requirement and choosing the BEAM accordingly. I'm cautioning against positioning the BEAM as being designed for web use cases in general, which it's not.
Many projects, including GitHub, do not need that kind of immediate reactivity and would not have benefited enough from the BEAM to be worth the trade-offs involved. A single example of a UX flow that could be made slightly better by rearchitecting for realtime isn't sufficient reason to justify an entirely different architecture. Engineering is about trade-offs, and too often in our field we fall for "when all you have is a hammer". Realtime architectures are one tool in a toolbox, and they aren't even the most frequently needed tool.
what price? learning a new language that is designed to be learned from the one you already know with fewer footguns? ok fine.
but you make it seem like going to elixir is some kind of heavy lift or requires a devops team or something. the lift is low: for example i run a bespoke elixir app in my home on my local network for co2 monitoring.
and for that purpose (maybe 300 lines of code? yes, i do want reactivity. wrangling longpoll for that does not sound fun to me.
To name just a few costs that aren't worth it for many businesses:
* A much smaller ecosystem of libraries to draw from.
* Much weaker editor tooling than with more established languages.
* An entirely different paradigm for deployments, monitoring, and everything else that falls under "operations" that may be incompatible with the existing infrastructure in the organization.
* When something does go wrong, using a weird stack means you have less institutional knowledge to lean on and fewer resources from people who've been doing the same thing as you.
* A whole new set of foot guns to dodge and UX problems to solve related to what happens when someone's connection is poor. This has come up repeatedly in discussions of Phoenix LiveView—what you get in reactivity comes at the expense of having to work harder to engineer for spotty connections than you would with a request/response model.
* More difficulty hiring people, and an increased tendency when hiring for selecting people who are really just obsessed with a particular tool and unwilling to see when the situation calls for something else.
There are many more, these are just the ones I can think of without having a concrete application with concrete requirements to analyze. In the end for most apps reactivity is so much a "nice to have" that it's hardly worth sacrificing the stability and predictability of the established option for moderately better support for that one aspect of UX, especially given that you can always add reactivity later if you need to at a slightly higher cost than it would have come at with Erlang.
If reactivity is a core requirement, that's a different story. If it's polish, don't choose your architecture around it.
When José Valim “moved on” from Ruby development to work on Elixir, his fans followed.
It’s a bit like true believers switching faiths when their leader changes religions.
It’s hard to make sense of it from the outside looking in, but it’s definitely a thing that happened historically and occurs in small and big ways even today.
i had never heard of jose until i started working in elixir. i had about two years of grueling ruby experience[0] and boy was elixir an amazing breath of fresh air.
what is also a thing is stockholm syndrome and sunk cost fallacy.
[0] ok, now that i think about it also this was when ruby was having serious 1.84-2.0 transition troubles and i had difficulty reinstalling ruby if i needed to redo the os because some python wheel broke everything, so i had other historical reasons to leave ruby with a bad taste in my mouth. i think my gripes about activerecord are real, though.
> in the modern web world you often have persistent client server connections
Is this actually true though? I’d be interested if you know any data backing that perspective. I only know what I’ve worked on and my anecdotal experience doesn’t match with this statement. But I know my sphere doesn’t represent the whole. In terms of state, by now there are many ways of dealing with persistence and reconnection. Not only are most of those problems solved with existing technologies and protocols but they’re everywhere in web dev. Maybe we’re talking past each other? Did I misunderstand your point?
I switched fully to elixir close to a decade ago now and library availability is still lagging. For pretty much any company I can be pretty sure there will be JS/Ruby/Python/C#/Java integrations/libraries and occasionally you'll find one for elixir maintained by someone that stopped responding to github issues 3 years ago.
It's definitely better but I can definitely see why you'd still choose rails these days.
I agree with this sentiment, though in practice it doesn't seem to be much of an issue the vast majority of the time. Sometimes you do need that niche library though, and end up forking and updating for your needs.
Given how rarely this comes up it feels like a tolerable problem that will only diminish as Elixir adoption continues to increase; I am aware of many rail shops that are slowly and quietly switching everything to Elixir, and it feels like that snowball continues to pick up pace as Elixir improves and those libraries are created.
It may come up rarely for you but for my workflow I hit into it at least once a month and if you're a new user you will hit into it more frequently as they initially port stuff over. I'm not sure what the solution is and it obviously hasn't been enough to keep me out of the ecosystem but it is something that is noticeably worse.
I have a very extensive experience with both Ruby on Rails and Elixir/Phoenix. Also ended up building large full-stack apps on either framework.
In the beginning when Ruby on Rails said hello to me, I instantly fell in love with it and the simplicity and the natural semantics that flow with it. It was absurdly easy to write new features and ship them to production. As the codebase grew and the team grew we started running into situations where APIs broke, or to trace the workflow of things in terms of finding where methods came from, finding parent modules of modules, and finding their parents, configuration, and I started to note a general lack of IDE autocomplete and type-safety.
Then after a few years I jumped ship to Elixir and if felt like a breath of clean air when I had to learn FP. Everything was simple enough to understand. Performance knocks Elixir, Node, Python and any other interpreted stack out of the water. The Phoenix framework was, and is said to be thoughtfully designed and although there was no IDE support, we still had Elixir LS which was great enough to provide realtime guidance, linting and type safety during compile time.
I was able to ship a very large app into production and it was bulletproof.
The problem with Elixir was our other engineers struggled to shift away from Node, or any other stacks they already knew. They found the entire FP world to be weird. Hell, I found it weird too at times. Simple mutations of maps and arrays, that would be trivial in Ruby ended up being so complex in Elixir. In the end it felt like my team was not on the same page.
I guess Elixir would be great if you ran a 3-person team or something, but since we were not, we got back to Ruby.
In today's world though, I am largely looking at Go, for a backend system. IDE support is up there with Java, and the ecosystem is old and mature enough to find any package that you look for. Performance is C-like and learning curve is lean.
I was working with Go a lot as something complementary to Ruby/Rails. I have ended up with so much Ruby work. Either maintenance of large successful efforts from years ago, new development for those same companies, or new development from the people who have experienced great success with Ruby on Rails. I can't seem to get away from it, and that's just fine.
At this point, I putting together teams and getting new developers into Ruby on Rails. I'm also seeing companies move back to full stack RoR after the luster of React has worn off. Also, modern RoR can get you so far now with a fraction of the dual framework headaches of a RoR backend/JS frontend.
Great to hear. I agree - all the react/SPA bloat along with other layers like Vite/SSR/Webpack etc. is not needed for 95% of the apps today.
Any MVC framework with HTMX, JQuery (yes)/Hotwire/Stimulus/Turbo, etc. puts the productivity and deployment speed of the front-end setup above to extreme shame.
Rails has more baked in for the typical crud app. Example:
Try to create a way for people to upload documents like images and PDFs and documents. Okay easy enough on both platforms and I want you to generate a preview for each of those files so that people can easily find those files. Now I want you to add pagination. Now I want you to add column sorting so that people can sort by file size or by name or by upload date. Finally I want you to add a search field. Going by the way all of this stuff needs to live in the URL so that you can bookmark all the different you know choices you've made.
The stuff is pretty trivial and rails but in elixir you would have to bake it all yourself very boring code that doesn't really matter. This is why I chose to build my startups admin dashboard in rails despite our main production API being an elixir.
LiveView uploads are baked in, previews and all. Everything else you list is included in the Flop library, if you want something off the shelf. In rails you are still including Kaminari or whatever other gems for all this too, so this is really no different.
Extremely risky tbh I would have an extremely hard time if I go off path or need to hire someone. It would be almost negligence to choose it unfortunately
It's the opposite since it standardises everything as oppose to roll your own.
If you need to hire someone you'd need to train them on your system no matter what, with a framework you can use their documentation to explain where things are and how they work.
Elixir is already a small fraction of a small and shrinking community (Rails). Ash is a tiny fraction of an already tiny fraction. I cannot imagine defending this choice to anyone unless I was literally the CEO of a company and answered only to myself.
Elixir really needs to lose the perception, if there is one, of it being a subset of the Ruby/Rails community. It's true that the initial influx of Elixir developers came from the Ruby world back when Elixir was new, but that was a long time ago. Tons of Elixir folk come into it nowadays without a Ruby background.
Elixir and Ruby really aren't that similar anyway. The syntax differences are very superficial - Elixir's a functional language with very style and semantics to Ruby, and that's even before you get into the magic of OTP and the BEAM, for which Ruby has nothing comparable.
It doesn't really matter though. You have to train new staff on your systems/code base no matter what you use. So if they don't already know ash it's the exact same as if you didn't use it. Only now you can point them at the ash docs and buy them the ash book and they'll know where everything in your system goes.
I've been using Elixir for over 10 years, if it was ever a "small fraction of the Rails community" it was during its formative years only. Elixir is fully its own thing. We don't even really talk about Ruby? I really do think you've got a mixed up perception on that front
Some friends just notified us that this is trending.
Let me know if you have any questions/comments/feedback about the work! It was a great project, I wish we had more budget so that we could spend some time with ruzzy and the C extensions as there's probably some things to be unearthed there with ASAN and UBSAN.
As for the comments on Spring/Elixir/Django/Phoenix, they're on our wish list every year but we're always limited by funding. It's about what the communities, foundations, and agencies can and will support. We are always working toward getting larger grants where we can work fully independently on whatever we want, but so far that hasn't materialized.
We'll keep trying!