DHH · 2025-07-12 · transcript-lex-474-2025 · source ↗
Rails manifesto: Principles of a great programming language
`1:59:40`
We forget why Chesterton's Fence is there. We just go like, why is that fence there? Let's yank it out. Oh, it was to keep the wolves out. Now we're all dead, oops. So I wanted to write these things down. And if we just take them quick one by one, you talked about optimizing for programmer happiness. I put that at number one in homage of Matz, and that's a lot about accepting that there is occasionally a trade off between writing beautiful code and other things we want out of systems. There could be a runtime trade off, there can be a performance trade off, but we're gonna do it nonetheless. We're also going to allow ambiguity in a way that many programmers, by default, are uncomfortable with. I give the example actually here of in the interactive Ruby shell where you can play with the language or even interact with your domain model. You can quit it in two ways, at least that I found. You can write exit. Boom, you're out of the program. You can write quit. Boom, you're out of the program. They do the same thing. We just wrote both exit
`2:00:40`
or the people who built that wrote both exit and quit because they knew humans were likely to pick one or the other. Python is the perfect contrast to this. In the Python interactive protocol, if you write exit, it won't exit. It'll give you a lesson. It'll basically tell you to read the fucking manual. It says use exit parentheses or Ctrl-D i.e. end of file to exit. I'm like, one is very human and another is very engineer. And I mean that both of them in the best possible way. Python is pedantic. Python is the value from the start stated is that there should be preferably one and only one way to do a certain thing. Ruby is the complete opposite. No, we want the full expression that fits different human brains, such that it seems like the language is guessing just what they want. — And part of that is also described the principle of least surprise,
`2:01:41`
which is a difficult thing to engineer into a language because you have to kind of, it's a subjective thing. — Which is why you can't do it in one way, which is why I used the example of both exit and quit. The principle of least surprise for some people would be like, "Oh, exit. That's how I get out of the prompt." For other people it'd be quit. Why don't we just do both? — Okay, so what's the convention over configuration? That's a big one. — That's a big one. That's a huge one. And it was born out of a frustration I had in the early days with especially Java frameworks where when you were setting up a web application framework for Java back in the day, it was not uncommon to literally write hundreds if not thousands of lines of XML configuration files. Oh, I need this. I want the database to use the foreign keys as post_id. No, no, no, I wanted as post capital ID. Oh, no, no, no, you have to do it capital PID. There are all these ways where you can configure how foreign relation keys should work in a database and none of them matter.
`2:02:43`
We just need to pick one, and then that's fine. And if we pick one and we can depend on it, it becomes a convention. And if it's a convention, we don't have to configure it. And if we don't have to configure it, you can get started with you actually care about much quicker. So convention over configuration is essentially to take that idea that the system should come preassembled. I'm not just handing you a box of fucking Legos and asking you to build the Millennium Falcon. I'm giving you a finished toy. You can edit, you can change it, it's still build out a Legos. You can still take some pieces off and put in some other pieces, but I'm giving you the final product. And this cuts against the grain of what most programmers love. They love a box of Legos. They love to put everything together from scratch. They love to make all these detailed little decisions that just don't matter at all. And I want to elevate that up so that hey, I'm not trying to take the decisions away from you. I just want you to focus on decisions that actually matter that you truly care about. No one cares about whether it's post_id or post ID or PID. — Yeah, great defaults. — Yes. — It's just a wonderful thing.
`2:03:45`
You have all these aspirations, they're gonna do some kind of custom, most beautiful Legos castle that nobody's ever built from these pieces. But in reality to be productive in most situations, you just need to build the basic thing. And then on top of that is where your creativity comes. — Absolutely, and I think this is one of those, part of the doctrine that a lot of programmers who get to use Ruby on Rails begrudgingly will acknowledge it's a nice thing, even if they don't really like it. Like it's hard to beat the sort of attraction to building with Legos from scratch out of programmers. That's just what we like. This is why we're programmers in the first place because we'd like to put these little pieces together, but we can direct that instinct towards a more productive end of the stack. — Okay, what are some of the other ones? — The menu is omakase. It actually comes out of the same principle that great defaults really matter. If you look at everything that's wrong with the JavaScript ecosystem right now, for example, it is that no one is in charge of the menu.
`2:04:49`
There are a billion different dishes and you can configure just your tailored specific configuration of it, but no one done the work to make sure it all fits together. So you have all these unique problems in the JavaScript ecosystem, for example, there's probably 25 major ways of just doing the controller layer. And then as many of how to talk to the database. So you get this permutation of n times n times n of no one is using the same thing. And if they are using the same thing, they're only using the same thing for about five minutes. So we have no retained wisdom. We build up no durable skills. Rails goes the complete opposite way of saying, do you know what? Rails is not just a white framework. It's a complete attempt at solving the web problem. It's a complete attempt at solving everything you need to build a great web application. And every piece of that puzzle should ideally be in the box pre-configured, preassembled. If you want to change some of those pieces later,
`2:05:50`
that's wonderful. But on day one you'll get a full menu designed by a chef who really cared about every piece of ingredient and you're gonna enjoy it. And that's again, one of those things where many programmers think like I know better. And they do in some hyper local sense of it. Every programmer knows better. This is what Ruby is built on. That every programmer knows better in their specific situation. Maybe they can do something dangerous. Maybe they think they know better and then they blow their foot off and then they truly will know better because they've blown their foot off once and won't do it again. But the the menu of omakase is that. — So you in general see the value in the in the monolith? — Yes, the integrated system. — Integrated. — That someone thought of the whole problem. This is one of the reasons why I've been on a crusade against microservices since the term was coined. Microservices was born out of essentially a good idea. What do you do at Netflix scale when you have thousands of engineers working
`2:06:51`
on millions of lines of code? No one can keep that entire system in their head at one time. You have to break it down. Microservices can be a reasonable way to do that. When you're at Netflix scale, when you apply that pattern to a team of 20 programmers working on a code base of half a million lines of code, you're an idiot. You just don't need to turn method invocations into network calls. It is the first rule of distributed programming. Do not distribute your programming. It is makes everything harder. All the failure conditions you have to consider as a programmer just becomes infinitely harder when there's a network cable involved. So I hate the idea of premature decomposition and microservices is exactly that. The monolith says. Let's try to focus on building a whole system that a single human can actually understand and push that paradigm as far as possible by compressing all the concepts such that more of it will fit into memory of a single operating human. And then we can have a system where I can actually understand all the Basecamp.
`2:07:53`
I can actually understand all of HEY. Both of those systems are just over a hundred thousand lines of code. I've seen people do this that maybe twice, maybe three times that scale and then it starts breaking down. Once you get north of certainly half a million lines of code, no individual human can do it and that's when you get into maybe some degree of microservices can make sense. — Basecamp and HEY are both a hundred thousand? — A hundred thousand lines of code thereabouts. — Wow, it's small. — It is. Considering the fact that Basecamp I think has something like 420 screens, different ways and configurations. — Ah, do you include the front end in that? — No, that's the Ruby code. Well, it's front end in the sense that some of that Ruby codes. It's beneficial to the front, but it's not JavaScript for example. Now the other thing we might talk about later is we write very little JavaScript actually for all of our applications. HEY, which is a Gmail competitor. Gmail ships I think 28 megabytes of uncompressed JavaScript. If you compress it, I think it's about six megabytes, 28 megabytes. Think about how many lines of code that is. When HEY launched, we shipped 40 kilobytes. It's trying to solve the same problem.
`2:08:55`
You can solve the email client problem with either 28 megabytes of uncompressed JavaScript or with 40 kilobytes if you do things differently. But that comes through the same problem essentially. This is why I have fiercely fought splitting front end and back end apart. That, in my opinion, this was one of the great crimes against web development. That we are still atoning for. That we separated and divided what was and should be a unified problem solving mechanism. When you are working both on front end and back end, you understand the whole system. And you're not going to get into these camps that decompose and eventually you end up with like GraphQL. — Okay, let's fly through the rest of the doctrine. No one paradigm. — No one paradigm goes to the fact that Ruby is a fiercely object- oriented programming language at its core, but it's also a functional program language. This five times I told you about, you can essentially do these anonymous function calls
`2:09:58`
and you can chain 'em together very much in the spirit of how true functional programming languages worked. Ruby has even moved closer towards the functional programming and of the scale by making strings immutable. There are ideas from all different disciplines and all different paradigms of software development that can fit together. Smalltalk, for example. With only object oriented, and that was just it. Ruby tries to be mainly object oriented, but borrow a little bit of functional programming, a little bit of imperative programming, be able to do all of that. Rails tries to do the same thing. We're not just gonna pick one paradigm and run it through everything. Object orientation is at the center of it, but it's okay to invite all these other disciplines and it's okay to be inspired. It's okay to remix it. I actually think one of the main benefits of Rails is that it's a remix. I didn't invent all these ideas. I didn't come up with active record. I didn't come up with the NBC way of dividing an application. I took all the great ideas that I had learned and picked up from every different camp
`2:11:01`
and I put it together. Not because there was gonna be just one single overarching theory of everything, but I was gonna have a cohesive unit that incorporated the best from everywhere. — Is that idea a bit at tension with the beauty of the monolith system? — I think the monolith can be thought of as quite roomy, quite as a big tent that the monolith needs actually to borrow a little bit of functional programming for the kinds of problems that that excels, that discipline excels at solving, and that paradigm excels at solving. If you also want object orientation at its core. I actually think when I've looked at functional programming languages, there's a lot to love. And then I see some of the crazy contortions they have to go through when part of the problem they're solving calls for mutating something. And you go like, holy shit, this is a great paradigm from 90% of the problem. And then you're twisting yourself completely out of shape when you try to solve the last 10. — Ooh, exalt beautiful code is in the next one.
`2:12:03`
— We've talked about that at length and here's a great example that really summarizes the domain specific language quality of Ruby on Rails that you can make code actually pleasant to write and read. Which is really funny to me because as we talked about when I started learning programming, it wasn't even a consideration. I didn't even know that that could be part of the premise, that could be part of the solution. That writing code could feel as good as writing a poem. — class Project, ApplicationRecord belongs_to:account has many participants. Class_name, Person, validates_presence_of:name. — See, you could read it out. You didn't even change. — Anything like a haiku or something. — Right? Isn't that beautiful? — Yeah, it's nice. It's really nice. There's an intuitive nature to it. Okay, so I have specific questions there. I mean ActiveRecord, just to take that tangent. That has to be your favorite feature. — It's the crown jewel of Rails. It really is.
`2:13:04`
It is the defining characteristic of how to work with Ruby on Rails. And it's born in an interesting level of controversy, because it actually uses a pattern that had been described by Martin Fowler in the "Patterns of Enterprise Application Architecture." One of the greatest books for anyone working on business systems. And if you had not read it, you must pick it up immediately. "Patterns of Enterprise Application Architecture," I think it was published in 2001. It is one of the very few programming books that I have read many times over. It's incredible. In it, Martin describes a bunch of different patterns of how to build business systems essentially. And ActiveRecord is a little bit of a footnote in there. The pattern is literally called active record. You can look it up. — Nice. — It's called active record. I wasn't even creative enough to come up with a name of my own. But it allows the creation, the marriage of database and object orientation in a way that a lot of programmers find a little off-putting. They don't actually want to pollute
`2:14:05`
the beautiful object-oriented nature of that kind of programming with SQL. There was a rant by Uncle Bob the other day about how SQL is the worst thing ever. Baba, okay fine, whatever, I don't care. This is practical. We are making CRUD applications. You're taking things out of an HTML form and you're sticking 'em into a damn database. It's not more complicated than that. The more abstractions you put in between those two ends of the spectrum, the more you're just fooling yourself. This is what we're doing. We're talking to SQL databases. By the way, quick aside, SQL was one of those things that have endured the onslaught of NoSQL databases structured list data for a better part of a decade and still reign supreme. SQL was a good thing to invest your time in learning. Every program I'm working with the web should know SQL to a fair degree. Even if they're working with an ORM, an optic relational map or as active record. You still need to understand SQL. What Active record does
`2:15:06`
is not so much try to abstract the SQL away behind a different kind of paradigm. It's just making it less cumbersome to write. Making it more amenable to build domain models on top of other domain models in a ways that you don't have to write every damn SQL statement by hand. — We'll just say the active record is an ORM, which is a layer that makes it intuitive and human interpretable to communicate with a database. — Even simpler than that. It turns tables into classes and rows into objects. I actually think SQL is very easy to understand most of it. You can write some SQL golf too. That's very hard to understand. But SQL at its base, and much of the criticism against SQL was it was written for human consumption. It's actually quite verbose, especially if you're doing things like inserts over and over again. It's quite verbose insert into table parentheses, enumerate every column you want to insert, values, parentheses, every value that fits with that column. It gets tedious to write SQL by hand,
`2:16:09`
but it's actually very humanly readable. Active record just takes that tedious away. It makes it possible to combine things in a way that a humanly describable language just doesn't. It composes things into methods and you can combine these methods and you can build structures around them. So I don't dislike SQL, I dislike a lot of things in programming. I try to get rid of them. SQL wasn't really one of them. It was just a sense of I don't wanna write the same thing over and over again. It was a, can we be a little more succinct? Can we match it just slightly better to the optic orientation without trying to hide away the fact that we're persisting these objects into a database. That's where I think a lot of ORMs went wrong. They tried to live in the pure world of objects. Never to consider that those objects had to be consistent into a SQL database and then they came up with convoluted way of translating back and forth. Active record says, do you know what? Just accept it. This record, this object is not gonna get saved into some NoSQL database.
`2:17:09`
It's not gonna be saved. It's gonna be saved into SQL database. So it's just structure the whole thing around that. It's gonna have attributes. Those attributes are gonna respond to columns in the database. It's not more complicated than that stuff making it so. — Yeah, but I should say, so I personally love SQL because I'm an algorithms person and so I love optimization. I love to know how the databases actually work so I can match the SQL queries and the design of the table such that there is, you know, optimal, squeeze the optimal performance out of the table. Okay, based on the actual way that that table is used. So I mean, I think that pushes to the point that like there is value in learning in understanding SQL. I wonder, because I started looking at active record and it looks really awesome. Does that make you lazy? Not you, but a person that rolls in and starts using Rails you can probably get away with never really learning SQL, right?
`2:18:09`
— As long as you wanna stay at the entry level of competence. And this is actually my overarching mission with Rails is to lower the barrier of entry so far down that someone can start seeing stuff on their browser without basically understanding anything. Yeah, they can run Rail's new blog, run a couple of generators, they have a whole system, they don't understand anything. But it's an invitation to learn more. Where I get fired up, and this ties back to the AI discussion, is when that's turned into this meme, that programmers no longer have to be competent. I mean the AI is gonna figure it out. The generators is gonna figure it out. I don't need to know SQL, active record is gonna abstract it away from me. No, no, no dude, hold up. The path here is competence. I'm trying to teach you things. I understand I can't teach you everything in five minutes. No one who's ever become good at anything worthwhile could be taught everything in five minutes. If you wanna be a fully well-rounded web application developer,
`2:19:10`
that takes years. But you can actually become somewhat productive in a few days. You can have fun in a few days for sure. You're gonna have fun in a a few minutes and a few hours. And over time, I can teach you a little more. Active record says like, yeah, yeah. All right, start to here and then like next week we'll do a class on SQL. — And actually you have this beautiful expression that I love that that a great programming language. Like Ruby has a soft ramp, the ramp goes to infinity. — That's exactly right. — So yeah. It's super accessible, super easy to get started. — And it never stops. There's always more to learn. This is one of the reasons I'm still having fun programming. That I'm still learning new things. I can still incorporate new things. The web is deep enough as a domain. You're never gonna learn all of it. — Provide sharp knives. — This is a good one, because another way of saying this, the opposite way of saying this, the Java way of saying is do not provide foot guns, right? I don't wanna give you sharp knives. You're a child. You can't handle a sharp knife.
`2:20:10`
Here's a dull butter knife. Cut your damn steak, right? That's a very frustrating experience. You want a sharp knife even though you might be able to cut yourself. I trust humans in the same way that Matz trust humans. Maybe you cut off a finger. All right, you're not gonna do that again. Thankfully it was a virtual think finger. It's gonna grow back out. Your competence is gonna grow. It's more fun to work with sharp tools. — And that actually contributes to the the ramp that goes to infinity. — Yes, to the learning — Value integrated systems. — We kind of hit on that one. This is Rails is trying to solve the whole problem of the web, not just one little component. It's not leaving you a bunch of pieces. You have to put together yourself. — Progress over stability. — You know what? If there's one that's dated, it's probably that one. At this stage, Rails has been incredibly stable over many, many generations. The last major release Rails 8 was basically a no upgrade for anyone running Rail 7. Rail 7 was almost a no upgrade for anyone running Rail 6.
`2:21:12`
I used to think it required more churn to get progress to stay on the leading edge of new stuff. And I wrote this before I experienced the indignity of the 2010s in the JavaScript community. Where it seemed like stability was not just unvalued, it was actually despised that churn in and of itself was a value we should be pursuing. If you were still working with the same framework three months later you were an idiot. And I saw that and I actually recoiled. And if I was gonna write the doctrine today, I'd write that differently. I wouldn't say progress over stability. — Well maybe it'd be a function of the age of the programming language also. — Maybe, or a deeper understanding of the problem. I think part of what's so fascinating about technology is that we have this perception that everything constantly moves so fast. No, it doesn't. Everything moves at a glacial pace. There is occasionally a paradigm shift
`2:22:13`
like what's happening with AI right now. Like what happened with the introduction of the iPhone in 2007, like what happened with the internet in '95. That's basically the total sum of my career. Three things changed. Everything else in between was incremental small improvements. You can recognize a Rails application written in 2003. I know because the Basecamp I wrote back then is still operating, making millions of dollars in ARR, servings in customers on the initial version that was launched back then. And it looks like the Rails code if I squint a little that I would write today. So most things don't change even in computing. And that's actually a good thing. We saw with the JavaScript ecosystem. What happens when everyone gets just mad about constant churn? Things don't change that often. — By the way, on that small tangent. You just sort of visibly, verbally changed your mind with the you of 15 years ago. — Yes. — That's interesting. Have you noticed yourself changing your mind