That's Not Very Ruby of You
This is a modal window.
The media could not be loaded, either because the server or network failed or because the format is not supported.
Formal Metadata
Title |
| |
Title of Series | ||
Number of Parts | 50 | |
Author | ||
License | CC Attribution - ShareAlike 3.0 Unported: You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this | |
Identifiers | 10.5446/37495 (DOI) | |
Publisher | ||
Release Date | ||
Language | ||
Producer | ||
Production Place | Miami Beach, Florida |
Content Metadata
Subject Area | ||
Genre | ||
Abstract |
|
Ruby Conference 201350 / 50
2
3
7
13
15
17
18
19
28
29
35
39
44
48
49
50
00:00
Electronic program guideSpeech synthesisImage resolutionGoodness of fitComputer animation
01:21
Compilation albumProcess (computing)Electronic program guideReal numberChord (peer-to-peer)Inheritance (object-oriented programming)Computer animation
01:59
Chord (peer-to-peer)Beat (acoustics)Lecture/Conference
02:34
NumberComputer animation
03:21
Electronic mailing listReverse engineeringString (computer science)Template (C++)VolumenvisualisierungInstance (computer science)QuicksortAliasingLengthHash functionParsingOrder (biology)Parameter (computer programming)
03:57
NumberFunction (mathematics)Video game consoleClefHash functionInheritance (object-oriented programming)Block (periodic table)Functional (mathematics)WordFrequencyComputer clusterKey (cryptography)Point (geometry)
04:26
Instance (computer science)Attribute grammarBlock (periodic table)Variable (mathematics)Inheritance (object-oriented programming)Instance (computer science)Variable (mathematics)BitPoint (geometry)CodeReal numberAttribute grammarCheat <Computerspiel>1 (number)Multiplication signSineComputer animation
05:08
CodeInterpreter (computing)Formal languageArmInterpreter (computing)Point (geometry)Right angleFormal languageProgrammer (hardware)Extension (kinesiology)
06:04
Social classGamma functionRow (database)SpacetimeSoftware repositoryComputer fileInstance (computer science)Statement (computer science)CodeDialectFormal language
06:51
Right angleFile formatBitCodeWave packetHeegaard splittingWeightMultiplication signArmWorkstation <Musikinstrument>Level (video gaming)SpacetimeFlow separationVertex (graph theory)
07:22
SpacetimeLocal GroupWave packetVariable (mathematics)SpacetimeVideo game
07:50
Process modelingCodeVariable (mathematics)Right angleComputer animation
08:31
Java appletSimilarity (geometry)DistanceWordRight angleProcess (computing)WordDistanceLink (knot theory)CASE <Informatik>CodeObservational studyCalculationNormal (geometry)MereologySlide ruleJava appletGreatest elementLine (geometry)Reading (process)Metropolitan area network
09:32
Procedural programmingGoodness of fitCodeData miningVideo gameLogicFormal languagePoint (geometry)Adventure gameReading (process)
10:34
Physical systemKolmogorov complexityLine (geometry)Binary fileEmailDependent and independent variablesLine (geometry)TouchscreenConstraint (mathematics)CodeOnline helpReal numberPhysical system
11:18
VacuumFunction (mathematics)Module (mathematics)String (computer science)Social classAttribute grammarQuicksortModul <Datentyp>Utility softwareSocial classModule (mathematics)Endliche ModelltheorieAttribute grammarHash functionLogicLibrary (computing)Electronic mailing listObject (grammar)Computer animation
12:07
Attribute grammarBroadcast programmingSocial classCASE <Informatik>Attribute grammarLevel (video gaming)Code refactoringRight angleGoodness of fitTerm (mathematics)Point (geometry)Casting (performing arts)Cellular automatonArithmetic meanReading (process)Object (grammar)Exterior algebraFactory (trading post)Endliche Modelltheorie
12:51
Computer programmingExterior algebraEndliche ModelltheorieObject (grammar)Computer programming
13:21
Object (grammar)Term (mathematics)Descriptive statisticsRight angleEndliche ModelltheorieRule of inferenceElectronic mailing listSocial classCodeDiagram
14:16
Game theorySeries (mathematics)Right angleCharacteristic polynomialData conversionHand fanGroup actionModule (mathematics)Social classRandomizationSpecial unitary group
15:08
Group actionGroup actionRandomizationModule (mathematics)
15:46
Line (geometry)MereologyFormal languageHand fanWritingLine (geometry)Computer fontMereologyModal logicVirtual machineWordComputer animation
16:20
Power (physics)ExpressionFormal languageTerm (mathematics)Power (physics)ResultantRight angleMetropolitan area networkCivil engineeringCuboidComputer animation
17:07
Power (physics)Patch (Unix)Line (geometry)Formal languageMultiplication signWordRight angleMeeting/InterviewComputer animationXML
17:56
40 (number)ExpressionObject (grammar)Subject indexingExpressionObject (grammar)CodeLine (geometry)Goodness of fitPoint (geometry)Right angleLocal ringNegative numberQuantum stateSign (mathematics)Element (mathematics)2 (number)Array data structure
19:23
Patch (Unix)Address spaceObject (grammar)Right anglePatch (Unix)Address spaceMobile appPattern languageSymbol table
20:01
Social classMacro (computer science)NamespaceSocial classWritingFunctional (mathematics)Order (biology)Right angleMacro (computer science)Patch (Unix)Object (grammar)Cartesian coordinate systemComputer programmingSpacetime
20:43
WeightInverse elementModule (mathematics)Computer configurationRight angleSocial classCodeProgrammer (hardware)Macro (computer science)Cheat <Computerspiel>Pointer (computer programming)Computer configurationDifferent (Kate Ryan album)Goodness of fitInverse elementPoint (geometry)Branch (computer science)Computer-assisted translationNumberRevision controlObject (grammar)Module (mathematics)Parity (mathematics)Computer fileMereologyMathematicsLogical constantDefault (computer science)Variable (mathematics)Arrow of timeImplementationLine (geometry)Message passingString (computer science)Instance (computer science)Equivalence relationDependent and independent variablesDecision theoryCoefficient of determinationWordRule of inferenceRow (database)
24:36
Rule of inferenceIdempotentSocial classMacro (computer science)Rule of inferenceIndependence (probability theory)Multiplication signInformationComputer configuration
25:13
Order (biology)Independence (probability theory)Independence (probability theory)InformationMacro (computer science)ImplementationSocial classObject (grammar)Sign (mathematics)Web page
25:54
FreewareIdempotentSocial classRule of inferenceMacro (computer science)Object (grammar)Macro (computer science)Social classStrategy gameRight angleRule of inferenceSet (mathematics)Intelligent NetworkComputer animation
26:33
Rule of inferenceWritingMultilaterationRule of inferenceRight angleTerm (mathematics)CodeGoodness of fit
27:05
Library (computing)Right angleFunctional (mathematics)System callKey (cryptography)
27:48
Right angleCode
28:20
LaserRight angleRule of inferenceChainMacro (computer science)Inheritance (object-oriented programming)System callLaserBlock (periodic table)
29:01
Asynchronous Transfer ModeArmMultiplication signRight angleNetwork topologyInformationSocial classMilitary baseAsynchronous Transfer ModeCodeCASE <Informatik>String (computer science)System callOrder (biology)Disk read-and-write headWave packetReverse engineeringImplementationRow (database)CausalityNP-hardLambda calculusBuildingComputer animation
31:06
Video gameInclusion mapExterior algebraExtension (kinesiology)Computer clusterExpected valueRight angleFreewareFunctional (mathematics)Interface (computing)Parallel portComputer animation
31:51
Module (mathematics)Inheritance (object-oriented programming)LaserIdempotentRule of inferenceCodeSystem callWordObject (grammar)Order (biology)Multiplication signRight angleRule of inferenceImplementationInterface (computing)Speech synthesisHierarchyEndliche ModelltheorieLaserComputer configurationInheritance (object-oriented programming)Social classModule (mathematics)MathematicsReal number
34:10
LaserObject (grammar)Kernel (computing)Right angleChainOrder (biology)Inheritance (object-oriented programming)HierarchyObject (grammar)Instance (computer science)CodeStructural loadProgrammer (hardware)WordCurveArtificial neural networkComputer animationMeeting/Interview
34:57
Reduction of orderStructural loadCognitionStructural loadMultiplication signCodeCognitionPattern languageGoodness of fitRight angleMacro (computer science)Programmer (hardware)ImplementationComputer programming
35:25
Pattern languageMultiplication signFormal languageArithmetic meanRight angleWordLecture/Conference
36:20
SoftwareVideoconferencingEvent horizonComputer animation
Transcript: English(auto-generated)
00:16
Good morning! Wow, now it's all downhill from here. I am really, really excited and blessed
00:24
to be here with you all today. I just started doing talks this year. You may know that if you've seen any of the other ones. And I never in a million years thought when I made a New Year's resolution to speak that by the end of the year I would be here with some of the best minds in the community that I call home.
00:42
So I'm really psyched about that. It's weird because in previous years I had always found myself being asked, like, what's your talk on? I'm like, I don't speak. What are you talking about? For whatever reason, this year most people have been asking me two questions. Who are you? And, oh, you're speaking? And so yesterday morning I had the opportunity to meet one of our opportunity scholars
01:05
and her guide. And I was talking to the guide and I introduced myself. He says, oh, Ernie Miller, I know you. Why do I know you? And I'm thinking, yeah, yeah, finally somebody actually knows, like, what I'm doing here. And he says, you're the bird
01:22
guy! So I may be the bird guy to you. That's OK. I think that's pretty cool. Lord of the birds. Lord of the gulls. You should totally ask me about Appriss. I just started working there about three
01:40
weeks ago, and it's a very meaningful job that I'm doing. We literally save lives, and they were so awesome to be like two and a half weeks into my employment. Sure, yeah, we'll send you to RubyConf, no problem. I would very much like them to continue to do things like this for me, so ask me about Appriss. So if you were at RailsConf, you saw Aaron's keynote. It was A flat,
02:04
and it really, let's just say, it struck a chord with me. I mean, it really set the bar. It made me want to be a better coda. All right. All right.
02:25
More than a fugue of you looked to be getting tired of this. I better stop fiddling around before I beat it to death. OK. Let's duet. So this is going to be my keynote. I really thought really long and hard about it. It's C
02:40
sharp. You, you may have heard of it. I think it's gonna be huge. It's gonna be, it's gonna be awesome. So what is Ruby? That seems like a really kind of silly question to ask a room full of Rubyists. So I ask it because, like, is this Ruby? No. That looks like C to me.
03:03
It looks like C written by somebody who sucks at it. How about now? Is it Ruby? How about now? It runs. Oh, it gets worse from here, guys.
03:22
How about this? Is this Ruby? I think we all can agree we're thankful that it's not. What about now? What about now? Is it Ruby? So,
03:43
so, one thing, this is obviously very different from PHP. The, the method naming and argument order is much more consistent in this. So. It runs. How about this? What's this look like? Is this,
04:02
is this Ruby? What if I change the function keywords to stabby lambdas, and I add a period before that check over there? How about now? I'm especially proud of this comment. All right, one
04:27
more. I think I'm making my point. How about this? So I learned something about Python. I haven't spent a lot of time doing Python. That it's basically just a bucket of attributes. You can assign anything to anything, essentially. I was kind of surprised
04:44
by that. There's no, like, real instance variables. OK. You might say, you might say that using a one, I'm not sure if you can tell, these are ones now. You might say that's cheating. I say it makes it extra elite, personally. Is it Ruby now? This tiny little bit of
05:03
code here. It makes it work. One more question for you. If your code has a syntax error, does it stop being Ruby? So
05:21
I guess the point I'm trying to make is that I don't believe that it's the interpreter that decides what is and isn't Ruby, right. I think it's the people. And that's cool, because Matt's designed Ruby to increase programmer happiness, right, and interpreters don't get happy, right. People get happy.
05:43
So then the answer to what is Ruby is duh. Ruby is a language. But what is a language, really? A language is a tool for telling stories. And so, by extension, then, that makes us storytellers. And I mean, even when you
06:01
think you're not telling a story, you're telling a story. For instance, anybody that's working on a team has probably opened a file in their repo to something like this. It tells a story. Or this one. This one, this one here, just
06:22
cries out like, I have no idea how I'm going to make this work. All kinds of put statements all over the place, commented out, left in. And if there was any doubt that Ruby is a language, it also has dialects, right. So you all may be familiar with this style of coding. It tells a story as well.
06:51
So before we go any further, I want to talk a little bit about some nits that I want to pick. I don't want to waste anyone's time, but you know, they did let
07:00
me come up here on stage, so I'd definitely have to pick a few nits. Does this make you recoil? It makes me recoil when I see it, right. So one thing that defines Ruby for me is the way that we format our code, in a lot of ways. This makes me feel a lot better, like, just seeing it like this, right.
07:22
Soft tabs in two spaces. That's the way we format. The, the train has left the station. Sorry, people that want hard tabs. And also, if you can use vertical space to separate ideas, you'll make life much, much easier for your coworkers. Here's another thing that really drives me nuts. Really
07:42
makes me crazy. I'm not sure if there's like a byte shortage or something, like, we need to, we need to save the bytes, but if it's not self-explanatory, your variables are definitely not x. Unless, you know, right.
08:00
OK. Here's another one. I'm sure you guys now are like, oh, you don't want short variable names? I'll show you. Yeah. You're very original. Though, to be fair, I would much rather
08:21
see that than x and i. Oh, how about this one? You've seen Ruby code like this? Uh huh. Every day is hump day. Right. So, we have a lot of refugees from Java in our community. I don't
08:43
know why they would really want to bring that baggage along with them, but also there's a link down in the bottom that'll be in the slides when we put them online. It's a study about how camel case is actually slower to read. And we read, we read and pick out parts of code much more frequently than we write
09:01
it. So, optimizing for readability. Again, we're storytellers. This is another one. Explicit return. I don't know why it makes me so crazy. It's just like, extra words. Not necessary. Everything has a value. Simplest case. You can remove it. More likely, if you're a Rubyist, you're gonna say something like this. You're gonna actually just return a hundred
09:22
at the beginning, say, OK, we're gonna normalize to zero to a hundred, and avoid that more expensive normalized distance calculation. Everything's backwards, but it's gonna be all right. So those are my nitpicks. Let's go on to some baggage that we bring. I came to Ruby from Perl, which is a much more
09:41
procedural-style language. A good friend of mine, and you know, it's not uncommon for us to write things like this in more procedural-style languages, if we're making our life miserable for good reason. And a friend of mine used to describe my code back when I was writing Perl as looking like a spaceship. And, he's right. It does. It
10:06
totally looks like a spaceship. If you zoom out especially, it really does. You know, that tells a story, too. It's trying to decipher, trying to decipher this code is like
10:22
reading a Which Way book or a Choose Your Own Adventure book from front to back. It, it's very, very difficult to make sense of. So I guess my point there would be that, you know, in procedural languages, we tend to just kind of create these buckets of logic, and we just throw them in a method, and that's all we do. You can't have that. That's not good. One
10:42
thing that I've used, and this is gonna get some mixed response, I assume, but, is 80 column lines. That's a constraint I put on myself. Not because, like, screen real estate is that expensive, but it's an early warning system. And also, again, I talk about making code more readable. We are storytellers. Do you open up
11:02
a newspaper and look at it like this? I mean, I don't. I, I read things much easier when I can scan lines, and, and so I think that short lines help. If nothing else, it stops you and makes you think, do I, am I really, if it starts to get uncomfortable, am I really doing the right thing here? Here's something else I used to do. We
11:23
create these sort of buckets of methods because we don't know where the things need to live, and we make a utility module or a utility class. You can't have buckets of methods. That's not OK. And class is a descendant of module. So it's important to remember that what applies to module also applies to class.
11:42
Something else that we tend to do, we think, and I'm not gonna name names here, certain, certain libraries maybe have hashes that they use for, for lists of attributes that are assigned to a particular object. That works out OK at first. And then you decide you need to typecast those attributes. And so
12:02
now the typecasting logic lives on the thing that's holding the hash. You can't have buckets of data either. And something that you might want to do instead is to have an attributes object, right, because that's what we do. And then it can handle that casting for you. But we don't normally see it in these kind
12:21
of isolated cases. Usually we, we get to some place like this first. Don't read it. It's just gonna hurt you. We normally catch, catch ourselves around this point. And thinking about, in terms of objects, helps us to get from this to this. Now I'm not saying this is a good refactoring
12:40
necessarily, but it does at least mean that someone has given some thought to creating some objects, right. I'm not sure this is the right level of refactoring, I guess is what I'm saying. But it's certainly better than the alternative. So you may be saying, that's way too many objects. And, again, I'm not arguing the modeling
13:00
is perfect. But we are working in object oriented programming, are we not? If we were doing awesome oriented programming, would you be telling me, that's just too much awesome. We can't, we can't have that much awesome. And, and modeling is really where the magic happens. It's where you move from these buckets of things
13:24
and you start to begin to, to describe things in terms of objects. You go from a descriptive description of the situation to being prescriptive. To being able to say, here is my mental model, right. It's the value in doing this modeling activity is that you get to go ahead
13:41
and reframe the problem, right. And it's all about naming things. So we all know Sandy's got a list of rules that is about creating more maintainable code. And we love rules as a community.
14:02
I think one of the biggest payoffs of following rules, like having short method names, having short class names, is that it forces us to give names to the code. Any Game of Thrones fans out there? Yeah? How
14:21
many of you actually read the books? All right. I'm gonna find out if you're lying later. All right. So have you ever tried discussing the Song of Ice and Fire series with someone? It's, it's tricky, right. There's a lot going on. You want to do it in hard mode? Try having a conversation about a Song of Ice
14:40
and Fire without using any names. Just describe the, you know, this guy over here who's the song, you'd have to go all the way back to the beginning, right, to describe anything. But the names are what we attach characteristics and relationships to. I can say Tyrion Lannister. You know who it is. I can say Red Wedding. You
15:02
know what I'm referring to. And if you're just watching the show, I'm not gonna explain it. We're storytellers. Putting things in random buckets doesn't work. You need to name your characters, your classes, your modules. You need to name their actions and the methods that they, they perform.
15:20
We find it hard to name things because naming something requires us to have some idea of what we think it's going to be. But the naming often comes before the knowing. Don't get too hung up early on. We all know you can change names. OK, a few of you actually read the
15:41
books. You know what I'm talking about. So if we are storytellers, here's a, here's a book for us. We've all probably had a look at it. Oh, hey. Wow. It has fans. OK. Who wouldn't have thought. There is a, there is a paragraph in that book that I think applies to coding
16:01
as much as it applies to, to any other kind of language. Vigorous writing is concise. A sentence should contain no unnecessary words, a paragraph no unnecessary sentences, for the same reason that a drawing should have no unnecessary lines and a machine no unnecessary parts. This requires not that the writer make all sentences
16:23
short or avoid all detail and treat subjects only an outline, but that every word tell. We get really, moving on from baggage from other languages, in the Ruby community, we get very, very focused on expressiveness. We like to throw that term around, right. And it's an extremely powerful
16:44
language. We can redefine things to do exactly what we want them to do with mixed results. Ruby reads beautifully out of the box, and it also gives us this power to extend the languages we require. In fact, I think that its flexibility is one of its most endearing qualities.
17:01
It gets out of the way and lets you tell the story that you want to tell. It's one of the things that makes me really happy. But if there's one thing we've learned from Peter Parker's Uncle Ben, it's that with great power comes great responsibility. So let's talk a little about monkey patching. Yeah.
17:25
Heaven sighs very loudly. All right. So somewhere along the line, we started to get the idea that expressiveness is the same thing as making it English-like. The thing about it is, is Ruby is a language of its own. Just like English, right.
17:41
In English, we borrow words like cappuccino, like espresso, right. But it doesn't mean that for the entire time that we're in the coffee shop, we must speak Italian. Ruby borrows language from English when it makes sense. So we know arrays have a first and a last method, right. We can refer to
18:01
the first or last element in our array. It's handy. So along comes someone, and says, well, if first and last are good, let's have second and third and fourth and fifth, and forty-two, not forty-second, because that gotta be, that has to be better, right.
18:23
I say, why stop there? I mean, array penultimate? Array anti-penultimate? Why not? I mean, it works. Look how expressive. If only there were some way that we,
18:40
as people, could, could index into any element in the array so that we wouldn't have to define all these methods. I mean, I don't know, like, we could use, like, positive numbers to go forward, negative numbers to go from the back. It would be really handy, wouldn't it? So
19:00
we all know we can ask an array to tell it if it includes an object. At some point along the line, we decided it would be better to ask the object whether or not it's in something. This is simplified from the real code. And I mean, I guess it reads like English, right. Second in array. But there's one
19:21
problem with this, right. Objects should be in the dark about where they're living, right. You ask an object to tell you whether it contains something. You don't ask an object to know what, I mean, this sounds like, super like philosophical, right. For an, for an object to find itself, right.
19:41
The container knows what it, what it contains. So here are a couple of questions you might want to ask yourself before you monkey patch. Does it address a real problem? You know, maybe it simplifies a pattern you see all over your app. Symbol to proc is a great example of this, right. I love that. That came from a monkey patch.
20:02
Does it follow OO principles, right. Does it make sense for the method to live in the class you're patching? Are you adding functionality to a class in order to use it as a stand-in for a real object? That's a no-no. That's a really smelly smell. And this is pertaining to applications, right. If you're writing gems on top of that, you also want to be very careful that you're not
20:21
stomping all over, you know, namespaces that other people might want to use. So with that in mind, let's talk about class macros. This is something that we love in the Ruby community, right. The fun thing about metaprogramming is that the problem is boring. Writing the program to solve the problem makes
20:41
it more interesting. We like interesting, right. And it's, it's been said that good programmers are lazy. So if we can write code that writes code for us, it's a win, right. I mean, plus let's face it, class macros, they're just plain cool. They really feel like you're cheating.
21:01
And when you first discover you can do it, it's so natural to get carried away with it, right. And Ruby comes bundled with a perfect example of a class macro, right. AfterReader, WriterAccessor, these are great class macros. I mean, they save us a lot of busy work, right, and they're very declarative. All right. It's a good thing.
21:24
ActiveRecord has class macros. HasManyPosts. I'm actually OK with that. I mean, something hasManyPosts. I'm OK with that syntax. I'd even give a pass to inverse of user, right. OK, you're still kind of describing what it is.
21:41
But we all know that that's not what happens, right. This is what happens, right. I'd like to point this part out in particular. That's fun. All right. This is not, not a good class macro when it has to do this, right. Here's another example. We have delegate. This is the
22:03
active support version of delegate, not forwardable or simple delegate. Pretty straightforward. Delegates work to owner, which is what cats do. You can prefix it. Still describing what it is, I think, at that point. It's a little lippy, but I'd say OK. But then there's this
22:23
option allow nil, where a whole bunch of extra behavior comes in, right. For instance, if you say allow nil, if the option's not set, and you have a nil there, it immediately raises an error. If it is set, it delegates to nil if nil happens to respond to the method, but otherwise it just returns
22:42
nil. And you can see this kind of indecision in the implementation. Again, this is small for a reason. You don't want to read it. I'm protecting you. I'm gonna put some arrows in here. These are all the branching points in the code. These are all the places where the code branches off to, to make a decision, right. If prefix is true instead of a string,
23:01
for instance, it'll use the value of two as the default prefix. But only if you're delegating to a method name. Not if you're delegating to an object that's an instance variable or a constant. It also checks explicitly for a two of class and prefixes it with self so you're not referencing the keyword. All right. If we were to make a few minor changes to this API, and again, for parity
23:23
with the one that was there, we'll just keep that in module. We can reduce the number of branches necessary to something like this. We split out the allow nil behavior to a different macro, and we say, OK, this is a different thing, right. It's, it's different. And we can kind of simplify the method
23:41
that we actually use. I mean, it's, it's now, it's now one line. This is the one line method that we generate. And neat thing is we can dogfood it inside an object to delegate those things to nil that nil responds to. We keep the same behavior. I'm not arguing this is the right behavior. I'm arguing this is, you know, equivalent. So it's something to think about when you're writing
24:01
class macros. Maybe you actually have more than one thing. So how about this one? Right. This must be great because it has no options, right. This is horrible, right. Because Ruby already has class macros that do this for us. This is what they're called. And if you really, really need
24:22
to make use of the hooks, go ahead and make use of the hooks as well. It's OK. I mean, it's better than adding new vocabulary that nobody's gonna know. And they don't now know where the file is to look for. So everybody loves rules, right. We talked about it earlier. In the Ruby community, we love rules.
24:41
So here are five rules that we can apply whenever we're considering whether or not something needs to be a class macro and how to implement it. In my opinion, they let me give my opinion while I'm up here. This is cool. Class macros should first off describe what, not how.
25:01
They should be item potent. If you run them multiple times, running the same class macro is not going to change things repeatedly. They should be order-independent. If you run the same macro with slightly different options, then it should be building some aggregate
25:22
amount of information versus changing what you had said earlier. Because that way you can reason about each thing independently. They should be straightforward. What you, what you see should be as close to what you get as possible. You shouldn't necessarily get surprised by what
25:41
happens, is a better way of saying it. And you shouldn't have to comb through pages and pages of documentation just to understand how to use a class macro. That's a really good sign that this would be better, better factored into some objects. And lastly, both the definition and the implementation should be free of branching, if possible.
26:00
So if you're branching a lot in the macro implementation, there's a good chance you have more than one macro, which I mentioned earlier. Or maybe a macro that takes a class or an object to be a strategy. So here's the rules again. And most of you probably are saying, that's impossible. I would say it's not necessarily impossible, in that those built-ins that I said, attr-reader, attr-accessor, and so forth, they actually
26:23
do this today. They, they satisfy all those criteria. But I'll admit, I'm kind of screwing with you. Obviously, like any set of rules, it's OK to break them if you have a reason, right. That's what makes it fun. I'm breaking the rules. Look at me. I'm wild.
26:40
It's really about happiness, right. A good reason to break the rules is if you're going to increase the happiness of the users of your code. Short-term is good. Long-term happiness is better. Think about the people that are come, kind of come along and read this stuff later. Not just the fact that you saved some keystrokes on the writing.
27:01
And you know, there, there are two kinds of surprises, right. There are good surprises. OMG, this works so well. So intuitive, right. Let's talk about callbacks. We love callbacks. And you know, I hate to
27:22
keep harping on callbacks, but the thing is, is there are a lot of libraries out there that have actually taken the active support style of callbacks and begun to re-implement that functionality, right. And you'll see, it's like, these callbacks are inspired by active support style callbacks. So this is, this is happening
27:42
frequently enough that I think it probably needs to be reiterated. So here's someone using callbacks. Oh, here's a before save. You know, here's, here's an after save. Around save. Holy heck, what is this? Why is my code all awful? Everything is terrible. Everything is
28:03
miserable. I don't even understand. Right. Right. That's not funny at all.
28:20
So let's assume we have a base class, for of course the only real reason we should ever have a base class, to model a military base with lasers, right. So with callbacks, you call
28:40
one macro to name the callback chain. Then you add callbacks to the chain with set callback. And then in the methods that actually want to take and use the callbacks, you have to wrap everything in a block, a run callbacks call, and then it yields to your code, right. So let's compare that to the rules. All right.
29:12
So if you're pointing at a method name, it might actually describe what. If the method is well named, you may be describing what, right. But if you make two calls to set callback,
29:21
you're gonna get two identical callbacks. You're gonna repeat the work. So they're not idempotent, right. And the order you define the callbacks in is the order they're gonna get called. Unless you're doing an after callback, in which case it's the reverse order, or an around callback, in which case they wrap each other in ways that look like the before and the after.
29:42
And I mean, straightforward, definitely not. And you've seen some of the implementation. By the way, Aaron did an amazing amount of work refactoring the callback implementation in ActiveSupport. If you saw the ActiveRecord talk that I gave before, where we talked about the implementation being very string heavy, building up these strings, he
30:00
refactored it to be probably about as good as something like that is ever going to be. Thank you so much, Aaron, for, for that hard work, cause it was not easy. Can we give him a hand? He's over there hanging his head. He's like, uh, it's horrible.
30:21
All right. So here's where it gets really interesting, right. I talk about how it's branching. It's branching so much it's an honorary tree. We can say, sorry, go back. We can say, and I took my own advice and said arm weapons instead of giving a lambda there. But we
30:40
can say if not armed, we can say unless training mode, right, and then we won't auto-arm. And then we can have other calls in, say, subclasses, like secret bases. And they can skip callbacks, again, with an unless or an if, controlling whether or not the callbacks get skipped. So we're treating
31:02
this code as kind of a big blob of stuff, right. And we're, we're, it, it turns out, really, that it's not just tricky to rock a rhyme to rock a rhyme that's right on time. It's, it's also tricky to use callbacks in a way that doesn't ruin your life. And we have, we have alternatives, right. We have, we
31:23
have these, these, these wonderful things. Inclusion, extension, pre-pension. And you know, it's OK. It's OK for your characters, the characters in your stories, to have demands and expectations of one another. Have you ever included enumerable and defined in each? Right. You've benefited
31:42
from this. You're defining an interface, right. You're just done, you have an interface, and you, you, you conform to it, and you get all this great functionality for free. So we might potentially consider, apparently, this thing's a little crazy. We might consider doing something like this. It's
32:04
gonna blow your, blow your method cache, by the way. Don't do this, like, for real. But like, it is an option. You can extend something, like, you can have an auto-arming method that simply calls super, or an auto-arming module that simply calls super on its fire lasers method. You implement fire lasers on the thing that extends it. You can get that behavior, that same
32:21
behavior that we, we just had before. Better in Ruby 2, which you're all running now, right. Yeah. It's, it's so much better. You can simply prepend, prepend auto-arming, get the same behavior. And if you have rules, like, about whether something
32:41
should auto-arm, you can, again, define an interface, right. You can say, like, OK, so when you, when you extend or you prepend auto-arming, you get this should auto-arm that's automatically set to true, but if you want to override that in a subclass, you're totally cool to do that. It's gonna determine whether or not, you know, you should actually do the thing or not.
33:01
So you can get that same behavior in a way that's readable. So if we compare the rules that we looked at again, it definitely defines what not how, because all you can do is say the name of the thing that you're, you're extending or you're, you're prepending, right. It's idempotent. You include, you extend, you prepend.
33:20
If you do it a second time, it's not gonna change the inheritance hierarchy of your object. And speaking of, you know, it does sort of depend on the order. Like, I mean, it might if, depending on the implementation, right, certainly it can be order dependent, right. Whatever you're calling in super is gonna, again, because it's, it's related to the
33:41
inheritance hierarchy. It's straightforward, though. I mean, you know exactly where to go look for that code, right. No surprises there. And it's about as, as free as you're going to be at branching, in that you have the keyword, you have, you have the, the class or the, or the module that you're extending or prepending or whatever. That's about as much as you're gonna
34:02
be able to do. Now certainly implementations can vary, but that's not my problem. So the other huge win with this, right, is like, with callbacks, how do you really know the behavior that's attached to something? I mean, you can ask for the callbacks and you get this, like, array-like thing, callback chain.
34:22
But if you're actually adding things to the inheritance hierarchy of the object, you can start to ask about what that object has. And you can see, for instance, the order that things are being executed very easily. And it's just Ruby, right. Like, it leverages stuff,
34:41
it leverages stuff that we already know, which is, brings us back to making every word tell, right. Like if somebody already understands a concept, why create an artificial learning curve for them? Is there, is there value there? I don't know. I mean, to me, I think that's really what it comes down to. You can reduce the cognitive load for
35:02
understanding, for understanding code, and that is a bigger win. Like, if, if good programmers are lazy, then, I mean, this is, this makes you a great programmer, right. Because you're gonna read this code much more often than you're gonna write it. And if you make it more readable, then every time you go back to it, you won't have to wonder, oh, how was that macro implemented
35:22
again? Now look. It's obvious that not one pattern is going to apply everywhere. OK. I'm not advocating that you just blindly go, you know, Ernie said, do this, and so I'm gonna go do this, right. It's totally OK. It's really fine that, and stories,
35:43
stories would be really boring if they were all the same. What I'm asking you to do is think. Think about the story that you're trying to tell. We're storytellers, right. I mean, and Ruby is such a wonderful language, a wonderful tool for telling stories. I love it. I mean, I,
36:02
I'm a little bit, maybe too passionate about it at times. I mean, I go to other languages and I'm just like, I wish I had what I had in Ruby. It's an awesome tool for telling stories, and I'm so grateful that we have it. So put thought into what you're trying to say, and make every word tell. That's all.
36:26
That's it.