Building GitHub with Ruby on Rails
github.blog
github.blog
It must also be a massive boon for the Rails ecosystem to have such a large property running off the head.
Doesn't anyone know of any Django shops that do the same, running off mainline?
Is rails the same way dependency wise?
django does not use sqlalchemy as its ORM, it has its own system (which i prefer!).
I have tried a lot and the least worst is Zapatos (and it's not really an ORM) because it at least tries to not paper over SQL and instead just creates a type-safe API for using SQL.
Now, if someone could create a Django-like ORM for Java or Rust, then we're talking. Hibernate and Diesel are nowhere near Django's ORM in terms of productivity and "it just works" factor. Go's GORM looks pretty good but haven't tried it. jooq does not look as easy to use or setup, and the workflow is entirely different.
For example you need an external package to use builtin postgresql, mysql or oracledb support. You need tblib to run tests in parallel using the built-in test runner. You need external packages to use argon2 or bcrypt as password hashers in the builtin auth system, and I'm sure there are others, since Django is very much batteries included, but modular.
The modularity also means you can also use any 3rd party database, use pytest to run tests, make your password hashing on your own, ... so I can understand that these are not listed as dependencies on pypi, but I don't really like that I have to list packages I don't directly import in my code as direct dependencies...
The first release of Django was in 2005. Back then, the Python Package Index didn't exist yet. Installing Python dependencies was really hard - you pretty much had to grab a copy of the code for each one and put it on your "sys.path" somehow.
So Django avoided the issue entirely by bundling everything you needed to build a web application in a single package.
That's why Django has "django.contrib" - in a time before pip dependencies, it was a way to separate out things like GeoDjango which weren't exactly part of the "core" framework but could be distributed along with it.
Existing Interface getting removed OR behavior or defaults changing for an already existing Interface.
That's usually the upgrades are about.
It is quite independent. There are between two and four dependencies: asgiref, sqlparse, tzdata on Windows only [0], and typing_extensions on <3.11 [1]. There are some optional dependencies (argon2-cffi, bcrypt, and a database library like psycopg2), but they are small and mostly self-contained.
[0] https://github.com/django/django/blob/main/setup.cfg#L39-L42 [1] https://github.com/django/asgiref/blob/main/setup.cfg#L34-L3...
I consider that a better measure of dependency risk than absolute count, since different ecosystems have different ideas about how large a library should be.
The brand new react docs don't even mention it: https://react.dev/learn/start-a-new-react-project
> We are currently leaning towards Option 5 ("Turn Create React App into a launcher"). The original goal of Create React App was to provide the best way to start a new React web app for the majority of React users. We like that repurposing it as a launcher explicitly communicates a shift in what we think is best for most new web apps, while at the same time leaving an escape hatch for the older workflows. Unlike Option 3, it avoids the perception that "creating a React app" is somehow deprecated. It acknowledges the reality that a bit of choice is needed, but there are now really great options to choose from.
https://github.com/reactjs/react.dev/pull/5487#issuecomment-...
Contrast to the JS ecosystem where as soon as there’s a disagreement or new idea a new framework is born
Every backend lanaguage has one or two really good frameworks. Simply because the cost of replacement is so high and the cost of developing a new one is so high, it just makes sense to invest in the one you're using. Sadly, this means just investing in hiring more people and not in actually improving it which GitHub/Microsoft is doing.
That's more because of our engineering culture. The cost of NOT upgrading outweighs by a huge margin than keeping building on top.
And yes, have seen Django shops locked into 0.9x release patched right into the core and running for a very long time, impossible to upgrade and all the horror stories.
EDIT: Added Django
I can understand the reason to put off encrypting the field too. Upgrades, or backporting, are just work like any other project and I guess that other things for now take preference. After all, before field encryption came along the risk balance calculation had already been done (even if only implicitly) that storing the field unencrypted in the database was safe enough. The availability of encrypted fields doesn't change that, though making some things safer doesn't necessarily fall neatly into the "requirements" bucket despite being a good idea.
It took Github a full eight years to get caught up after that fateful decision in 2010 to hold off on Rails 3.
The cost of not upgrading is always the worst option. It's just that those making the decisions might not have the same stakes. It has nothing to do with technology and happens in every situation.
Often you're just not even aware of what these costs are because you're wired to work around it. It just feels right to continue that workaround including continuing to hire and expand when it reality it's just more overhead.
Consider moving to an SOA. Rather than upgrading a monolith when the engineering team knows that it’ll gradually have pieces pulled out of it, use that effort on the migration.
Sounds like this is a good question to ask companies when you're interviewing, since it probably can act as a proxy for a lot of other engineering habits.
I found framework and runtime "freshness" to be a good metric of company engineering culture.
For example:
- Good test coverage (particularly for critical points of your application) including CI pipeline
- Use dependabot or similar to make sure you get alerts for any critical updates (like security patches)
- Practice good dependency "hygiene" - only add a dependency when you really need it, and do vetting to ensure it's well-supported, has been updated recently, etc.
- Regularly audit and remove dependencies - when a library author declares they are sunsetting their project, plan on a replacement (even if that is, worst case, a fork). Remove dependencies which are no longer used in your code.
- Separate out your development/testing/production dependencies
- Use a good dependency manager: for example in Python, use Poetry or pip-tools or similar, rather than manually updating requirements.txt files yourself
- Update early and often: other than dependabot make it a maintenance task to check for updates at least once a week. Use managers, scripts etc to make this as easy and painless as possible.
Obviously if you are inheriting a legacy project you have to deal with the cards you are dealt, but these are a good target to move towards even with an old codebase.
Nowadays most projects I've seen use the latest stable release or at least the latest LTS - maybe some legacy projects lagging behind.
I would have expected Microsoft to focus on developer efforts into speeding up Ruby as a language given they are one of a small few large companies that have deep language/compiler expertise.
Not in my experience.
I'm new to Ruby, with 13 yoe as a SW engineer.
Personally, I find it a very hard language to master. Writing tests often feels like I'm settings variables left and right without seeing them being used in the current context. But that then happens to be part of the let() way in rspec.
Now you might say: why use rspec? I inherited this codebase, so gotta do what you gotta do.
I do really miss my compiler. I am not a fan of writing a block somewhere that can be invoked 2 weeks later for the first time and then fail, because someone passed in a number where a string was expected.
I went from PHP to Java to C# to F# to JS to Rust. F# and Rust stand out in terms of hardest to write, but easiest to trust.
I don't have that feeling with Ruby, and RoR.
But, again, my personal opinion. Good friend of mine started with Ruby, and he loves it. He says that he accepts the magic things for what they are, and uses them. My brain doesn't allow that. I have to understand.
In terms of the "I wrote a block somewhere and it broke when executed for the first time two weeks later" - don't do that in a scripting language. Use the REPL to build/test the block. That's the trade off - instead of a compiler you get a fast REPL - use it! :)
TS is a bit more flexible and expressive than Sorbet, but I find Sorbet very ergonomic even with strict typing. I rarely have to use T.let or T.must.
Sorbet's typed data structures like T::Struct and T::Enum are also great.
Maybe I’ll check back in 3 years? But it seems to be A pet toy of Shopify, and for their needs.
A lot of stuff uses method_missing and define_method. There’s also instance_eval, which is used to create DSLs like rspec. Once you know what they do, stuff makes a lot more sense.
[5] pry(main)> $ user.first_name
From: /Users/.../.asdf/installs/ruby/2.7.7/lib/ruby/gems/2.7.0/gems/activerecord-
6.0.6/lib/active_record/attribute_methods/read.rb:15:
Owner: User::GeneratedAttributeMethods
Visibility: public
Signature: first_name()
Number of lines: 4
def #{temp_method_name}
name = #{attr_name_expr}
_read_attribute(name) { |n| missing_attribute(n, caller) }
end
Tells me exactly where this "magic" method is defined, and I can pop open that file and read all the source. instance_variable_defined?
defined?
are two common onesbut if you are using something before defining it you are going to crash so that's definitely one way of distinguishing it.
using fetch is another way to provide a default value to something that may have a nil value as a meaningful value.
> but if you are using something before defining it you are going to crash so that's definitely one way of distinguishing it.
Would you clarify? Like that was my point, casually using something where `nil` is a possible assigned value, or maybe the variable hasn't been defined, makes possible the (sadly common) category of bugs where the program does not crash, but proceeds as though the variable was assigned `nil`, but actually the variable was never defined.
In contrast to local variables where the program will crash if you reference the variable but it hasn't been defined.
My comment meant "bare instance variables in Ruby are not great [and we might not want to recommend them as a solution to people complaining about Ruby/Rails quirks]". Do you disagree and actually love the behavior of Ruby instance variables? Or are you simply technically correcting me? (which, again, I appreciate)
yeah I wouldn't say i love it and i'm not sure why they did that but i imagine they had a reason for it originally. i would say it should have crashed instead of return nil as a default. they did tend to try to make the programmer happier and maybe they did it to that end but i don't see a large upside to it... not too much we can do about not using instance variables though... at the end of the day you just have to be a little more careful.
tests are a pretty good thing to have though and can catch this kind of error.
I hear you on the compilers, and I do miss them at least a little whenever I don't have them. But my goodness, there's really something fun in Ruby. I think it shines in smaller codebases, situations where you can have some hope of understanding 90% of everything that's going on as a single developer (and honestly part of the sales pitch of microservices is that you know there's no funny business crossing the wire, so you only need to know the magic bits of the services you work in). But there's really so much joy in stringing together a few functions in a single line, knowing that there might be a few different types being passed around depending on context but knowing that all the functions can handle all the types, and not pausing after every line to check whether an err was nil... Honestly when I have a compiler i miss the magic, and when I have the magic I miss the compiler.
How are you supposed to fix a bug in your own service if you don't know how to set up a specific permutation of services locally in order to reproduce it?
or maybe put it this way: the big-ball-of-mud formed by metaprogramming tricks feels like it has boundaries that are permeable in a particularly arcane way, whereas the big ball of mud formed by microservices has boundaries that are permeable "merely" by distributing or spanning of both humans and logic.
Good metaprogramming levels up a language's power in the same way going from a hammer to a nail gun levels up your building power.
Creating a DSL in ruby is mostly just creating well named class methods, often that take blocks, and calling them without parens. Sprinkle in a little `method_missing` overrides and a few `define_methods` and that's it.
I don't know why people seem to actively avoid learning it, but a day of study, and stepping through a few "magic" methods with a debugger should reveal how simple and non-mysterious it is. And also how useful it is.
Metaprogramming is pretty amazing for gems and DSLs in a limited domain. When I see business logic that has metaprogramming in it, I kinda freak. I know in the future that business logic will change and debugging the very clever code in that business logic may become a nightmare.
I say this a person who adores Ruby.
Problem solved by using Sorbet in your codebase. I know at least Stripe and Shopify do. Also forces you to keep magic at the minimum (which any sane dev would do anyway).
Ofc, you'll shoot yourself in the foot doing that if you let individual test files get to big, but that's a bad idea anyway sooo.
I had a similar experience, and it was a great lesson.
“The real problem is that programmers have spent far too much time worrying about efficiency in the wrong places and at the wrong times; premature optimization is the root of all evil (or at least most of it) in programming.”
You can't patch the kind of performance you need for these products after the fact, it needs to be baked into the architecture.
You execute for today, but make it easier to replace parts on the future
Rails was such a huge part of my professional career.
Now, 13 years later and I'm deep in the JavaScript ecosystem and have been for 8 years.
The most exciting thing to come out of this ecosystem recently is RedwoodJS, because it takes a lot of inspiration from Rails.
It's in a somewhat weird spot: On the one hand it is mature and has amazing DX/UX going for it, with a lot of very thoughtful tooling. On the other, for some reason, it has always remained niche with just a couple of core developers, even though it's now nearing version 6 and at least 8 years of releases. I do not know why that is the case. It's a beautifully written full stack framework, taking having inspiration from both Rails and Laravel and in the world of web TS, it should get a lot more attention than it does.
Maybe it's just the weird name :^)
One thing is picking a library which I can replace if it it gets abandoned, etc. a very different one is picking a full stack framework where replacing it means rewriting everything.
If I wanted a full stack framework, I’d pick Laravel or Rails because they’re already proven, have a big community, are used by big names in the industry and I’m 99.9% sure they’ll still be around and maintained 5 years from now.
Having a community is nice and motivating, but that makes building good software over that many years without ever being the community darling more impressive to me and seems like a great indicator for deep commitment, that gives me a different kind of confidence than hype and VC money.
I am not sure which sustains better in 2023.
But of course Vue is a frontend framework, and maybe the appetite for those was higher (and associated risk was lower) than for a batteries-included JS backend framework like Adonis.
I'm less likely in my career to stray away from whatever the old heads came up with. For instance the new thing is putting server/database calls in server side React components. But something tells me MVC was invented for a reason by people way smarter than me.
But the view layer has not aged well. After years of working with a focus on React and TypeScript, I can't stomach the Rails approach to views. As much as I appreciate the value proposition of Stimulus and truly feel the shortcomings of SPAs deep in my bones, I crave components, type safety, unidirectional data flow, and more options for styling than just classes. React in particular has rich options for UI frameworks that feel truly idiomatic. The last time I tried to start a project with Rails, I moved at a breakneck pace until I got to the view layer, at which point I had to pull the plug.
I'm reaching for Next.js these days because it's the closest I can get. It gives me the opinionated framework I crave plus server rendering and the ability to drop down into client-side rendering when it calls for it. Prisma is a damn good ORM, even if it doesn't have the intuitively ergonomic beauty of ActiveRecord. And of course, TypeScript throughout is a godsend.
But I still miss Rails. I miss the console, Sidekiq, the profound power of ActiveRecord for simple things with the ease of dropping back into SQL when I need it, the polish of FactoryBot and those easy easy easy tests. I miss the breezy and fluid syntax of Ruby. I don't feel limited by TypeScript, I love working with it, but TypeScript lets me lecture, Ruby lets me sing.
Agreed - In my opinion, Rails messaging/soft marketing could be a lot better about how it's great for a data driven backend, whatever the frontend/UI.
I know there's things like API mode and webpacker, but this all seems very secondary and begrudging at times. Maybe I listen too much to what DHH says, but definitely think the Rails view stuff should be what's secondary. It's a turnoff for a lot of devs who would otherwise be quite happy with Rails as a backend.
I pair Next with Nest (sigh, why only one letter different?) when I need a proper backend but I can get so far with Next that I’m using it less and less now.
Any experience with it? What makes it far from perfect?
If someone reading this has experience with both TS+React and modern Hotwire apps, you’d do the world a service by writing a blog about modern Rails views for the experienced React developer.
Also sprinkle some (rare) Stimulus and Turbo streams/frames.
The one thing you're gonna be missing is typing, Sorbet does not work in views.
I still build in Rails. And even thought I tried alternatives I don't think anything is as stable and fast (for me) to create things.
Rails is love
But GitHub is not a great Web app. It is frequently/constantly out of sync with the latest data/status. You quickly develop the habit of manually refreshing the page every time you are preparing to do anything with a PR, and that's not something that should be necessary these days.
It surprises me to see a loud and proud blog post detailing GitHub's process of staying so relentlessly up to date with the latest and greatest version of Rails: the app is not properly responsive, for whatever reason, and to a degree that would not be tolerated where I have worked. I would rather read about how they are trying to fix this issue.
Admittedly, it's been a long time since I looked at Rails code, and I don't have the slightest idea how GitHub is actually architected. But I don't remember the "front end code" in Rails being a separate thing from the server code, typically: the whole point was server-side rendering. Is GitHub using one of the JS/TS frameworks for the front end? I do remember that being a developing trend, a few years back.
Point is, there's nothing about Rails in particular that would prevent fixing these issues, that's probably the result of development and business priorities, legacy code, etc. that would be an issue with any tech stack.
I wonder if Eileen Uchitelle will bring this practice to Shopify as well? Edit: It seems [1] Shopify is also running on latest Ruby and Rails version as well.
?!
There's at least Spring.
It's one of the most common frameworks in the industry across languages.
Web is not CPU bound, it's memory and network bound. Rails can run huge traffic perfectly fine if you know how to code for performance (e.g. caches, async with Kafka etc.) Ruby had also pretty significant speed improvements in the last years.
The tools are there, you just need to understand and use them.
I mean it may be working just fine, but I don't see it - and the success rate of refreshing a page to see an update is so high that it doesn't instill confidence.
These tools should be more reactive, I think, with live progress indicators and the like.
Attributing some UI bugs with their choice of framework is a massive oversimplification of the problem.
Any source for this?
My understanding is that it was extracted for building Hey from the use cases the 37signals people had on other products such as basecamp, etc.
I was saying it came after, meaning GitHub could not have used it since it didn’t exist. :)
That's awesome. Not only fixing it for your team but the entire rails world.
Or breaking it for some.
However, incorporating this methodology into our workflow would be both a lot of work to set up and also a lot of work to keep running.
There certainly is a size threshold under which this is clearly an overkill and we are under that threshold.
Yet, if this could be turned into a product, a clean integration, a command I need to run... would definitely use it (and pay for it).
You should be upgrading all the time since day one, adding necessary infrastructure gradually as your app grows.
Conversely, I was called by a company that I had built an app for previously. They had not upgraded the framework it was built with (Laravel), and ended up offering me consulting days to jump several versions. The irony is that the job ended up being quick and easy to do.
Did you use a tool like Shift to help with the upgrade? What about frontend dependencies? The recent move from Mix to Vite is great, but if you have a large frontend, it can be a major PITA to update. More so if you have any sort of custom webpack configuration.
For example in many organizations partial deployments don't exist and rollback is not easy, so having a "once a quarter we test everything and bump" is less traumatic and expensive than handling minor breakages every week.
You can invest into that infrastructure/maturity but it may not be the best use of your time and money if you don't even know that your company will exist next year.
I think the pattern to consider is: (i) Yes, this would improve our deployment speed/upgrade speed/security posture, possibly by a huge amount. (ii) We have much bigger problems with higher impact.
Like, at work, we could spend a month or so to setup something like dependabot for our private stuff and I'm pretty sure we could get to a point of deploying these dependency updates quickly - or, for less critical systems, automatically even. And it would be cool.
But that won't help us with some of the flagship products in the company that have C++ dependencies on EOL windows components and no automated deployments. We'd rather have the capable guys working on these nasty issues, since these upgrades for the modern products can usually be done by a junior dev in a few days for all of these smaller and well-controlled systems.
It simply has too much magic and doesn't offer enough abilities (unlike Elixir or any Scheme variant) to justify the dynamic type nature.
Go and Rust are perfect for me (and maybe Zig?). They covered everything I need.
I'd love to see their Gemfile.
I would bet it's present in GHE's OVA (https://enterprise.github.com/releases/3.8.1/download)
Being able to built publish ready things, alone, within only weeks instead of months is a total life changer if you like building things
Unfortunately I’m fairly certain the message that will be heard is ‘We should totally change something around on the customer every week, that’s what GitHub does’
I really like the sentiment of this quote but that is an easy thing to say for a behemoth like GitHub.
I find these blog posts from google, meta, aws etc super awesome since they run and solve problems smaller companies simply don’t have. And they shape how smaller companies solve similar issue at smaller scale. But doing a setup to be practically on bleeding edge rails for example is not something every company can afford. They need LTS releases and the sorts. Still awesome that they managed to achieve this.
I cannot agree with the "Should I do it too?" section. It probably works very well for an org as large and dedicated as Github, it very likely makes a lot of sense for what they do at the scale they do it at.
For most of us that are consumers of technologies and frameworks, treating the framework as an extension of an application stack, as the blog has outlined, is a terrible idea; it requires devoting time and effort towards its upkeep, and that is not our core business, nor should it be.
That does not, however, mean it's being treated as an unimportant part of the application stack, and implying so is judgmental. It's importance is that you need to be careful about the tech choices you make and understand what the implications will be down the line.
I would try to argue that this in fact may be subjective.
For me, updating all the dependencies in my stack every morning is a productivity routine that gets me started. If I spend a 30 minutes studying changelog of a dependency and linked github issues, I don't see that time as wasted even though it often does not contribute to the business. I think it has three benefits.
- easy morning start routine to get going
- developer education, expanding horizons
- code climate; having warn feeling in the gut of not falling behind, wanting to avoid dirty plugs and monkey patches, ability to work on the HEAD, should an issue arise.
My team currently does something similar albeit with a smaller framework (we are also much smaller than GH!), and it has done wonders for the stability of our flagship app. Imo it's only a terrible idea if your company does not want you to do it.
I'm curious as to why you would disagree with what Adam Hess writes about handling updates though. To me he respectfully outlines that GitHub has engineering capabilities that allow them to update their Ruby on Rails weekly, and that it's a good idea to do so, if you can. I can follow you as far as how the application stack isn't the core business in the sort of organisations you and I seem to work for, and weekly updates likely shouldn't be your goal, but I do think that you should allocate the resources needed to keep things relatively up-to-date.
I'll give you an example of how I don't follow my own advice. We have what has developed into an important asset management system that we build in-house, which due to a lack of updates being prioritized now cannot be build on the LTS version of it's core tech. This isn't a major problem today, because it's on an internal system on a virtual network which is heavily protected, but it's also gotten to the point where it will likely need one or two people to work full time for a week to a month to get it updated. Doing that might actually be cheaper than having kept it sort of up-to-date, maybe with quarterly or even yearly updates, but if we couldn't get those prioritized, how do you think we're going to get a week-month for updates prioritized? :p
Or maybe the organization is just uninformed of the issues. Most management of organizations lack a view into 80% of the issues at hand.
> some people will think this is silly
It's sad rather than silly.
Like when I go to a supermarket and can't checkout because the terminals are down... right it's not a core part of the business and just a cost center. So I decide to order online and their checkout form goes into an infinite loop and I give up... they've lost customers.
And that's problem. Tech is an integral part of most businesses now. Chances are if there's an outage you'll lose customers. It's a core part of your business - possibly 1 of the most important.
Often the #1 reason why something can't be done is that the tech behind it doesn't support it.
I have to imagine this leads to either GitHub being the defacto lead maintainers for those gems, or GitHub removing gems from their stack and writing their own code.
But generally, I've worked with hundreds of devs in the same code base without issue. So, why do people ask this?
A Rails engine is basically a self contained Rails app, including routes, which you can mount inside of a host Rails app at any route if your choosing. They're usually used to build reusable libraries, but this use case also works very well.
* Parallel builds/CI to look into the near future: current + next. When time is due current and next need to become green and the next alpha becomes future, which is allowed to fail (3 parallel tracks: current, next and future). Keeps all your build tools en par early, too, so there is less rot, and one team can concentrate on the migration while other teams aren't interrupted by that, but also for a single or only a handful of developers, you can have better change management (at the cost of the extra computing power).
* It feels less a monolith, if its in a dynamic language (not compiled / transpilled / linked) and in many files (there is little to build and deployments are smaller and faster). In such projects, increments are possible across multiple axis in a synchronized dance.
* Pipeline everything and continuously shift left. Identify the most important improvements and if they can step-break the process well, apply the earliest one coming from the developer perspective. Any such change will speed up any change after that step.
* Implement fast turn-around with the parts that change often so you can change them often well. Cooperate well with upstream, this is most often a key to ongoing success.
* Distributing traffic over multiple application servers and being able to deploy different configurations / revisions and directing part of the traffic to it is invaluable. Have your tools/systems configured well to make it easy and comfortable to do this way. Production must not feel like an all or nothing game any longer, but serves as experimental playground.
And as the article highlights, perhaps the key reason for smooth deployments and upgrades is that the CI testing story is so, so good: RSpec [1] plus Capybara [2] for us. That means we have decently extensive tests of just about all behavior. The few small Rails and Ruby upgrades we've done have gone quite smoothly and confidently, with usually just a few non-Rails gem dependencies needing to be manually updated as well.
The "microservices" story is where we've pulled in the Crystal programming language [3] to great effect. After dabbling with Go and Rust, we've found that Crystal is truly a breath of fresh air. Crystal powers the parts of Heii On-Call that need to be fast and low-RAM, specifically the inbound API https://api.heiioncall.com/ and the outbound HTTP(S) prober background processes. I've ported some shared utility classes from Ruby to Crystal almost completely by just copy-and-pasting ___.rb to ___.cr; porting the tests for those classes was far more onerous than porting the class code itself. (Perhaps another point of evidence toward the superiority of RoR's testing story...)
The front-end story is nice but just a bit weaker. Using Hotwire / Turbo successfully, but I have an open PR to fix a fairly obvious stale cache bug in Turbo [4] that has been sitting unloved for nearly a month, despite other users reporting the same issue. I'm hopeful that it will get merged in the next release, but definitely less active than the backend side.
For me, the key conclusion is that the excellent Ruby on Rails testing story is what enables everything to go a lot more smoothly and have such a strong foundation. I'd be curious if any GitHubbers can talk more about whether they too are using Rspec+Capybara or something else? Are there internal guidelines for test coverage?
Crystal looks great, are you using it mainly for type checking? If so why not Sorbet?
(1) the API server at https://api.heiioncall.com/ which gets hit frequently for check-ins, e.g. cron job monitoring
(2) the outbound probe processes that do website monitoring, polling your desired URL every minute and making sure it's up!
You should also read about Github's history with "Rails" and how challenging it was for them to make it fast enough for them and upgrade it. It's pretty interesting they got around that "challenge" by throwing a LOT more resources at it. It's interesting because this isn't usually a challenge with other major framework upgrades. It makes sense you would need this much investment given the hyper-dynamic dangers of Ruby (not just the language, but the ecosystem), making it difficult and risky to upgrade.
TL;DR the advice in this blog post does not seem applicable to most companies.
There's a ton of merit to being on the latest release or close to it so you can get the latest security patches easier. The diff between that and the latest `main` branch seems like it has diminishing returns for most orgs.
get it on Ruby 3.1 if you can - https://railslts.com
Also, are you at least a little concerned about your career using a tech stack that old?
Fantastic that GitHub has managed to wrangle so many lines of code in a language I don't care very much for, but my Samsung A53's browser is snappier without it :)
Edit: to be fair, GitHub's has a hamburger menu that morphs to an X that I dearly miss. JK :P
Ex-Hubber
Like, a lot of times I see some baz.foobarify() I have really hard time understanding where the heck that comes from. RubyMine makes wonders and control-clicking gets me there about half of time, but the rest of it it's either "search in all files, hoping that `def foobarify` is unique enough" or "this is crazy, but I'm gonna set a breakpoint, run it and see where this rabbit hole goes".
It feels kinda like Scala (or, to lesser degree, Haskell) magic operators problem, but worse.
I consider myself proficient with a decent number of languages and frameworks, but Ruby/Rails is one arcane mystery that just never clicked. So I really wonder what's the trick to make metaprogramming shenanigans manageable at this scale?
foo.method(:bar).source_location
That is wildly useful when debugging/figuring out where the actual code for some method is at runtime.That’s a bold move to do as opposed to being end of week or weekend.
I think Monday requires more maturity and more successes as it prioritizes dev time over downtime. Saturday outages affect fewer customers but are hard on staff.
..sounds like they're not dogfooding dependabot? curious if anybody knows more/why
So uploading code to a github repo makes github server execute it later on. I wonder if this would qualify for a bug bounty... /s
Edit: I guess not, since this is just a pull request and still requires approval before merging to main. I assume.
First, it opens a Pull Request, not an automatic merge, so hopefully the code is reviewed before merge.
To exploit this, you would first need to get malicious code merged into rails master which has many eyes, and then get passed more eyes when it gets reviewed by GitHub.
Not impossible, but if you got your code merged into rails master, you have wiggled your way into many more environments than just GitHub.
We can assume that only trusted maintainers can put code into the Ruby main branch. Similarly, every build system depends on many many signed packages. It is not much different than that.
Change is somewhat inevitable though
And those changes are the reason rails is still really good, modern, and not considered legacy software almost 20 years later
And people definitly chose ruby because it was cool. So what you said should be applied to Ruby, not Go.
https://www.fastruby.io/blog/assets/images/RRBPerfHistory_72...
Then in 3.2, ruby released YJIT which improved median rails response time by about 100%
https://raw.githubusercontent.com/easydatawarehousing/ruby_m...
It's kind of a golden era for rubyists that stuck it out. Beautiful maintainable code that hits C performance for many tasks.
Really?
https://tomaszs2.medium.com/ruby-3-2-0-is-from-another-dimen...
here are some benchmarks from 2019 (ruby 2.5) related to string and regex operations. already certain operations were faster in ruby than C or go, particularly on longer strings.