DAVID HEINEMEIER HANSSON: That any better? Oh, there we go. Woo. Software's hard, as you can see. Hardware,
too. So last year I had the personal pleasure of celebrating ten years of working with Ruby
and ten years of working with Rails. But this year,
I have a much more interesting anniversary,
which is ten years of sharing Ruby on Rails with all of you and everyone who's been using it over
the past decade. The picture in the background is actually
from almost exactly this time, where I gave the very first presentation on Ruby on Rails at a Danish
university ten years ago. Ten years ago, I had to talk a lot about what is MVC, for example. Today, not
so much. There's a lot of things that over the past ten years, things we were worried about
in the beginning, sort of leveling up as a community and as, as programmers, that just aren't relevant
anymore. We're just taking all that stuff for granted. Which is awesome. We get to care about a lot of other stuff. But as I look back over the past ten years, which is pretty much the majority of
my adult life, I've been working on Ruby on Rails. It's fun to look back even further. I think there's a common misconception that anybody
who ends up creating something like Rails or doing something else within software development or computer science, well, they must have been programming since they were five years
old, right. The whole notion of a hacker is somebody who, who sort of got their first computer twenty
years ago and was just programming the entire time.
Well. That wasn't me. I did not learn to program when I was five years old. I didn't learn to program
until I was closer to twenty. I'd been interested
in computers for a long time, but it wasn't really until the late '90s, early 2000 that I dove into computer programming as something that
I was going to do. I had a lot of friends who were doing it. I knew a lot of programmers. But somehow it, it sort of never, never caught on. Before I started writing software that I needed for
myself, and before I found sort of a place in the software world for that to happen. And the reason I, I say that is, is I've seen a number of essays of like, what is a true hacker, and, and as a true hacker, one of the things that keeps being
thrown out is those ten years, right. You should
have been programming for ten years already, otherwise you're way behind. Well, I learned to program about three years
before I released Ruby on Rails. Turned out fine. And I don't say that as, like, it was because I grew up on a farm and didn't know what a computer was. This is me in, in the center there with the stick, and the blue shirt in 1985. These are the kids that were living in my neighborhood. In 1985 I got introduced to my, my first computer. And I was about five years old.
And I got introduced to computers through gaming.
Sort of, we were playing ninjas in the streets around
our houses, and then we'd play ninjas on the box. And I found it fascinating right from the
get go, right. Computers were really fascinating and games really captured my imagination early on. I remember,
at, at that time, there were certain, lots of parents
were like, well make sure you get out and play a lot. Because you don't want to spend your, or wasting your time, that was the, that was the word, wasting your time in front of computers inside, right. Well, I really did want to waste my time in front of computers. And this was the computer to have in 1985, in our neighborhood. But
we couldn't afford a computer like that. There
was only one guy in the whole neighborhood that had
a computer like that. So we all shared it and we all played Yeah, Kung Fu, in turn. But then the next year, so, I, I couldn't afford this computer, but my dad somehow,
he was fixing TVs and stereos, he traded a stereo
with this guy for this other weird computer, which
was an Abstraught 646. And I was really excited. It didn't actually
play Yeah, Kung Fu. I was a little disappointed
by that, but it had some other crappier games.
Anyway, it was a computer. And that was sort of my first introduction to, to computers, six
years old. And, and I tried to learn programming. I, I got a magazine and, at the back of these magazines back then, there were programs
you could type in. And I was like, wow, this is, this is amazing. I can control this computer. So I built my first information technology
system. It was messages to my mom of where I went, where, I had this clever system that
would really optimize the fact that writing a message
of where I went and, and when I was going to be home, it was too complicated. It would be much easier if I just wrote a little note where I gave her the location on the tape that she had to fast forward to, and then she could read where I was. I thought, man this is so clever. I just have to write down two twenty-eight, and then
I could preprogram that note, and she'll never
know I was over at Peter's house playing Yeah, Kung
Fu. That really wasn't programming, right. I just
typed some stuff in. I didn't know what the hell I was doing. I just somehow figured out print,
OK, that puts stuff up on the screen. That was, that was the extent of it, right. But it was my first stab at programming. And I, and I, it kind of failed. That was the extent of my programming, that
I knew how to fast-forward to a pre-recorded
message. Not that great. So a couple years later, late 80s, I saw this game for the first time. Battle Squadrant.
And I remember thinking, holy shit, these graphics
are amazing. How can they make this? This looks so good, when you were used to a Commodore 64, the graphics of the Amiga 500, which is mind blowing, right. And once again, I felt this, like,
wow, wouldn't it be amazing to be part of that? To be able to create something like that? I'd love to make games. So I sort of started looking around, and,
and I found this thing called Amus. I don't know, has anybody here ever programmed in Amus?
Not a single hand. OK. Must have been a very European thing. But it was sort of a real programming environment, and, and I got the box, and sort of my English was a little, not that great, so I was sort of just reading through it and trying to find the code. And it was all about sprites and vectors and ifs and variables,
and it, it didn't make any sense to me at all. So I thought, eh this is a little bit too hard. Thankfully, there was something
called Easy Amos, right. Oh, wow, that's gonna be great. This
other one was too hard. Now I just have to do the easy one. Unfortunately, in Easy Amos, it was still
programming, and it still had conditionals and variables and
all these other things I just did not understand. I,
it's so funny, because, once you learn something,
it can sometimes be hard to go back and think, like, how was it before I knew how to do this? But I distinctly remember, why would
you have a variable? Like, if you just assign something once, why
would you ever sort of want to change that? Why does it have to be a space. Why can't it just be the thing. Like, I did not get the concept of variables. And this is at, I don't know, age ten or whatever. So, still not getting programming.
It's still not making any sense to me. So I gave up on that, too. Then, in 1993, I went to something called
the Gathering. The Gathering three, which was
a big demo party in Denmark, where people from all over
Europe, maybe some from the U.S. as well, would gather to, to show off their skills of creating these demos. And demos were basically just, like, little
music videos with computer graphics. And I thought that
was really awesome. And, again, I got this sensation
of, wow, that's amazing. People are creating these
sequences, they look really good. This is, this is awesome. I'd
love to be a part of that. This is '93, so I'm, I'm fourteen. And this demo party, and then I met pretty much everybody I knew for the next ten years in, in computer software, including Allen of TextMate
fame. I was fourteen and he was part of one of these demo groups, and we got talking, and then
ten years later, I'd help him release Textmate,
and this is now twenty years ago. Anyway. I still didn't get the concept, right. Like,
it was all, it was Assembler. So it was even harder and weirder to figure out than Amos
was. It was vectors, it was math, it was, it was just really hard. So once again, this
is the third time I tried to sort of figure out programming, because I want to build stuff. And the third time, it failed. So I ended up building another information
system. At that time, there's something called BBS's.
So pre-internet, you dialed up to basically every web site individually
through a modem, and I ran one of those things. At that time, it was, it was called a Where's BBS, which is where we traded all
the illegal software that we couldn't afford,
and games, and demos. And I had a lot of fun doing that. I was fifteen and I was, I was working at a grocery store, and I spent all my money buying modems and phone lines. But sort of the long and the short of that is that I failed to identify with programming under the computer-science paradigm. Computer science, in itself, just didn't really
appeal to me. Like, it didn't make sense to me. Learning programming through sort of the lens, the
prism of, of hard science just, it didn't really, it
just didn't click. And I was actually pretty disappointed
for awhile. I had tried to learn programming three
or four times over the past ten years of my, my life, and it just, it wasn't clicking. No surprise to sort of my teachers. This is my high school diploma, part of it, and it says math, final exam, F. And, and English,
I got an A. But math was just never my thing. Physics never, was never my thing. Any of the hard sciences were just never my thing. And you say, oh, well that explains
a lot. That's why Rails is so fucking slow. But it, it's true. It just never appealed
to me. But, I think it also inoculated me with something really early on, which was, it disabused
me of the thinking that I was a computer scientist. That I was ever going to come up with an algorithm. That I was ever going to make any ground-breaking discoveries at the low-level
of, of computer science. And that was actually really a relief. Because
when I finally got into programming, I knew that
was just not what I was going to do with it. That was never, it wasn't my idol, it was not what I was chasing. I wanted to build information systems. Like all these
attempts I had over the years, they were all about information
systems. They were about using the computer to build
something else that really didn't have much to do with the underlying things. That there were people,
smart people, who had come up with algorithms underneath
to, to make it all work, wonderful. I'm not one of them. And that's fine. I think as an industry, very few people have gotten to that realization. Even if it is,
that they, on a daily basis, build information
systems. Even if it is that they're working on yet another social network for sock puppets, or horror,
in my case, yet another fucking to-do list. The
aspiration of the whole industry, everyone in it, is that
we're all programmers. Right? No we're not. I am nothing like Linus, right. He's actually a real computer scientist. To
figure out how to, I don't know, fucking improve the
scheduler in the kernel. Shew. No clue. No interest.
All good. I am ever in debt that there are people like that out there who can do this stuff. So I don't have to do it. So I can focus on something else. But I think most programmers think that, oh yeah, that, that's
what I do. Yeah, I work information systems, but,
we're kind of colleagues, right? Me and Linus here. I'm pretty sure that he would tell you, fuck you. We're nothing alike. We are not colleagues.
What you do is making another fucking to do list. I'm improving the fucking kernel of Linux.
Far more important work. He would disabuse you of your
delusions of grandeur real quick. And I think that's a real shame. I think it's a real shame that if you sort of pick your heroes in such a impossible fashion,
that they're actually nothing like you and you
will be nothing like them, you're gonna set yourself
up for a bad time for the whole ride. The truth of the matter is that most information system development has very little to do with
science. Yes, it's all built on top of computer science. Yes, computer science is what makes it possible
for us to do what it is that we do. But it doesn't define what we do. And I think in many ways that prism of computer science is harmful to the development
of information systems. It's actually not a good view on
the world to have. Just because you can make,
you're Steingraeber and Sohne, and you can make the
best piano in the world, that doesn't make you
a great pianist. It doesn't mean you can play
wonderful tunes. Just because you can create the foundations
of which other people can build upon, just because
you're a great computer scientist, doesn't mean you're
a great software writer. Doesn't mean you're a great programmer of
information systems. And most of all, if you are committed to building information systems, and I am wholly
committed to building information systems, I've given up
the notion, long ago, that I was going to get into games programming or vector programming or anything
else that sounds like hard science and is hard. I think you're gonna be much better off. But I think it's also really tough, because I
think most of the paths, the celebrated paths into
programming go through courses called computer science.
So you're sort of taught right from the get go that computer science, like that is the ultimate ideal,
and what you're doing here is just sort of piddling
along until you can get to this top of the mountain. Even worse, if you actually have a degree
in computer science, right, and now you're slumming
it, with yet another social network, or, yet another
fucking to-do list. I mean, that's a recipe for self-loathing
if I ever knew one. But, as I say, this is mostly about the prism of how you're looking at programming,
what is programming, what is writing software. What
is that we do every day when we create information systems? And if you look at it from this prism of the hard sciences, you think, well, Law
of Thermodynamics. Physics. This is, this is
the real serious hard stuff, right. You will laugh at French
poetry. Ha, ha, ha, ha! They're all just, what, analyzing what some schmuck in the 1700s did, and there's a thousand different interpretations of, of
what that person actually wrote and what does that actually
mean? Like, that's pathetic, right. You can't arrive at
any ultimate, clear, universal truths. Math! There's a truth. There's a final result.
Physics. There's a truth. We're knowing more about
the natural world in a way where we can be completely confident. Mostly. In what we know. Certainly
in math, right. If you carry that over into programming, you
end up with shit like this. Law of Demeter. Practices and principles who sort of project that they're
universal truths about the natural world, that this
is how good programs are made, and this is not really an argument. The only argument is whether
you're professional and following the laws, or you're an amateur
and you're breaking them. When I look at computer programming, and when
I reach most, read most programs, I'm not reading
hard sciences. It is much more like studying 17th
century French poetry. What the fuck did this guy
mean? Like, I can't follow this at all. Like, is this some weird reference to some play somewhere?
What's going on here? It's actually more like forensics. It's more
like analysis. It's much more subjective. Like, what is actually
going on? What were they trying to communicate?
What's just going on here, right? So, I find it so funny that, that programmers who work in programming, and they laugh at
all these subjective fields of endeavor, when
that is what they do every day. They just, no, what I'm doing is computer science. This is empirical
truth, blah, blah, blah, we have laws, blah, blah, blah. I think the, the bottom line is that is when you go in with that notion, when you go in with the notion that we can actually discover laws of programming, like, Law of
Demeter, of how we should be creating our programs, you
lull yourself into this belief that there are some
practices that are just true. They're not up for debate. They're not up for discussion. They're science. That what we do is science.
Well, I think there's another word for, sort of,
those delusions. Pseudoscience. When people think
they're doing science and they're not actually doing science. That's
pseudoscience. I think a lot of what's going on in software, methodology, practices, is pseudoscience. Which would be fine if people would accept
that and say, yes, what I'm doing is pseudo science. Like, I'm not finding any grand truths here,
but they're not, right. They're ex-pouting that
this is, this is the truth. Well, here's another pseudoscience. Diet schemes.
I think diets are actually incredibly similar to most software
methodology approaches. They all sort of espouse that I have the truth, what you need to get slim and healthy is the ten-day green smoothie cleanse. That is the truth. That's how you get it, right. And then you, shit, that, that's, OK,
smoothies. Sounds good. But what about this super shred
diet? Like, I lose twenty pounds in four weeks?
That's certainly better than ten pounds in, I don't
know, ten weeks, or whatever that hungry diet girl
is promising. I'll go with that super shred guy,
like he's got to have the truth, right. And it's so funny, if you read any diet books, and diet books are incredibly popular.
If you look at the most popular book on Amazon, the top one hundred list, a lot of them are diet books. People want to be told how they can cheat the basics. I think software development
is exactly like that. I think software developers are exactly like
people trying to lose ten pounds and thinking, you know
what, all this exercising, just eating healthier,
that's a little too hard. Let's, let's listen to this super
shred guy. He's got to have the answer. An answer that's less painful, less simple and basic. There's
got to be some grand secret I just don't know yet. If I can just learn the secret then everything's gonna be great, right. But it's pseudoscience.
Those diets are based on anecdotes. They're based on one
guy trying something, or, or looking at a few
people, a tiny sample size, it's just pure, poor,
pure poor science. External variables, uncontrolled experiments
that run for too long. You can't derive any absolute truths from
it. But people keep arriving at absolute truths. And just like feeling a little overweight,
and most people do at some point in their life. Everybody wants to lose whatever it is. They want to feel healthier even if they are at the correct weight. They want to be in better shape. All our code bases are exactly like that. Everyone has like, oh I'd love that this part of the code base, it's not that clean, right. So we have that same feeling of being a little insecure about our quote code quality,
just like most people are a little insecure, at least
at certain times in their life, about their body,
right. So we're ripe for somebody to come in and tell us what's wrong. To fix it for us by just saying, oh, no, no, no, you don't have to do any of the hard stuff. Writing good code, do you know what that's about?
It's about this one practice. This one secret that
they don't want you to know. If I teach you that, then all your code is going to be wonderful. But right now, you're not a professional. You're an amateur. You're
writing dirty code. You should feel really bad about that.
You have sinned. But, I will give you absolution. I have the pathway to clean code. And it hits a lot of people right in the impostor plexus. Like, ugh, you're saying
my code is dirty? Yeah, I guess it is a little dirty. There's this one part that's, like,
shit, maybe I'm not really a computer scientist. Maybe
it doesn't really, I don't really belong here amongst
the programmers. Can you please tell me, how do I get to be a computer scientist? How can I get to belong amongst the esteemed professional programmers? Can you tell me
how? And there are lots of people willing to tell you how. That the salvation will come through these
patterns and practices, and as long as you follow these
ten commandments of good code, all shall be well. OK. I think the most popular commandment, I'm
gonna spend some time on that, the most popular practice,
the most popular pattern for making people feel
shitty about their code and shitty about themselves and
shitty about their path through programming, is TDD. TDD is the most successful software diet of
all times. It's so alluring, it has such an appeal in its basic principles, that everyone gets
wrapped up in it. I got wrapped up in it for quite awhile. I got wrapped up in the storytelling that all software before TDD was shit and
unprofessional. And that the only way to arrive at clean code was to follow the principles of TDD. And the principles of TDD, mind you, are not about the tests. It's about test first. It's
about test-driven design, right. That we have tests
afterwards, that's just an accidental side-effect. A benefit,
if you will, after the fact. And it's the perfect diet. I tried multiple times, which is usually how
it goes with diets, we try one and it doesn't really work and we fall off the wagon and then a few months later you try again and you feel bad about it the whole time and that's how I felt about TDD for a long time. I felt like TDD was what I was supposed to do. I was supposed to write all my tests first, and then I would be allowed to write my code. And it just didn't work. I kept just feeling like, this is not, I'm not arriving at something better here. When I'm
driving my design by writing my tests first, the code
I look at afterwards, it's not better. It's
not cleaner. The dirty code I wrote without being test-driven
first, it actually looks better. But, so successful has TDD been, that for
the longest time, until actually fairly recently,
I just thought, well, I'm the wrong-doer. I'm the one doing
it wrong. TDD is not at fault, right. Just because everybody's doing TDD wrong, doesn't mean
that there's anything wrong with TDD. There's just something wrong
with all of you. That's the problem. If you would just be more faithful to the practices, then everything would be great. And that's what makes it such a great diet. That it keeps people in the perpetual state
of feeling inadequate. So, you keep having to
buy more books, and attend more conference talks, and
attend more workshops, and hire more consultants, to teach
you to be truer to the religion of TDD. Hogwash. Let's look at some code. So here's a very simple piece of code. Person has an age method, that calculates how old somebody is. And we
have a test for it. This piece of code depends on the world. It directly refers to date today. It's a explicit dependency. You cannot change it in there.
Well, in a lot of languages, that's a problem. Like,
how are you actually going to test this if you can't somehow figure out how to change the
date of today. Like, every time you run your test it might be a different day and it might be broken. Well, in Ruby it's really easy. We just stop that constant and make it work. That's what
the travel-to method is about, right. Proponents of TDD will look at that code and say, dirty, dirty code. Explicit dependencies
hidden inside. You're mocking a global object? What the fuck? You need to shape up. Here's the shaped up version. We inject our dependency, so we have
a default of date.today, but we can put in our own, in the test, we can put in our own date, right. This is much cleaner. Right.
No. Great. We improved our code base. Did we? Is this a better code base? Is this method better than what we just had there? Is it simpler? Is it clearer? No. It's easier to test. And that's the important point, right.
That's the important point in all of these debates,
is just, is it easier to test? That's the measure of success. I think that's
a shitty measure of success. I think there are
much higher ideals than just whether something
is easy to test. But it gets worse. Here's another example. If you actually have
a method that depends on another method, we have to
inject the dependency all the way down, now you're
really muddying things up and now the code is really starting to get nasty. And this is such a simple example. I've actually posted this
example online before and had arguments with TDD proponents about
that. And, yes, this is, I'm like, well, what does it matter? You're just injecting one dependency,
what does it matter? It's not that big of a deal, right? Yes it is. Because this is exactly the type of thinking
that leads you down a really nasty path. Let's
look at another example. Here's a standard Rails controller. It has
reliance on the world. It relies on a before action that ensures permissions. It sets up a new object
and sends out an email and then it responds to something, right. The whole purpose of the
controller in Rails is to sort of direct the world. It's to interact with the world. But how do you unit test that, right? That's really hard. It's relying on the entire world.
If we're following this scientific approach of
unit testing where we're isolating all the variables, holding
everything else constant except for these two things, what goes in,
what goes out. This is bad, right. If we instead put in something like a person creation command and hide away all the actual
doing of the control and then we inject all the stuff that it depends on we can test person creation command really well. Is that code better? Is that code simpler?
Is it clearer? Would you rather look at this
and then understand what the system does or would
you rather look at this and try to figure out where does this thing go? And that's the consequence of this chase of
test-first. It leads you down a path where the gospel of test-driven design is that anything that's
easier to test is better. That's it. That's the measure
of quality. If you can test it easily it's better. If you can't test it easily, it's worse. Boo. Exactly right. Boo. It's not better. We're losing sight of what
we're actually trying to do. Tests were supposed
to support us. They weren't supposed to be the main thing. And I think this is leading to a lot of Zombie astronautic architectures. Things
that I thought we moved past long ago. If you look at, at this person create command, that reminds me
very much about Struts 1 point 2, and how they had every action as their own object. And that
it was great because it was easy to test, and it was shit when you were trying to put a whole architecture together, because you
had all these create commands and all of the sudden you
had a million objects. Yes, they were easier to
test, but the system was much harder to reason about. You see the same thing around ActiveRecord,
for example. You see, well ActiveRecord should just be
data access objects. They shouldn't actually have any
logic. They should just be about interfacing with the database,
because then we can split out everything else. Our domain
logic, it's just that it doesn't have to touch the database, so that our tests can be simple,
so that our tests can be fast, right? Again. Order of priority. Test, test fast,
oh, your architecture. That'll just fall from that,
right? I recently read James Coplien, has a great
paper out called "Why Most Unit Testing is Waste."
And for me, this is the money quote. Splitting
up functions to support the testing process,
destroys your system architecture and code comprehension along
with it. Test at a coarser level of granularity. TDD is focused on the unit. The unit is the sacred piece, because that's the science
piece. That's what we can control all of the variables.
We're just looking at these few pieces, right. What James is saying, maybe that's not the
right level. Maybe testing, the role it should have,
shouldn't be about the unit most of the time. And, I sort of alluded to this awhile back, I wrote a post called Testing Like the TSA,
and the main thing about that was about over-testing
and sort of this testing theater that goes on.
But I hadn't really made the switch that it, the problem is that we're trying to test at the wrong level. It's not testing itself. Testing is great.
I'm not advocating that we shouldn't have tests. I'm
advocating that driving your design from unit tests is actually
not a good idea. That you actually end up destroying your system architecture and your code comprehension
along with it. So if unit tests aren't the thing, what could we do instead? Well, I think there are higher levels of testing. We've already sort of moved to that in Rails. It's no longer called test unit, where you
place your tests, it's called test models. That's
already one step up. That sort of frees you from feeling bad about the fact that your, your model tests actually touch the database. That's not a
bad thing. Yes. They run slower. But they also test more things. You can make anything fast if it doesn't have to work. And I think that's the problem with testing
in a lot of cases. We recently had a really bad bug on base kim where we actually lost some data for real customers. And it was incredibly well-tested at the unit level. And all the
tests passed. And still we lost data. How the fuck did that happen? It happened because we were so focused on
driving our design from the unit test level, we didn't have any system tests for that particular
thing. And it was a really simple thing. It was like, if you were editing an object and you were editing the attachments, you could lose an
attachment. And we lost some attachments and it was a terrible thing. And after that, sort of thought, wait a minute. All these unit tests are just focusing on
these core objects in the system. These individual
unit pieces. It doesn't say anything about whether the
whole system works. Most TDD proponents, I find, are much more
focused on the unit level, because that's where they're
driving their design. And they're not very much focused
on the system level at all, which is what people actually give a shit about. Does the system work? I don't care about whether your units work. Does the whole thing work?
That's what matters. So that kind of freed my mind up a little bit. That if we give up this need for hard science experience, where we have
to control all the variables and boil everything down
to a single unit that can be tested, we can float freely with the world. Awesome. This realization, I came to realize, was why
people hate fixtures. So fixtures in, in Rails is
about spinning up a world, it's about setting up,
sort of, small size version of the whole world.
Where most approaches, they focus on just one unit. I don't want to have an account in here and a project in here if I'm just testing my message. I just want to test this one single thing, right. And if you're doing that,
yeah, fixtures are probably not a good thing. It
doesn't really work for that. It works really well when you're not concerned
about the hard science focus on unit tests. It works really well when you're focused on a larger
level. When you're focused on models, when you're
focused on controllers, and most importantly when you're
focused on systems. But all that is sort of usually swept away by the holy trinity of test metrics. Coverage,
ratio, and speed. I've been in a lot of internet arguments lately. In such esteemed establishments as Hacker
News, and, and elsewhere, and I find it really interesting,
because each individual argument will make me rage, but
then the larger set of all arguments, like a meta study, actually reveals really interesting things
about what people care about. What they value. And what I find is, in most discussions about design, especially around Rails, what people
care about these things, and these things only. It's about
the test coverage. It's about the test ratio. And it's
about how fast your tests run. Like, that's the pedestal. That's the holy
grail. What actually happens underneath, the design of
the rest of the application is, eh. Doesn't really matter. And thus, a lot of people come to celebrate, oh, I have a one to four test ratio. For every line of production code, I have
four lines of test. Oh yeah. And they say that with pride. And I'm like, what? So you're saying for every line of production code you write, you have to write four lines of code? And that somehow makes you a hero? How, how does that work? So your system is now five times as large, reasoning about the whole system is now five
times as complex, and you're proud of this, why?
Well, of course, because I have a hundred percent
coverage. My five thousand tests run incredibly fast
because they never actually test very much. They certainly do not test the system. They
test all these little slices of unit. Wonderful. It's not wonderful. You have anemic fucking
tests. They don't prove shit. You're gonna have the same
bug that we have on base camp, and the system is not going to work even though you've proudly proclaimed, oh, well, your units are working. Well, whoopity-doo. This decoupling is now
free. People think that, oh, this is like that saying, like,
quality's free. Right. Testing is free. Not when you're
doing it like this. It's not free. And most importantly, it's not free, not so
much in time, but in conceptual overhead. Understanding
a system that has been test-driven designed from the
unit perspective is really hard. Because you have all these
levels of indirection. You have all these levels
of intermediation. To separate the tests from slow things, like
HTML or the database or, any of the other parts of the system that actually makes up your
system. And they focus just on that one thing. So they can be very fast, if they don't have to work. They don't actually have to test
your system. So that's sort of two charges in one. It's a charge first that your design is not going to improve. Your design is going to deteriorate
by doing test first programming, because you're
going to construct your units of testing, your methods, in a
different way, like we say with the age example. You're going to inject all your dependencies in a
way that does not prove things. And second of all, you're not gonna get the benefit of great coverage. You might have
a lot of tests, but they don't test your system.
It doesn't improve your confidence in actually
the whole thing working, and then what good is it? Well, I thought about this for a long time and thought, like, this is not really, it
doesn't seem like that great of a revelation. Why,
why do I keep having these arguments over and
over again? Why are people focused so hard and
so intensely on this trinity of test metrics?
How did that come to be the main thing that people are arguing about? How did that come to be the main decider of what's good design and what's bad design?
Really, couldn't really figure it out. Until I started
thinking back of like, what is this prism we're looking through? We're looking through computer science.
Engineering. Professionalism. James Harrington wrote a bunch of books on
quality of engineering, and he has a great quote here. If you can't measure something, you can't
understand it. If you can't understand it, you can't control
it. If you can't control it, you can't improve
it. That makes a lot of sense. Cause like, yeah, yeah, that makes sense. That's gotta be why.
And then I got another great quote. Just because
you can, just because something is easy to measure
doesn't mean it's important. This, I think, is exactly what's going on
here. Programming of information systems is a lot
more like French poetry than it is like physics. But
programmers grow up thinking that they're computer scientists,
so they want it really badly to be like physics. They want it really badly to be a hard, professional science. And coverage, ratio, and speed. You can get
that fucking thing down to six decimals. Like,
that, I can be so precise about how fast my test runs, eighty-four point seven percent coverage,
boom. Got it. Doesn't say anything about whether or not
that's actually important. Doesn't say anything about whether
that's actually producing a good system. Doesn't say anything about
whether the person after you, or you yourself, three months
from now, can understand what the hell is going
on in this code base. You haven't necessarily made anything any
clearer. You've made it very easy to produce metrics. And if there's one thing we love with, with science, it's
clear concise objective truths and coverage and
ratio and speed fit that bill. So we adopted them with open arms, even though they were not that important. Second part of it. Cost is not value. A lot of people have invested so much in building up their expertise, their time, their four-to-one
ratio in tests. The investment is massive. Well, of
course they're gonna be defensive about it. Like, you've
invested so much of your ego and your time and your resources on this project, into testing. So
of course it must be valuable. Of course it must be important. That's not how it works. Just because something
is really expensive, just because something takes
a lot of your time doesn't mean it's valuable. Doesn't
mean it's important. So I was sort of giving a brief description of this talk yesterday at dinner with Aaron
Patterson, and he trolled me right back and said, TL;DR, just don't test, right. Like, that's what
I'm supposed to get out of this. No. No. Testing absolutely has value. Regression
testing absolutely has value. Driving your design through test
first? In my mind, rarely has value. Not never. There
are times where I'll write my tests first, usually
when it's something like a translator of some kind,
where I know exactly what's going in and I know exactly what I want out. That could be a good case to start with test first. Most information system design
is not like that. I'm trying to figure out and sell what the system is supposed to do. What I'm going to arrive at is the test, is this set of tests, it's a set of regression tests,
that make me feel good about that after the fact, that I can still change my system and not break it, right. So TDD. Kent Beck. Main proponent behind TDD
has a very sensible quote that goes exactly along
these lines. I get paid for code that works, not for tests, so my philosophy is to test as little as possible to reach a given level
of confidence. Immensely sensible. I find that that's actually
often the case with these things that get taken too
far. TDD started out as a pretty sensible thing.
Kent has an even more sensible perception of it
now, I think, than when he wrote the test-driven
book originally. But that's not what most people
take away. That's not what most people run with if they want to build a career on making people feel shitty about their code bases and their dirty,
dirty code. They take a much more extremist approach,
that unless you're doing test-first, you're not a professional.
Certainly not what Kent's saying. OK. So for me, this really boils down to, we're, we're trying to wear the wrong hat
the majority of the time. Thinking of yourself
as a software engineer will lead you down the path
of coverage, speed, metrics, hard sciences - all
these things we can measure and it leave you laughing at shit like interpretation of French poetry.
Of subjective evaluations of a design in the system, even though these are the only tools that we have. So this has taken me awhile to arrive at this conclusion. I've hated the word software
engineer for quite awhile. Cause I never felt it fit me. I never thought of myself as a software engineer. I kind of tried to be one, a few times, and I failed all the time. And by the time I finally arrived at programming
as something that I wanted to do, it sure as shit wasn't software engineering. Yes. It's a hard hat that I wear occasionally, when I do performance optimization. That's
hard science. You make a change. You measure it. Was it an improvement? If not, revert. If yes, deploy.
Very scientific. Very good. Great to wear the hard hat when that fits. Is what, that what I do the majority of the time? Is that how I think of myself when I write most of the things that I write? When I add a new feature to base camp or do forensics to figure out how a bug came about, or what somebody meant when
they wrote a bug in or something? No. That's not what I do. So I don't try to think of myself as a software engineer. OK. If we're not software engineers, most
of the time when we make information systems, what
are we then? What other hat should we try to wear? What other identity should we try to aspire
to? I think we had it all along. I think we had it in the language all along. We're software writers. Writing is a much more apt
metaphor for what we do most of the time, than engineering is. Writing is about clarity.
It's about presenting information and motivations in a clear-to-follow
manner so that anybody can understand it. There are not bonus points for making something
convoluted, as there often is with engineering and with
test-first design. Making things more convoluted gives
you the benefits of, perhaps, easier to test. They don't give
you clarity. So those things are often in opposition. Clarity is all about being succinct without
being terse. WE can write things using as small words as we know how, using as little complication
as we know how, using as little conceptual overhead
as we know how to get the job done. That's a much better approach. And I think
it comes very easy if you think of software development as writing. If you look at a piece of writing that somebody has written and it's
kind of convoluted, can't really follow the argument,
and paragraphs are not broken up neatly, is the first thing you're gonna say, you know what the problem with
this is? You're not using big enough words. If we just shoved some bigger words into this text, it's gonna be there. That's good. Oh.
The problem here is like, like your sentences
are too clear. If you just insert a sentence in the middle, that'd be great. Oh, do you know what? This needs more semicolons. That's what this
needs. If this has more semicolons, boom. You got clarity. No. More indirection. More third-person. These
are not the things that make for great, clear writing.
And that's obvious when we talk about things like writing.
SO if we talk about software development as writing,
I think it'll be obvious too. I think if we supplant the high ideal of what matters for
design is how easy it is to test, how easy it is to make engineering driven, and put
clarity of the code base above all else, we're gonna be much better off. And arguments are gonna
be settled much easier. And it's gonna be much
easier to read the fucking code you wrote three months ago, because you had that in mind. That was your motivation. That was what you
were going for. So what is clarity? How do you figure that out, right? That's real easy to say, oh it's just clarity. Boom. It's open to interpretation,
right. It's not as clear as just saying, oh if you can just get your code coverage above 85%
then you're gold, right. Clarity doesn't work like that. There's not
a metric we can just apply, because, again, it's not
hard science. Clarity of writing is not hard science. So the easy answer is, I know when I see it. Right? There's not just gonna be a list of principles and practices that somebody
can be taught and then they will automatically produce
clear writing every time. Right? If you want to be a good writer, is it enough just to sit and memorize the dictionary? No. Just knowing
the words available to you, knowing the patterns of development
is not gonna make you a good developer. You have to develop an eye. You have to develop an eye for clarity, which means first
of all, you have to decide that that's important
to you. So that's the first step. If you're still stuck in, the most important thing about my
system is how fast my tests run, and how many of them I have, well. Forget about it. You're not gonna get to this point. You have to decide that the most important
thing for your system is clarity. When you do decide that, you can start developing an eye. I started getting into photography maybe six years ago.
When I first got into photography, like, I would
look at a picture and it was like, well, looks like a good picture. Now, I've been looking at thousands of pictures.
I've been taking thousands of pictures. And I've
developed an eye. I can see when the white balance is off. I can see, oh, this has a blue tint. Oh, this actually, if we crop it just a little bit more, only the subjects we want to have in focus are in focus. Oh, this would actually be better in black and white. That eye just came from doing it. A lot. It didn't come from just sitting down and
reading a lot of photography books. And I think it's the same thing with code. I think a lot of programmers, coming at it from a software
engineering angle, thing that just all they have to do is learn the practices, learn the patterns,
memorize them all, and then they will be good programmers. No, they won't. The only way to become a good programmer, where, by definition, I define
good programmers as somebody who programs, who writes software
with clarity, is to read a lot of software, write a lot of software. Just like how do you become a good photographer? You take a lot of pictures. And you look at them. And you practice. And you practice.
And you practice. I think it's quite similar to the problem
with diets, right. The fundamental truth with diets
is to be healthy you should probably exercise regularly,
you should probably eat a reasonable amount and it should
be good stuff. Like, that's three things. Incredibly
hard to do. Most people do not do that, right. Figuring out how to write good software: read a lot of software, write a lot of software, aim
for clarity. It sounds too simple. Why is it simple? Because there's not just
a secret. There's not just one answer somebody
can give you. The only way you can get there is by doing it. So when I first started developing Rails, I read a ton of software. I read the entire Ruby standard library. Partly because
documentation of Ruby at that time was pretty poor, and the only way to figure out how it worked was to actually look at the code. But that was also where I learned so much. Today, we have it so much easier. Bundle open name of any gem, and it'll open, boom, right up in your text editor. You can look at any code. How many of you have read through a complete gem recently. Something you did not write.
Awesome. That's actually really encouraging. I thought it
would be much less. I think that is exactly the path you need to take. You need to read a shit ton of code. And it's not so much just because you read this code and then, oh that's all great stuff. Just as important as it is to, to develop your sense of writing by reading
a lot of shit writing, so is it with code. And I think you will find that that is actually very easy. Because a lot of things
you'll do bundle open on will follow Sturgeon's Revelation.
90% of everything is crap. Well, at least you know you have company if you write crap software and I certainly do
from time to time. And that's a great way to learn. I actually find that I learn the most about software and learn the most about what
matters to me, I learn the most about what clarity is when I read poor software. Because what I do is, I take a piece of software, I take a class or method, and then I look at it, how could this be clearer? Like this is, I think this is poorly written. I think this smells. How can I rewrite it? So by just sitting down and going through
that exercise and rewriting it, I find I learn
a whole lot about what I care about. So that's what I've been doing lately. Engaging in a
lot of these internet arguments. Somebody will
submit a piece of code, and usually the submission will come
along with the proposed solution, too, right. I have this shitty piece of code. Then I learned about these three patterns. And now
it's wonderful. And what I have found every single time, and I've only done this maybe a handful of times, maybe a little more, is that every single
time, you just took the shitty code and you stuck it into some different boxes. Like, it didn't actually improve. Applying
the pattern to it did not improve the underlying clarity
of the code, because you just wrote it poorly. Like,
the problem with the code was not that it was missing patterns. The problem with the code
was that it was crap. That it just had to be rewritten. Now, that leads us to sort of a mission, in some ways, from Rails is and what Ruby is, and it leads also to clarify some of the arguments we've had in the Rails community
for awhile. Readability is incredibly important
to Ruby. We have a lot of duplicated methods that do exactly
the same thing, just so we can improve readability. I remember the first time I saw unless, when I was learning about Ruby. That was one of those light bulb moments. It's like, wait
a minute. Unless is exactly the same as if not, but it's a different keyword. Huh. Right? It was not just about making the most efficient, compact language. It was about
readability. Poof! Mind blown. And decade-long love-affair with Ruby established.
And I think that this is what we're trying to achieve
constantly in Rails as well. A lot of people will gripe about, oh, ActiveRecord is too big or
something is too big, or have too many methods. The surface area is too big or there's, whatever
it is, right. Like, who gives a shit? Is it more readable? Is it more clear? That's the only thing that matters. What do I care whether the surface
area of a method is a hundred methods or it's two hundred methods? I don't give a shit about that. The only thing I give a shit about is whether, is the code I'm actually reading,
is the system I'm trying to understand, is that
more clear. When you put clarity as your number
one mission, a lot of concerns just fall by the wayside. It just doesn't matter anymore. And it's liberating. So, I think this actually comes from sort
of the same rope. I didn't have time to write a short letter, so I wrote a long one instead. I think that describes about eighty
percent of all that ninety percent of shitty code. Most people did not take the time to write a short piece of code, so they wrote a long one instead. And then they wrote that
long one, piece of code, and they like, pulled
out their suspenders and like, oh yeah, I'm done.
My tests pass. Boom. Right? Or they look at it and decide, oh shit, this is too long. I must be missing some patterns. I just sprinkle some
patterns over this. Wonders, right? No. What you wrote was
a draft. This was just a first draft, right. Any piece of code you write down is just a draft. Mark Twain actually had the hard job, right.
He wrote in ink. If you actually had to change that, well that was kind of hard, right. So his drafts were a lot more complicated. Ours?
We have it so easy. A text editor? You just delete stuff. And you don't need any of the little stuff that you, you fill over the page and you spill it everywhere and so forth.
An eraser. You can just delete stuff. Like that's my
favorite key. The delete key. It's the number one tool for improving code. Delete key. So when I was in high school, I submitted a bunch of first drafts as essays, and they were really shitty. And of course they were.
They were the first draft. And my teacher at the time said, oh, all right, all right, this
is actually not bad. You just told me the step one. If you have something on your mind, you should write it down. That's what I did. I, I wrote it down. And then I handed it in. Oh, if you've written something down, you should rewrite
it. Oh. That was the step I missed. And I think that's the step most people miss when
they write down code. Cause they're focused on
all these other things. They're not focused on the clarity,
because when you are focused on the clarity, you will realize that all your first drafts are terrible. All my first drafts are terrible. All my first attempts at writing a good class are poor.
They're too long. They're not at the same level of abstraction. They're not clear. And that's
OK. I wrote something down. I was trying to figure out
what the system was supposed to do. That's hard work. And often times you don't
get perfect code out of that when you're still
trying to figure out what it is that you're writing. But once you've written it down, you should
rewrite it. And I think the key part of rewriting is omitting needless words when it comes to regular
writing. When it comes to programming, it's omitting
needless concepts. It's omitting needless patterns. It's omitting
needless practices. It's omitting needless classes. It's omitting all
these extra things that aren't getting you closer to clarity,
right. How do you know? You develop an eye for it. How do you develop an eye? You read a lot of code. You write a lot of code. You rewrite a lot of code. And you forget about fucking patterns for awhile.
You forget about fucking TDD for awhile. And you focus on just what's in front of you. The piece of code. How can I write it simpler? Write software well. Thank you very much.
Wow. He knocked that out of the park.
legoconf for children.
This is a follow-up to the keynote:
https://www.youtube.com/watch?v=z9quxZsLcfo