Shopify invests in research for Ruby at scale
shopify.engineering
shopify.engineering
* Rust - I do not understand the borrow checker at all and I'm a senior engineer at FAANG. I can barely write a simple function in Rust. I've struggled more learning Rust than any language (and I can write C and C++ just fine!)
* Go - I like Go, but there is a ton of boilerplate involved with writing it. Ruby is far more concise and you can get straight to business logic.
* Java - Even more boilerplate
* C/C++ - I think Ruby clearly wins on productivity here
Gitlab's history with $faster_language has at least some background documentation, e.g. https://about.gitlab.com/blog/2016/04/12/a-brief-history-of-....
They seemed to have liked it, as at least a couple of other services are written in $faster_language - gitlab-shell and gitaly (probably, several others).
There may be more static languages nowadays, but they're very young - I think in real world, there wasn't, pragmatically, a lot of choice, although today's young languages are... still young :)
It doesn't mean a project is doomed simply because it chose Go. That said, Heroku tried to do a major Go rewrite of their entire backend and the project failed miserably.
var lst = users.stream()
.filter(User::isAdmin)
.map(u -> u.id() + “ : “ + u.name())
.limit(10)
.toList();
static boolean isPrime(int n) {
return switch (n) {
case 0, 1 -> false,
default -> !IntStream.range(2, n).anyMatch(i -> n % i == 0)
}
}I came away liking C++ more than I thought I would. I didn't find it hard to learn but it was time consuming. Where learning Rust I never understood the basic concepts enough to be productive, I could be productive pretty quick with C++.
The trouble is there is a lot to learn because the language is just so old and has been through so many revisions. To some extent you can't just limit yourself to the modern stuff since in order to learn the modern stuff you need a basic understanding of what it was before to know why things are done the way they are now. You also run into code samples that use the old stuff or corner cases where they're needed.
I also think it really gets you to think about how computation and memory is happening at the metal level which is great for optimization but I think for most of the work I do it would be largely a distraction. I see this is a downside, not an upside.
That said, you're definitely right. You can have nice, expressive code in C++: I just think the learning curve is the biggest problem. I'd be happy to use C++ in my next project though.
I should spend some time actually learning modern Java and less time avoiding it.
func IsPrime(n int64) bool {
return big.NewInt(n).ProbablyPrime(0)
}
Each language has its own pros and cons. Go wants to be explicit and simple to be understood. Java is fully-featured.This is just anectodal evidence anyways. And these are tools in the and, and no point for a "tool fight".
new BigInteger(n).isProbablyPrime(0);(Specifically cases where you want the project easy to jump into with almost no toolchain setup.)
The fact that "Ruby developers already basically know the Crystal syntax" is a selling point for Crystal, but if people are already evaluating a switch to another programming language, that's just one of many factors that must be considered.
People use Ruby because they like the way it works, not because of the syntax.
It's definitely lacking in the web ecosystem department but the language is a joy to use and incredibly fast.
I think people focus on the superficial similarity of Crystal, without thinking what semantics need to be the same for it to use usefully similar. And those semantics aren't there, so it doesn't matter if it sorts of looks the same and includes most methods.
I feel like if it was tractable to run Rails on Crystal then someone would have done that.
Last I heard (which was years ago) it was pretty much a solo project.
That said, the demo is really something and I like what they're doing. I hope one day it becomes my language of choice.
I don't think it's necessarily the wrong decision but you have to decide if it's right for your project.
Most C# apps I've worked on in the last 5 years are deployed to Kubernetes.
- EFCore is MSSQL first, even if other options are provided
- Many libraries ship with two implementations: an over-engineered Windowsy version that barely works (with a big scary warning that it should never be used in production), and a thin wrapper around some Azure service
- Important tooling like the debugger (which wouldn't be so necessary if .NET had halfway decent support for printf debugging, but here we are...) is locked to be compatible with VS and (MS' build of) VSCode, despite both of them using supposedly open (and Microsoft-pushed!) standards like DAP
- The community is really culty, the response to "X is broken when using the non-MS-Stack alternative" always seems to be "well use the standard MS solution then"
- It's practically open source in name only, because the build engineering is so convoluted that it's nearly impossible to find the canonical source code of core features like the standard libraries
- "Many libraries ship with two implementations..." I've yet to come across these "many" libraries in the 5 years since I've been building services with .NET Core.
"The community is really culty" - I'm not sure where this is coming from. It's hard to refute such vague criticisms.
- "It's practically open source in name only" - Here is the base class library source: https://github.com/dotnet/runtime/tree/main/src/libraries or https://github.com/dotnet/corefx/releases (depending on what version you're looking for)
1. https://docs.microsoft.com/en-us/ef/core/get-started/overvie...
Maybe our definitions of open source are different, or maybe you're just shitting on Microsoft for your own reasons. Regardless of whatever your experiences have been with .NET in the past, they don't mirror the majority of the folks that use it everyday.
Graphical tooling to deal with process dumps, etw data, and profiler information only available on VS.
What projects? None of those are forced on you or have any references to them built into .NET Core. I've been building .NET apps since 1.0 reached beta (in 2001?) I can count on one hand how many times in total that I've worked with those systems. This argument is a hell of a reach.
> GUI frameworks out of Redmond The upcoming Microsoft MAUI is cross-platform (no, Microsoft isn't building support for Linux, but there are open source efforts working on it.)
You can use https://avaloniaui.net or https://platform.uno
> Graphical tooling to deal with process dumps, etw data, and profiler information only available on VS.
https://www.hanselman.com/blog/dotnettrace-for-net-core-trac...
There's also https://github.com/SachiraChin/dotnet-monitor-ui
You can use JetBrains rider to profile in Linux/MacOS as well: https://www.jetbrains.com/help/rider/Profiling_Applications....
If you don't want to use .NET, you obviously don't have to.
Ruby is faster to write and more concise by a long shot—certainly if we're talking back-end web services. I prefer Go to Ruby generally but it's weird that Go developers tend not to even see how much yak shaving is involved with it. Or really any downside with it.
Try writing this in Go:
records = User.limit(10)
records.select { |user| user.is_admin? }.map{|user| "#{user.id} : #{user.name}"} records := Stream.Limit(User, 10)
records.Select(func(user User) bool {return user.IsAdmin()}).Map{func(user User) string { return fmt.Sprintf("%d %s", user.id, user.name) }
Yes a bit more verbose, that is the price to pay for static typing without full type inference as in the ML language family.https://go.googlesource.com/proposal/+/master/design/go2draf...
records.collect({case u if u.isAdmin => s”${u.id} ${u.name}”}).take(10) guess the language
That line of code could be Scala, or something else.
In any case, the point is that there are compiled languages that offer similar productivity like Ruby, with AOT/JIT compilers out of the box, and great IDE experiences.
In Go, the intuitive way would be one loop with an if inside it. So it would be easy to spot this performance issue if you did it the ruby way with two loops.
https://go.dev/play/p/ixDKuosxPNp
I bet I wrote my for loop as quickly as you wrote your map. The character count isn't that much higher.
The more important thing is the ruby version is chainable and more readable—and that matters far more often.
> more readable
Without having more context, User in your code is possibly an ActiveRecord class, so to read the #select, you have to consider that it could be radically different and heavier than Enumerable#select (eg. it may execute a DB query as a side effect). So I like your example still, because it’s representative, and certainly expressive, but not readable per se. IMO this sin here is simply that ActiveRecord shouldn’t have overloaded select.
Using an ORM was a poor choice on my part. I agree the magic there does harm readability since it makes it a lot harder to understand what it really is doing.
In fact given that only a subset of users will be admin users for the second loop n is going to < 10 anyway.
I believe it was Rob Pike that actually said something along the lines of not bothering to optimise until you know that n is large[2].
If Ruby is "so productive", that's a quantifiable measurement, no?
What were the options in 2006 for languages with both a fast runtime and reasonable DX? I honestly can't think of any. Ruby at the time was pretty far ahead on DX for mainstream and up and coming languages. It was known to be slow but DX for Java was really not great and mired in "enterprise" features and mindset.
Edit: python was of course around and I don't remember the Django timeline well enough to say if it was viable in 2006 or not. PHP was of course around but again there was a mindset issue at the time.
But if you prefer 500 devs instead you should consider ruby, python or PHP. Middle managers are getting high on these numbers.
more expressive languages including common lisp certainly give more power for an experienced engineer to outperform someone fresh out of univeristy. enough to say that I'd rather have 2-3 senior engineers experienced with common lisp or clojure or haskell over 10-15 juniors working on go or python.
and what if you gave them the same expressive language? I'd argue that its even more dangerous. Common lisp is a powerful language but its easy to code yorself into a corner if you don't have the experience to properly use it. it;d be easy to build overcomplicated systems that are brittle. go is in fact better for them because it limits the damage they can cause.
I agree that the hiring pool is small but if you want go level performance, metaprogramming and developer productivity, common lisp was your best option.
Shopify went with ruby. not a terrible language but it did come at teh cost of performance.
The answer to this will lead to what actually matters in a language, in terms of building a product. Raw performance isn't it.
Runtime performance is great and very much welcome if you can get it for free but for a ton of web apps it's not a major selling point on its own.
If I can write 30-100% less code and be able to Google almost every single problem I encounter and find tons of high quality blog posts, documentation and videos along with having decently maintained third party libraries for common features then this is going to win every time in my book against something that doesn't have this. It doesn't matter if your web app uses 100mb of memory instead of 1gb or can serve 300 requests per second instead of 30. Most apps never come remotely near the point where this level of performance matters and Rails makes it easy enough to cache things where you can get your p95+ responses responding in 50-100ms or less without much effort.
Basically Rails sets you up where a solo dev or small team can run an entire SAAS app on a single $20-40 / month server and have tens of thousands of paying customers without really having to think much about performance. Combine this with Hotwire and you can build really nice feeling sites very quickly if you're the type of person who doesn't want to build APIs + JS front-ends.
On the other side of the spectrum with Shopify, GitHub and Basecamp you have engineers running Rails at massive scale making the framework better for everyone (themselves included). It's a self-fulfilling prophecy and win / win scenario because the more people that use it contribute back to the project (patches, community related things, etc.).
At this point the only things that matter are fast how you can build your app and how happy are you building / maintaining it. As Ruby, Rails and compute resources get faster then frameworks who focus mainly on performance become less appealing over time for a huge class of web apps because once you reach "good enough" performance it's all about the community and mass adoption. It's like a company who pops up and tries to copy another company but adds 1 small feature to differentiate themselves. As soon as the company you copied decides to add that feature you're going to be climbing way up hill to barely survive.
Except at least BASIC had compilers available, and Darthmound BASIC was originally designed with what we call JIT nowadays, even if that wasn't a thing on 8 bit home computers.
Pythons community in the ML space is pretty incredible. Trying to recreate all the libraries in another language is no small task, then you also have the issue that Data Scientists don’t want to write in complex languages.
In events like this, improving the language can start to look like the best option.
I work professionally in Golang now and I appreciate so many things about it, but when I go back to get something done for a personal project in Python, it is scary how much faster I can move.
Pydantic, FastAPI, SQLAlchemy, Alembic, requests, attrs, click... it's going to be a long time before other languages can hope to provide libraries with developer experiences that even come close.
tooling can be built with money and money is usually not the issue for these companies.
It also doesn't need to be microservices madness - see GitLab (and also GitHub, but I think they don't open source their internal services), which rewrote some parts in Go.
And if we take into account Ruby's predecessors, Smalltalk, SELF, Dylan.
Smalltalk had multiple commercial implementations and was used to build mission critical software in banks and utility companies and manufacturing companies and…
Smalltalk still has commercial implementations, like Cincom.
One of my favorite quotes
> I think that it's extraordinarily important that we in computer science keep fun in computing. When it started out, it was an awful lot of fun. Of course, the paying customers got shafted every now and then, and after a while we began to take their complaints seriously. We began to feel as if we really were responsible for the successful, error-free perfect use of these machines. I don't think we are. I think we're responsible for stretching them, setting them off in new directions, and keeping fun in the house. I hope the field of computer science never loses its sense of fun. Above all, I hope we don't become missionaries. Don't feel as if you're Bible salesmen. The world has too many of those already. What you know about computing other people will learn. Don't feel as if the key to successful computing is only in your hands. What's in your hands, I think and hope, is intelligence: the ability to see the machine as more than when you were first led up to it, that you can make it more. Alan J. Perlis
Also, language speed alone isn't a deciding factor if your bottlenecks are elsewhere: network latency, i/o etc.
Having a "fast" language, for many projects, is something you worry about only after achieve some kind of success, and that success is made more achievable by having good developer tools.
With dynamic, interpreted languages that have effectively zero compile-time, one can achieve significantly tighter iteration cycles across a team, ending up limited more by test suite runtime than by slow edit/recompile cycles. This leads to higher productivity across an engineering organization with a quickly evolving codebase. Not important for all use cases, but pretty critical for many.
I don’t know what machines do people develop on, but on a fairly old laptop I get practically instantaneous iteration with incremental compiles with Rust, which is one of the slowest compiling languages. I honestly can’t imagine where is this supposed slow compiles in case of something like Java - like sure one can create some monstrosity of a build definition, but if some competent person wrote it it is just as fast as an interpreted language. Hell, it can do hot swapping just fine.
Both of those are comparable to C and compiled. Rust is a bit lower level, Golang a bit closer to C++.
Go is the odd one in the list, you might as well say that one should write an external function in Java and call that from Ruby (which would be fair if Ruby would already run on the JVM, e.g. in case of TruffleRuby).
Go has nothing at all to do with C++, C++ is a low level language, and an expressive one at that. Go is neither of those, it is managed and not good at expressiveness (by design).
There's no need to wait for TruffleRuby (unless you want to).
Ruby is great for developers of all skill to learn and be productive.
Rust is fast as the devil but you have to be a damn good coder to learn it. Even then I doubt you can be as productive managing memory all the damn time. It's a low-level language great at low-level things.
Ruby is a great option for Shopify. Rust is a great option for Firefox's Servo (though that project failed so maybe not).
Was it also nike and paypal? I remember it being walmart and some others that were big champions of node in the beginning.
really? I thought it was Joyent? Would love a source on this.
But Ruby?
EDIT: I posit the last question as well..a real question. In another words, I guess we'll find out how this goes! I don't know what the "right" answer is. I'm more interested in the trade offs they evaluated on this front, or if its such that 500K is just a "hail mary see what happens" situation
It seems like they like ruby and appreciate what it allows them to do. There's no particular reason to think that the strengths they value in ruby will be present in those or any other languages either. They mentioned metaprogramming for example and it truly does feel easy and powerful in ruby in a way that I've only felt in certain lisps otherwise. Presumably they're heavily invested in certain techniques and powers, have earned and maintain internal expertise in them and find them valuable.
Moving the critical functionality into a language where they'd be giving up that hard-earned expertise is a bold move. It may be the standard move, but imo it's pretty radical and a fairly significant gamble. If you're pushing the limits of a language that otherwise works very well for you, expanding those limits does seem wise, even the conservative choice.
It also makes it hard for tools to reason about what is being run as well when you have stuff running in `instance_eval` contexts and `method_missing` being abused. So now here we are trying to unravel that by trying to make the interpreter smarter with caching to improve performance but if I had to turn back time, I would reverse every instance where one tried to be clever with metaprogramming in the name of syntax.
Anyway it doesn't matter. The point was that they presumably have identified certain things ruby does well for them and have invested heavily in them. If ruby does other things less well then abandoning ship for an unknown set of tradeoffs is a riskier move than improving the specific weaknesses that are their obstacles.
What ruby's inherent strengths are or even if they exist at all doesn't matter as much as their investment and expertise in them does.
Many times it is the different semantics that allow for better performance.
If you can add new methods or change their implementation at runtime, performance optimizations get a lot trickier, for example.
The immutability that's foundational to Elixir and Erlang enable the incredible scaling capabilities of the Erlang VM.
This. If you want at least one order of magnitude of scaling to come "for free" (note: further orders of magnitude may still cost you), the BEAM VM will hook you up thanks to this fundamental design decision
This particular example is a non-issue though - it's completely solved through dynamic deoptimisation (as in the machine code with and without method redefinition is exactly the same.)
It's actually much more than 500K. I think they have at least 6 very senior devs working on it¹. I think 3 million $ per year is a very conservative estimation.
That said, it's definitely very mysterious what their analysis was.
¹=https://shopify.engineering/porting-yjit-ruby-compiler-to-ru...
It would be far costlier to rebuild infrastructre, train and shape a culture around another technology stack in an already monoculture company like Shopify.
Shaped objects (aka Self's maps or JavaScript hidden classes) are an old idea, but they seem to have been only recently rediscovered, and the basic idea suddenly allows a lot of other potential optimizations (where research would be helpful). We don't know if they'd really improve Ruby performance, but I think it's very likely & I suspect they'd also enable future improvements.
(for further detail, see this comment and its parent: https://news.ycombinator.com/item?id=31402949)
I haven’t paid much attention but the “optimize ruby” posts seemed to be much more common 5-10 years ago.
Makes me wonder if devs just moved to node/python in the meantime?
Plus I was just trying to be nice!
So lesson learned - important interview needs to be in an empty house. I don't have a great solution for the cat problem.
Anyway I usually don't take interview failure that hard but this one was painful because my performance was so embarrassing and I cared about the job. Probably my poor performance was in direct proportion to how excited I was about the opportunity - too bad.
(Definitely let the cat in! Every zoom meeting I am in has at least one cat, and it is a welcome distraction compared to all of the crying babies and other nonsense)
can we call this optimized ruby compiler "reggaton"
All jokes aside, they should get in contact with teh guys at gemstone software. I remember there was work on a highly optimized ruby vm called "maglev". I wonder whatever happened to that.