Really surprised how many commenters are talking about using a faster language when the example of slow code in the post is failing to cache the results of an expensive database query.
In my experience, even in "slow" languages, that type of thing is the predominant source of major performance problems, and the supposedly "slow" language would be perfectly adequate if you an stop shooting yourself in the foot (and if you can't, a faster language will not help you).
I'm sure there are extremely high-performance or high-scale points where language choice starts to matter more, but I'm also not surprised if Shopify is correct not to think they're there yet.
Most CPU intensive functionality in the core Ruby lib is implemented in C anyway, to ensure performance.
The vast majority of overhead in the rails app I work on is poorly build data models and poorly written queries. It makes no sense to talk about marginal gains of a few percent or a few ms per request when there are DB queries that take multiple seconds to complete.
In our case, a large part of that is due to the decision that someone made 5 or 6 years ago to store large amounts of data as serialized ruby hashes in the DB, rather than JSON (unsure if postgres supported it at the time), or simply as separate tables.
None of the poor performance of our codebase is down to Ruby itself. Most of it is due to features and data models being implemented with no thought for performance, a lot of which wasn't an issue when first written but as we've grown have become a constant thorn in our side (e.g. retrieving a multiple-MB serialized hash from the DB just to grab 3 values, then doing this 10 times in a request)
It is surprising until you realize that Rails' ActiveRecord consistently wastes 100-200ms on every request just to serialize / deserialize data from/to the database.
So yes, a language that's both faster and has less overhead in its ORM / DataMapper library definitely will help you.
Our data-heavy API returns JSON responses from our DB in ~40ms using ActiveRecord. So no, it doesn't waste 100ms on every request! We're serving around 6000 requests like that per second.
Rails on Heroku is about the most inefficient combination you can get for a web server.
I've always thought of it as the platform you use for running toy apps with maybe a couple of dozen users at most and a low load. It's incredibly quick and easy to get a Rails app running on Heroku, a couple of hours at most. But you pay (in dollars and performance) for this.
Yeah, Heroku performance on shared dynos is really not great. The variability is very high also, so you'll get some requests seemingly randomly timing out. The dedicated performance dynos are better, but even more expensive. We were on Heroku for a long time but as the scale got too much we migrated to Google Kubernetes Engine which has been great.
That's not remotely true. If this is happening to you then you're almost certainly having N+1 problems which is architectural and would affect any solution you're using. Add google trace to get a breakdown of your requests SQL that's executing.
In an unusual situation it is possible in PG to have a very large pg catalog if you have thousands of tables and schemas which is resolved at run-time because Rails resolves models and types through db introspection, and the types specicially are only loaded during runtime. But that would be very unusual. I'm working on solving this in Rails because this unusual sittuation is affecting us.
I can only presume things have improved in the meantime.
Still, I regularly chat with Rails devs and to have a MacBook Pro 2018 return responses in 150+ ms is alarming. But you might be right that it could be a N+1 query problem.
Even without those though, I've still seen Rails apps perform quite horribly. So 50/50 from me, you might be correct but I wouldn't entirely discount the option that Rails is still quite suboptimal in terms of performance, compared to many other frameworks.
I mean I see rails perform horribly too, it's my job to go in and fix things, and I focus a lot on fundamentals (what's your DB doing, what data do you need to serve the request, what shouldn't be inside of the request-response cycle).
Because a lot of web developers these days build applications and ORM's are great but make certain patterns convenient so it's really easy to code yourself into places that don't scale. Then people reach for various caching solutions rather than taking a step back and looking at what's actually executing.
I've seen just about every bad pattern you can imagine and it's not usually obvious because the code looks simple enough. Like that permission check in your controller is actually serializing 1000 ids and querying against them, or that .first doesn't have an index so you're sorting the whole table, and much worse than that.
Sure. This is a thing regardless of language and framework. Point is, there exist some of them that are quite forgiving and don't give you a 150+ ms response time out of the box like Rails does for a number of projects I inherited in the past.
ActiveRecord is configurable. You have options to bypass the serializer. Rails can't magically have the correct answer to every problem out of the box without tweaking
Was that an argument? It seems pretty clear that that is not the goal of Rails. I'm arguing here that "Rails can't be performant" is not necessarily true
I am glad to see that there are much more reasonable Rails devs out there compared to some rather toxic individuals around in HN at least!
A lot of tech can be fine-tuned to be very performant. My point was (still is) that there exist technologies today that allow you to delay your scaling decisions much further in future, compared to what a stock Rails app (without any performance tuning) will.
Most languages bring their own ecosystem and associated phosphophy of how you'll use it.
The Ruby phosphophy seems to be lots of magic (in a good way) and in exchange you accept that details get lost behind the scenes and that it's only fast enough, but not truly fast.
Switching to a language that values speed with tools that have a different phosphophy can then make such a bug much more visible, due to the lack of behind the scenes magic.
While the phrasing irks me, I think I agree with the sentiment: "languages that value speed tend to expose more of the details, thus when presented with a performance problem, you have more options ready at your disposable". One of the biggest barriers for me personally as a long time user of high-level languages is going down into C internals and feeling like I can safely make changes. It also sucks if you don't want something that comes out of the box with Ruby (say you want a more memory efficient array than what Ruby gives you). C extensions allow you to add these things, but the knowledge is specialized and writing C extensions can feel like a black art due to a relative lack of resources on them
There are two other alternative interpretations that I think are untrue however:
* "languages that value speed give you tools that expose more of the details and thus help you avoid adding defects in the first place" which I disagree with because (1) the average programmer will not understand what most low-level options actually do and (2) exposing more options is like trying to program with ones and zeros - at some point low-level abstractions don't scale well in a constantly evolving project
* "languages that value speed generally have fewer abstractions and thus make it easier to find bugs because there is less abstraction" which I think is untrue in projects of meaningful size. Macros are very common to find in languages like C and arguably as complex as metaprogramming in Ruby. Additionally Java is considered a relatively fast language and Java projects often have lots of abstraction
First thing I tell anyone when they say "this code is slow because of X" is to profile it. Profile, profile, profile! More often than not your assumptions are wrong.
There's a myriad of tools out there for profiling, some language specific, some not. Learn at least one of them well, how to read flamegraphs and how to benchmark properly (warmup code, synthetic vs real traffic, etc). There's definitely a jump between making guesses and hoping you improve performance vs truly understanding what your code is doing.
Not sure when they clarified the licensing around GraalVM, but it's what kept me away from it since it's inception. Looks like the single executable binary is under the Oracle license side of the equation.
Last time I tried to run Truffle on the company test suite it spent an hour processing 1/8th of the suite. Then it was killed by the OOM killer. On a 32 GB machine. To be fair there was only one or two errors during that, so compatibility is at least getting there.
Meanwhile Ruby 2.6.5 chugs along and finishes the whole suite in 8 minutes. Never hitting any unreasonable amounts of memory.
Yes TruffleRuby struggles to run test code because it works against the optimisations we add to make production code fast. For example when you add more profiling to better optimise the hot code it makes the cold code slower, and tests are almost all cold code.
Also our C extension emulation layer used to be extraordinarily slow while we made it work correctly, and it's still rather slow.
It's a challenge but we're working on it.
But TruffleRuby is the only alternative Ruby implementation to even run major applications that I've tried at Shopify.
I'm not certain I buy that argument. Yes, the actual code of each test would be slower than usual, but the things around it, test harness, factories etc should get plenty of execution. And at least in our not so very good test code base, that is where most of the time is spent.
Amazing work and really appreciate all you're doing to better the ecosystem.
Question: (a) do you believe we'll ever get to a day when TruffleRuby/Graal will be able to 100% run Ruby on Rails and (b) how much faster over MRI do you believe it could achieve?
Compatibility yeah I don't think there's any reason we can't be very close to 100% there.
For parts of the Ruby ecosystem running production workloads, such as the Liquid template engine, I see 6x performance today. I think that's a realistic goal in time.
What speed gains do you get? Does it ever seen like a lot more trouble to try to optimize ruby instead of just writing slow parts in a different language?
I'm aiming for around 6-10x for real production code.
> Does it ever seen like a lot more trouble to try to optimize ruby instead of just writing slow parts in a different language?
I'm pretty philosophical about this.
People want to write and run Ruby code. I trust they've got their own good reason for that. Taking that as a given, I want to let them run it as fast as they can, with the best tooling I can give them. Instead of 'you shouldn't do that' I want to have the attitude of 'ok we'll see what we can do'.
I do personally really like Ruby and I reach for it pretty much whenever I start a new project.
Telling people not to do something is very acceptable in a company. If it is users doing something with a product, that's different, but technical decisions matter.
That person is commenting about another company, not Shopify. Though at one point in time our test suite did run under 10 minutes (across ~100 agents). Ref: https://buildkite.com/case-studies/shopify
I wonder what would be more efficient, constantly trying to eke out some performance out of a inherently slow language? Or writing/rewriting new/critical paths of the codebase in a faster language.
Ruby used to be able to say we sacrifice performance for developer productivity.
I don’t think this is any longer true, there’s plenty of languages out there that developers can be just as productive with, while producing wildly more performant code.
If you want the luxury of scale problems down the road you do RoR until you lock down that first couple billion dollars of valuation. Just ask Stripe, Github, AirBnB, Gusto, Shopify, Coinbase, Dropbox, Twitter, Door Dash etc. Then you can have the "problem" of picking the wrong language. Massive survivorship bias in the panning of Ruby/RoR IMO...
Also the Ruby/RoR community and culture is better than most other languages/framework. I think culture is a totally valid performance reason to pick a language. Sure there are faster languages and there are jerks everywhere but on average it seems RoR devs are on average nicer and more collaborative people relative to peers.
There is a just a mindset for wanting to write in a language optimized for developer happiness that dovetails with wanting to be happy and work happily with other people. Ya sure those C++ guys can write more performant code but I know who I want to work next to 8 hrs a day. And who I will be more productive working with.
Also I don't think there are plenty of languages that are Ruby/RoR peers. Django doesn't come close. JS ecosystem is a dumpster fire. Some functional and JVM languages maybe but they often come with a corporate culture that kills their benefits. Kotlin would be my bet I guess?
Also if scale is your issue and rails isn't cutting it then you need to go to a proven language with a proven and hirable developer base. That rules out a lot of new and promising languages. Sure they might be just as productive languages but they are resource constrained at the people level. It is really hard to hire Elixir/Phoenix devs etc. You need a talent pool of thousands. Also you need to KNOW the language will be there with a community in 10 years and that it has a history of evolving without screwing over the community. I guess Twitter going to Scala would be an example of this, from my understanding it doesn't solve all their problems.
Total aside: plenty of language need massive tuning to work at scale but it seems like Ruby is unfairly singled out if someone does "exotic" tuning of it but if someone tunes a JVM language or invent their own it is supported.
> Also you need to KNOW the language will be there with a community in 10 years and that it has a history of evolving without screwing over the community.
I don't think this is true at all. Where was Rails 10 years ago? It was pretty bad compared to today's Rails. If the Rails 2 and Rails 3 rewrites never happened then RoR likely would've been superseded by something else and be "dead" today. The point is that Stripe, Github, etc were all early adopters of Ruby and accepted that risk
> You need a talent pool of thousands
I also don't think this is true. You need to hire the right people and you need for them to stick around. And you need to be in the right line of business obviously. Again most of the companies you listed were small/passionate/scrappy for a long time
Edit: downvote away for disagreeing. I don’t see anyone presenting a counter argument.
This has not been my experience.
It has been “do it THIS way in ruby” even though either way is perfectly valid (eg list of Literal strings / symbols vs %i or %w.
Lots of bike shedding type discussions on which way is better and unsurprisingly no consistency across the codebase.
There’s also a lot of hidden things you can only learn from years of usage and no clear documentation of when / where features came and went.
All in all every Ruby dev I’ve worked with across 4 companies have all had the same sort of elitist / pretentious attitude compared to Python, Go or Java devs. Ruby has only been second to Scala and Rust devs (so far).
Seems like you're comparing between languages that end up being the default choice due to their low learning curve (Python/Go/Java) and languages chosen because the default choice wasn't good enough (Ruby/Rust/Scala). The latter tends to be much less restrictive or more featureful which necessitates governance by convention/culture/guidelines since its significantly more difficult to be exactly prescriptive over significantly more variance.
I personally find the first set of languages to be more consistent syntactically (typically because they're simpler languages that have auto-formaters) but the latter set of languages are extremely consistent in patterns/ideologies. It seems like you care more about the former and didn't care to learn about the latter (which I'll admit, does present a higher learning curve and tends to be acquired through experience with the community than through a doc).
I find that Rails apps tend to have some of the most consistent styling (within the codebase, and between codebases) of any language/framework out there. There's generally the "Rails" way of doing things, usually whatever Rubocop defaults to.
Also, "perfectly valid" doesn't mean "good", or "best practice", most style rules tend to reason beyond just looking pretty. String literals are slower and use more memory than symbols, and they're harder to grep for (either visually or with grep) in the codebase. More importantly, it's a lot clearer in code what a symbol's intent is, it's an immutable internal identifier, whereas strings should be used for storing data. Strings are mutable, which can be a source of bugs, a fairly trivial example would a developer making a typo and writing `str += 'label'` instead of `str = 'label', using symbols would raise an exception. Same for using %i or %w for arrays of integer or words, it ensures that the contents of the array are of a consistent type (at least at that point). Personally I don't think it should be a strict rule (I've turned the lint rule off on our codebase), but I do use them where appropriate, in particular when defining a constant as an array as it makes it clear to others reading the code what its intent is.
The only real complaint I have about Ruby style is that there's a million ways to work with enumerables, often with subtle differences in behaviour. For example, extracting a value or default from a hash is commonly done with `hash[:val] || 'default'` or `hash.fetch(:val, 'default')`, if the the key exists in the hash, but with a falsey value (nil or false), it will return 'default', but the second will return the falsey value. This can be good or bad depending on your specific use case, but I've come across unexpected behaviour from both versions.
I definitely agree with you about hidden features though. I've spent hours this week reading through different gems' source code because the documentation was lacking, at least it's generally readable code. It's frustratingly common when reading gem docs for me to find `#method(opts={})` as the method signature, with no additional explanation as to what parameters it takes.
I much prefer Ruby having a prescriptive style guide that the majority of developers use, I can look at the source code for any gem or app and immediately be familiar with how it looks, it's a lot less overhead when starting on new codebases. Compare this to C, where there's half a dozen different conventions on where to put your curly braces, or JS, where there's arguments as to whether lines should end with a semicolon.
You're right that a lot of ruby developers are pretentious, especially compared to Java or C# developers. Most Ruby developers are programming/technology enthusiasts, they have a passion and interest in what they do, I spend a fair amount of my spare time programming, or reading about programming. This is especially true for experienced developers (before bootcamps were all teaching Rails), they learned Ruby in their own time, not at university.
On the other hand, a lot of Java/C#/Python devs do it as a job and nothing else, which there's absolutely nothing wrong with, everyone has different hobbies and interests. One of my coworkers was previously a Java developer, and he has no particular interest at all in programming, he would probably be just as happy as an accountant, he spends his spare time painting or with his family.
> there’s plenty of languages out there that developers can be just as productive with
There aren't that plenty really. Golang has nothing like Rails, neither does Node. You can say Django / Laravel but then it's the same performance issues.
Or maybe you're talking good old enterprise software like Spring / Asp. I don't think Ruby/Rails should feel inferior to any of those names for web development.
I think you can absolutely be just as productive with JS, but it's also easy to be incredibly unproductive.
The problem I have with JS (both for server side and client side) is that there's usually several different packages/libraries/frameworks to achieve the same goal, and often one gets deprecated in favour of another, requiring constant updates and changes to the development and build environment. JS development is all about the flavour of the week. For example gulp/grunt/webpack, or NPM/bower/yarn. This is compounded by the lack of a standard library.
Every company has its own particular build system (and configuration of that system), libraries they use, style guide, and file/folder layout. It's also very easy to abuse scoping and class mutability, with only style guides and eslint to save you. It can be a lot of work keeping a larger and older project up to date.
> The problem I have with JS (both for server side and client side) is that there's usually several different packages/libraries/frameworks to achieve the same goal, and often one gets deprecated in favour of another, requiring constant updates and changes to the development and build environment. JS development is all about the flavour of the week. For example gulp/grunt/webpack, or NPM/bower/yarn. This is compounded by the lack of a standard library
So which ecosystem is more productive then? What you just described is horrible for a company like Shopify; they aren't a 3 men team working in a garage. And even for a small team, why would you wanna chase a crazy ecosystem like that instead of focusing on your actual product?
I think that it can be a productive ecosystem if you have experienced technical leadership that's proactive in keeping things up to date. If you spend a bit of time every month or two keeping your dependencies up to date it's not too painless, but if you neglect it for years, then it's an absolute pain to update.
I've discovering this the hard way as I slowly upgrade our front end from AngularJS 1.4, no transpiler, gulp, and bower. Almost much nothing has been upgraded in 5 years, which is like 50 javascript years.
JS is not a great language to use if you're an independent beginner, you either have to follow a tutorial blindly to get a boilerplate setup and hope that in the 6 months since it was written nothing has changed in the libraries used and the tutorial is out of date, or you can spend hours learning how to structure a JS app.
I feel like I'm being harsh on JS. Ruby/Rails is an incredibly productive ecosystem for a beginner, but has the same problems with maintainability and upgrading if you neglect it too.
Any framework isn't productive when you're in greater technical debt than the Weimar Republic, and it's easy to write bad code in any language if you're lacking experience. Upgrading dependencies in any ecosystem is difficult if you don't touch your gemfile or package.json in half a decade. I've had the same problems upgrading our Rails app as our AngularJS app, I'm just much more qualified to handle them.
There were also no experienced Ruby/Rails or JS/AngularJS developers at my work until I joined (and there's still no experienced JS devs), and we've always been pushed to ship features, not improve performance or keep our dependencies up to date, so I've had limited opportunities to work on fixing technical debt. Not entirely sure why you'd create a product with two frameworks none of your employees have any experience in. On the plus side, with all this spare time I've had during lockdown, I've managed to make good headway in resolving a lot of that debt, beats spending my days watching Netflix or playing video games.
I don't wanna answer for Shopify because I don't work there, but:
1) Shopify LIKES Ruby. The founders love it. You don't drop this after 15 years to gain 20% more speed.
2) Rewrites are hard. We're talking about millions(?) of lines of code
3) Their teams will have to adapt to a new language
4) Maybe 10 years from now a faster language appears - do they do a rewrite yet again?
5) Optimising things is a part of what we do as developers and even love to do. Is it unheard of to try to optimise your code in java?
6) > there’s plenty of languages out there that developers can be just as efficient in.
That was always the case. Rails devs still believe (for the most part) their framework is productive and fast enough.
They're still mostly a Ruby monolith afaik, so you can't add new features in Go on top of that. Each company and what works for them.
> They are clearly already spending a lot of resources optimizing Ruby code to match their demands.
I think the work on Graal is a VERY long term investment. They can grow to become a 200B company even if none of that work succeeds. Also, I think it's just one guy Shopify is hiring to do that but I may be wrong, so definitely not a showstopper for Shopify :)
I don't see why that would be the case. In fact, the performance improvements during the 2.x era seem to indicate the contrary: that Ruby can be faster.
Well, the extensive use of “method_missing” appears to be staggeringly difficult to optimize short of a tracing jit and it’s also the core idiom of many popular frameworks. Of course it can be faster—if you remove the slow, unique features you can optimize it like any other language.
Which tracing jit would you recommend for production work?
The implication is, of course, that there isn’t a good one. This isn’t ruby the language’s fault, it’s just weird that after like 15 years being the go-to tool for VCs there’s no substantial investment in the core infrastructure.
We just gotta wait for banking software to be written in it, I guess, so there’s a vested interest in it over the long term.
Edit: I’d like to further note that other languages use similar features (string-keyed functions) but they aren’t typically put into high performance code/are seen as a hack around formally definitions (possible exception: common lisp, although I would expect a macro). This is inherently a readability improvement over manually defining the methods you use.
JRuby optimizes method_missing in production right now so there's no need to wait for a tracing JIT.
I hope that Shopify will start to invest more into R&D for CRuby as well now as well as having Chris there working on TruffleRuby.
I'm not sure what you're trying to say with the last part because Ruby works quite differently to Lua or Self here and Self has been "fast" for 30+ years anyway.
Yes, and at the time Shopify was started Ruby was likely a very good choice. The parent comment is saying that today there are alternatives that run faster and provide similar levels of productivity.
> Shopify is an insanely huge e-commerce platform (and a $100B company).
That's an interesting note. They have a $90b market cap, trading at ~53 times sales. It's one of the more extreme valuations I've seen in the last 25 years, including the dotcom bubble (and that's saying something with how overvalued everything cloud-related is today).
As one comparison for the absurdity, Yahoo during most of the height of the dotcom bubble, was trading for 30-50 times sales, growing sales faster than Shopify, and they were solidly profitable (Shopify has never earned a consequential profit in its history). That's how bad Shopify's present valuation is, to get good comps you have to reach into the dotcom bubble.
The market thinks they're Amazon-like. The problem is they've never demonstrated any great margins in their platform (despite 14 years and counting) and Amazon's big lift-off in their stock occurred solely due to the ability of AWS to generate immense operating income. Without AWS, Amazon eventually gets the sad multiples of a Target or Walmart on their retail business.
This is an obviously mistaken valuation riding one of the most overvalued markets in US history, one that will most likely brutalize investors that get in late. It's a classic example of how very inefficient and irrational the stock market can be in the shorter term. And no, that doesn't mean an investor should be the fool to step in front of the irrationality train and short it either (everyone here probably has heard the Keynes line about the market remaining irrational longer than you can remain solvent).
It'll take at least 10-15 years at a minimum for Shopify to grow into its present valuation, in the best case scenario, if everything goes perfectly and they some day find some margin in their business. If they eventually manage an enormous $2 billion profit ($1.7b in sales today ttm), they'll still have a 45 PE ratio at today's valuation. That's a prime market example of insanity.
eBay has a vastly superior business (in all regards, including its quasi-monopoly positioning and the tremendous profitability of ebay's platform), trading for a huge discount to Shopify, on the basis of the market's mistaken extrapolation about Shopify's future. If they're lucky, they'll one day be the size of eBay with a fraction of the profit margin (and of course eBay has a mere $29b market cap, 12x op income multiple; compression is a killer). I mention eBay (beyond obvious reasons), because Shopify is likely doing nothing more than pulling future returns forward to an extreme, as eBay once did (leading to a decade of stagnation in the stock).
They are probably overvalued.
But they have a great product worth tens of billions and will eventually get earnings in line with their valuation. I wish I bought that stock years ago. No, wouldn't buy it now indeed.
You’d have to compare them to an equivalent shop in the same market of about the same size with a different stack to get a meaningful answer out of this—I’d say off-hand that it’s very unlikely their edge is tech.
You only need to be more efficient than the competition, and there’s a shared incentive to push out products faster than you can maintain existing ones. Over the long term it never makes sense to use ruby; only in the short term when it provides a marginal improvement over the competition does it pay off.
Benchmarks are subjective, but all benchmarks show Ruby as slower than compared dynamic languages. The relative speed difference is different per benchmark, but across the board Ruby is slower.
It fundamentally has to be slower. Ruby is the most dynamic of the dynamic programming languages. And the community has embraced metaprogramming, making it every more dynamic. Especially on webservers, you'll be executing hundreds, sometimes thousands, more lines of code than other servers, especially in a mature system.
Is it "slow" enough to matter? Probably not until you get to a medium scale. Everywhere I've worked, we've had to on average double the hardware specs for Ruby servers to make them as performant as other dynamic language applications we run. Not the most expensive thing in the grand scheme of things, but there are entire cottage industries of magically tuning Ruby and Rails that you don't have to worry about with other systems until much larger scales.
The article doesn't even discuss benchmarking Ruby against other languages, so I'm not really sure what you're on about. Couldn't resist taking a performance jab at Rails?
Also, I'll take "double the hardware specs" if it means I'm actually able to focus on what I'm building and not dicking around with devops or rebuilding all of stuff Rails metaprograms for me by hand.
If there was a framework for being as productive as Rails at half the cost then it would be flourishing. There isn't and as a result Rails isn't going anywhere any time soon.
> Also, I'll take "double the hardware specs" if it means I'm actually able to focus on what I'm building and not dicking around with devops or rebuilding all of stuff Rails metaprograms for me by hand.
Try 7x to 11x. That's the amount of reduced RAM usage -- and the amount of increased accommodated users -- on identical hosting by the two apps I rewrote from Rails to Phoenix.
> If there was a framework for being as productive as Rails at half the cost then it would be flourishing.
Bold of you to assume technical merit is the only factor. Historically this has almost never been true. There are a number of web frameworks that perform much better than Rails and are quite easy to work with.
Cargo culting is a powerful force. Corporate inertia -- even more.
And yet Phoenix hasn't stolen a significant amount of market share from Rails.
> There are a number of web frameworks that perform much better than Rails
If you're measuring hardware loads and busting out your stopwatch to measure response times, then sure.
Bottom line is, there are plenty of good reasons to choose Rails over Phoenix. If you want to label choosing a well-backed framework with an incredibly mature ecosystem "cargo culting" then by all means.
Have fun writing Ecto queries by hand, wiring up document storage on your own, trying to find a standout auth library of choice like devise, finding a library that makes managing database views less of a pain, wiring up end-to-end system testing.
I'll be over here running rails new, wiring up sidekiq to ActiveJob, and building shit with ease.
> And yet Phoenix hasn't stolen a significant amount of market share from Rails.
I thought we all learned popularity does not correlate with quality. It correlates pretty closely with corporate inertia and perceived lower risk of developer churn though. Businesses love tech stack for which there are bigger pools of programmers. Says nothing of the quality of the stacks.
> If you're measuring hardware loads and busting out your stopwatch to measure response times, then sure.
Needlessly snarky. Response times matter in a lot of businesses. Count yourself lucky that it hasn't been an important metric in your work.
> Have fun writing Ecto queries by hand
I do have fun writing those. Most times the code in my functions ends up more readable than the equivalent Rails code I wrote years ago. There are some exceptions where you have to dig deeper. Haven't seen a framework -- Rails included -- that lets you handle all complex cases with zero deeper digging needed. At one point you do have to understand SQL and query optimizations, no ways around it.
> wiring up document storage on your own
What for?
> trying to find a standout auth library of choice like devise
It's called Pow and works very well. Additionally, Elixir's maintainers themselves are authoring such a library at the moment.
> finding a library that makes managing database views less of a pain
We can argue if this is a good thing until the Sun explodes. It really depends on the business. I have consulted for businesses where it was very important and true enough, using a library that's well-tuned for classic web apps (like Ecto and ActiveRecord) isn't the best idea there.
> wiring up end-to-end system testing
For 3.5 years with Elixir this is the first time I hear that this is a problem. Any data to back this up?
> I'll be over here running rails new, wiring up sidekiq to ActiveJob, and building shit with ease.
More power to you. Rails is excellent for an MVP or a prototype and this is well-known. It's what comes after is what has burned me out of it. Its maintenance burden is much higher than many others, including PHP's Laravel.
> For 3.5 years with Elixir this is the first time I hear that this is a problem. Any data to back this up?
My point is that it doesn't come with Phoenix out of the box (unless something has changed?), and that difference in philosophy is the core of what I'm getting at. With rails new I'm getting an end-to-end test suite and chrome driver installation for free.
Phoenix also has no plans of implementing something similar to ActiveStorage do they? How about ActiveJob now that elixir developers have rediscovered how great a queueing system is with the adoption of Oban?. Will Phoenix ever make a move to include something like ActionText?
They won't even consider adding basic things for developer productivity like undoing a generator.
The Rails team is much quicker and happier to extract something out of the companies supporting it (Basecamp, GitHub, Shopify, etc) and include it directly in the framework, whereas the Phoenix team seems much less willing to take a "batteries" included approach.
There's a balance of making something easy to use and making something "technically superior". The Rails team seems to care much more deeply about what the framework feels like to use, and the Phoenix team cares more about building something that is "dogmatically perfect" (which you're correlating with quality).
What's easier for someone to learn?
rails g model article title body user:references
mix phx.gen.html Content Article articles title body
I understand what they're going for here, but I'm not sure the tradeoff is worth it. If Phoenix wants to increase their adoption, then I think they need to accept that things like this matter.
When my small SaaS customer calls and asks for an extra extension at current hard times, then all I need is to open up Rails production console (pry) and live type in an ad-hoc code with auto-completion aid:
$ rails c
Loading production environment (Rails 5.2.0)
[1] pry(main)> s = Subscriber.find_by_email('xyz@abc.com')
=> #<Subscriber:0x000055dbb64c3bb8
id: 12913,
email: "xyz@abc.com",
state: "active",
expires_on: Fri, 15 May 2020 14:10:19 UTC +00:00,
...
[2] pry(main)> s.expires_on += 2.months
=> Wed, 15 Jul 2020 14:10:19 UTC +00:00
[3] pry(main)> s.save!
=> true
Pedantry aside, we've reached a point in our industry where we can do a lot with horizontal scalability.
I mean, every programmer who funnels through university understands map reduce, and that helps on multi-core threading up to system job running.
But there is a limit, usually in the persistence and caching layers. What you'll find is that those "large scale deployments" are going to have a -lot- of internal cache systems and I can pretty much guarantee that the services running those caches and persistence will not be written in ruby.
You can make anything* scale, but how many CPU cycles you need to burn to get the functionality you want is a matter for the finance department.
If you're running in a lossy business, you can bet that those CPU cycles will begin to cost more than developer velocity is worth, because servers are an eternal and ongoing cost.
On the flip side if you make more money than the infra+devs cost, then nobody is going to hound you for wasting 2x 3x the cost. Because "it's the cost of doing business" is easier to justify when you're cash positive.
> services running those caches and persistence will not be written in ruby
So what? What's wrong with using software like redis for cache, for a very small (but important) part of your business?
I bet java apps use redis as well, and redis isn't written in java. So?
Local caches and local node caches are both very useful. (That's why Redis 6 introduces this https://redis.io/topics/client-side-caching), but anyway from what I saw in the past, the major speedup of using Redis in such a context is that you want to use a shared very fast view that is global in nature. A simple to understand, but good example, is the leaderboard problem in multiplayer games that have million of users (Facebook games and such). Even if you have a local cache, and even if you have an additional store where you record the high score of each user, you need a global and very fast to update view of all the sorted scores, to tell the user its rank, users nearby, the rank of their friends. There are a number of problems like that that require to use different data structures and a global view. The problem is that using Redis with the Memcached mindset, will always severely limit the potential benefits.
> Why would you need an external service for that? It's adding complexity -- and likely hosting costs.
We're also dependent on mysql, are you gonna implement that in Elixir as well? Redis is a great piece of software, and it's a real SHARED cache, so it could work for sessions or other small state management you sometimes want to remember for example. What you described won't work for that.
Interesting but not surprising; I'm being regularly pleasantly surprised by the Erlang/Elixir ecosystem :) . Can you precise what you're talking about when you say "Erlang/Elixir have built-in caches" ?
My point is that for all the talk of how performance doesn’t matter and that we can scale ruby, the real heavy lifting is not handled by ruby.
It’s not a “problem”, but if you’re going to talk about large companies scaling something you need to understand that they’re likely scaling it in spite of limitations.
Largely, some systems don’t scale too well (latency on network accessible cache, throughput in persistence layers such as databases) so a lot of application layers will lean on those things heavily and they are exclusively written in relatively “faster” languages.
I guess that's so though it's interesting in the early days Github didn't:
>...a web startup like ours doesn’t need any outside money to succeed. I know this because we haven’t taken a single dime from investors. We bootstrapped the company on a few thousand dollars and became profitable the day we opened to the public and started charging for subscriptions.
Tom Preston-Werner in 2008. I guess the thing is not how much the hosting costs in absolute terms but how much it costs relative to what customers are prepared to pay for the service.
Once a business grows to certain size and beyond the shareholders don't want to hear anything about tech rewrites. They are happy the product is working, they are not alarmed by slow response times (which GitHub has plenty of on my gigabit connection that streams 4k@30fps without any lag) unless there's a big customer churn, and hosting costs, even if big-ish, to them are just the cost of doing business.
My point is, yes, you are right -- but there's a lot of conservatism involved once the business gets to a certain size. Nobody cares about improving anything from then on (which usually leads to the now-giant to start steadily losing relevance; GitHub is quite far from that but we all remember Microsoft, right?).
I’ve seen videos on Twitter of the Shopify CEO saying that Ruby’s performance literally doesn’t matter to them. That it’s easy enough to scale it horizontally and the benefits outweigh the cost.
A monolith doesn't necessarily mean slower, even with Ruby. There are lots of opportunities to run less code on each request, do some work with the db, and to split off measure bottlenecks into services in a faster language. It's often good to build things quickly, find fit, and then carefully measure before you introduce calls over the network.
A monolith is a problem which they are also breaking down, when you want to make something faster it's easier to target the service that does it vs the giant app.
Edit: getting downvoted by people that don't work at Shopify.
Stop painting ruby as slow. In benchmarks i've seen it's handily beat out PHP, which still runs much of the web. the ruby 3x3 goal, of getting running super mario at 60FPS, was if i recall correctly, already reached (or close to it) in ruby 2.6. https://developers.redhat.com/blog/2018/03/22/ruby-3x3-perfo...
additionally:
> Sinatra + Sequel is already very competitive in web performance with Go
> Between Ruby 1.8 and 2.5, performance has improved around 13x in tight loops[2]. The Rails performance issue has been massively overblown since 1.9 was released.
"Sinatra + Sequel is already very competitive in web performance with Go"
A lot of the time, that "competitive with X" in web frameworks is because the scripting language has a web server coded in something other than the scripting language. I don't know about that exact stack, but I know that's the case for Node, for instance. The web server is written in C. So when you benchmark a "tight loop" in those languages, you are running 99% C and 1% your scripting language.
Now, that is not a bad thing. It is a valid result, in the sense that it is a good thing for environments to have fast web servers, and nobody cares what the implementation language is... with perhaps the sole exception of this case, where we're trying to compare the performance of scripting languages by their web server implementation. You can't claim "Scripting Language X is fast because it has a fast webserver!" when the webserver isn't written in Scripting Language X.
(A moment's perusal didn't show me what this particular web server is implemented in. If someone can link me to that web server and show it's implemented in Ruby, I'll be happy to eat my words here. But if the performance is comparable to Go, that's enough evidence it isn't written in Ruby to satisfy me until more evidence comes in. If Ruby isn't a slow language, you've defined "slow language" to the point that no language is slow. There isn't much competition in the "slower than Ruby" field; Perl 6 is pretty much the only entrant I know of. There's a number of languages as slow as Ruby, it is not uniquely slow, but there's almost nothing slower.)
PostgreSQL is obviously not written in ruby, but the other components are very much "ruby code". There appears to be c/Java extension for ssl and parsing http, though - but AFAIK the main server is ruby.
> A hello-world Deno HTTP server does about 25k requests per second with a max latency of 1.3 milliseconds. A comparable Node program does 34k requests per second with a rather erratic max latency between 2 and 300 milliseconds.
> Deno's HTTP server is implemented in TypeScript on top of native TCP sockets. Node's HTTP server is written in C and exposed as high-level bindings to JavaScript. We have resisted the urge to add native HTTP server bindings to Deno, because we want to optimize the TCP socket layer, and more generally the op interface.
Please note that Perl 6 has been renamed to Raku (https://raku.org using the #rakulang tag on social media). Also: not sure how long ago you tried using Perl 6 and found it slow. If your data is from the Parrot days, it is definitely out of date: the MoarVM backend is at least two orders of magnitude faster.
While Raku is generally slower than other languages, there are times when it is is faster than those same languages.
There was even one report of it being faster than C/C++.
(My guess is that the C/C++ code was doing a lot of string copies and/or scanning for a null terminator. The MoarVM backend doesn't generally do either of those things.)
Not sure how "overblown" the performance issue is. I rewrote two commercial Rails apps to Phoenix and had both versions of both apps run side by side for two months. The Phoenix apps consumed 7x-11x less RAM, accomodated 9x-10x more users on identical hosting instance, and had almost 10x quicker response time.
Phoenix is written in Elixir -- another dynamic language.
I am willing to argue with facts but you just added another non-factual opinion to the pile.
...Oh, and a Mario game implementation says nothing about the typical production uses of a language and its stack.
That, plus the fact that most Ruby users don't go for Sinatra and Sequel.
I've seen conflicting benchmarks on this showing different results - possibly has changed over time, or run different comparisons. What you linked seems current at least.
Also keep in mind that as far as performance of dynamic languages goes, all of the P* languages (Perl, Python, PHP, and... Ruby ;)) have been left in the dust by the front-runners (eg Node.js or LuaJIT). Perl used to be king a long time ago, eventually, PHP took pole position, and maybe now it's Ruby's time to shine. But being leader of that particular pack could mean you're nevertheless still 'slow' depending on context.
No, both your post and this reply are dogmatic. As I said, Ruby is the slowest modern dynamic programming language (and it's much slower than Perl). I really wish the Ruby community would listen to valid criticism. All dynamic languages are deeply flawed in some way, especially Ruby, and most ecosystems are open to learning from others.
> All dynamic languages are deeply flawed in some way, especially Ruby
That sounds pretty dogmatic itself. You don't have to like dynamic languages - but that doesn't mean they are deeply flawed. The same could be said for statically typed languages with a different set of values.
People used to think JavaScript was too dynamic to optimize, too. Then people poured time and effort into it and now good JavaScript virtual machines can hold their own against competing implementations for other languages.
We can't forget to consider the cost of productivity gains and developer happiness from using ruby. It can significantly out weigh the cost of some additional hardware.
If it doesn't bring you that, then we have a problem!
> …but all benchmarks show Ruby as slower than compared dynamic languages. The relative speed difference is different per benchmark, but across the board Ruby is slower.
Ruby and Python, for a long time, have been almost identical in laguage benchmarks and Python's lack of speed hasn't stopped it being the most adopted language by some metrics. So this whole speed thing is a red herring.
> Interesting; Shopify doesn't use TruffleRuby, but instead prefers MRI?
Shopify's investing in TruffleRuby as well as MRI - they employ me to work on it. We have it able to run one major app, but still working on making it as fast as we'd like.
Idiotic. That’s what using the right tool for the job is all about. Ruby isn’t for everything and never will be. Just stick to CRuby (or JRuby if integrating with the JVM). They’re already stable. No point diluting the space with more rubies for superficial reasons like lessening the performance trade off in Ruby when there are many many other languages better suited for high performance algorithms to apply where needed. That’s what good engineering is all about after all. Knowing trade-offs and choosing the right tool for the job, not denying them or trying to fight them like TruffleRuby idiotically does. Shopify is like Canada’s Groupon. The only reason they are profiting is because they have a simple business idea despite their mediocre engineering skills.
Not running most Rails applications is true, but the applications that can be run on TruffleRuby are not quite plain. It can run a web application that serves storefront traffic (source at the end of https://engineering.shopify.com/blogs/engineering/optimizing...)
Yes, Ruby is meant to be easy and magical, but it was never meant to be fast. It's fast enough for most things, but you also wouldn't show up to a drag race with a tuned bicycle.
How is it that Python is able to do so many things quickly (even excluding NumPy/SciPy)? Is it more native code libraries? Could Ruby follow this path as effectively?
In general these days, Python "general purpose" code is about as fast/slow as Ruby. And yes, everything that does heavy lifting has native extensions underneath.
Basically, what he found is that for programs that work with large graphs of objects (as opposed to arrays of numbers, which are the domain of numpy and friends), Python isn't all that fast. I don't know how it compares to Ruby though.
I wasn't specifically thinking web frameworks but a number of projects that I found surprising and performant. One example I can recall is Graphite (Whisper, Carbon).
Seriously, if you need high performance out of the box, you should probably just skip Ruby. I love that language to death but most of the time you cannot use of it for a decent scale.
Same for me with Elixir. I love that little thing so much but there are workloads where it objectively shouldn't be used -- for web apps it's definitely one of the best picks out there but that's a different topic.
I've lately been writing several Rust tools and mini apps and have admitted to myself that even if a language stack clicks with you almost perfectly, you should still reach out to other tools when appropriate.
Even us the senior devs forget that, and it pays to get reminded of it every now and then.
...Rewrite in almost anything else and you'll have fast code. :)
It's quite amazing the lengths the companies will go to just to avoid changing their status quo. But for them it makes sense.
---
EDIT: Downvoters, calm down. Ruby on Rails is objectively quite a slow framework and this is proven in many public benchmarks (Techempower included). And Ruby isn't the fastest among the dynamic languages either.
Stuff like this always confuses me. It's like asking how to exercise without sweating. I would think the first sign of performance problems would mean some profiling and some porting of sections to a native language. Instead some companies go down a crazy rabbit hole instead of just making some shared libraries.
I thought the same as you but then I realized that the investment in a tech stack is basically done only once and almost never revisited.
Then people go on all sorts of crazy journeys to justify their investments in pain and burned money.
Even though I get downvoted at places in this thread (and upvoted generously on others), I will never tell to people "you should always just rewrite to Elixir". Meh. If your app works fine, have it be in COBOL or PL/1 if that helps you do your job better.
But as you said, when your app/hosting starts struggling you should start rethinking your choices if all the lower-hanging fruit has been already collected.
In my experience, even in "slow" languages, that type of thing is the predominant source of major performance problems, and the supposedly "slow" language would be perfectly adequate if you an stop shooting yourself in the foot (and if you can't, a faster language will not help you).
I'm sure there are extremely high-performance or high-scale points where language choice starts to matter more, but I'm also not surprised if Shopify is correct not to think they're there yet.