Null Object Pattern
Closing Keynote: You Gotta Try This
Summarized using AI

Closing Keynote: You Gotta Try This

by Avdi Grimm

In the closing keynote titled You Gotta Try This at the LoneStarRuby Conf 2013, speaker Avdi Grimm presents an engaging exploration of meta programming in Ruby and the joys of coding. The primary focus is on his toolkit for building null object classes in Ruby, which enhances coding efficiency and developer happiness.

Key Points:
- Introduction to Null Objects: Avdi explains the null object pattern and its purpose—simplifying code by implementing a dummy object that responds to method calls without performing any actions. This allows developers to eliminate repetitive checks for object presence.
- Benefits of the Toolkit: Although creating a null object class can be achieved without a library, Avdi emphasizes that his toolkit simplifies this process, making it easier to implement variations of the pattern.
- Variety in Null Object Patterns: He introduces advanced concepts like a black hole IO object, which facilitates method chaining, and a traceable null object for debugging scenarios.
- Joy in Coding: Avdi shares personal anecdotes highlighting the transformative influence of Ruby on his coding journey, comparing his early cubicle life with the vibrant Ruby community. He reflects on the thrill of meta programming and how certain music can evoke profound emotions akin to coding joy.
- Pair Programming Initiative: He advocates for pair programming as a means of sharing joy and enhancing community engagement, encouraging attendees to connect with new partners and promote collaborative coding practices.
- Interface Subsetting in Code: Avdi discusses the importance of tailoring interfaces in his toolkit, illustrating how to filter methods for a specific use case sequentially.

Conclusions:
- Avdi encourages attendees to seek joy in their coding practices, highlighting that frequent engagement with enjoyable programming activities fosters greater effectiveness.
- He emphasizes the importance of sharing joy within the community, concluding with a call to action for participants to connect through caring cards to facilitate pair programming opportunities. Avdi’s dynamic presentation underscored the importance of community, joy, and the continued exploration of Ruby's meta programming capabilities, aiming to inspire the audience to find and share their coding passion.

00:00:21.279 I want to show you some ideas. A little while ago, I wrote a toolkit for building null object classes in Ruby.
00:00:28.119 Now, don’t worry, this is not one of those talks where I show you a library that I just wrote and tell you all to use it in your production apps. It's not one of those talks. I just want to share some of the fun parts of building this library, some of the things that made me happy.
00:00:35.760 Quick show of hands: who here does not know what a null object is? A couple of people. For the benefit of those who aren’t familiar with the null object pattern, here’s a really quick introduction. Here’s a method that does a lot of logging, and it may or may not have a logger depending on whether someone passes one in. It keeps checking to see if the logger is present before it can use it.
00:01:02.640 Here’s a null object implementation of a logger interface. This object will respond to any of the usual logger methods, but it will do nothing with them. We can take that and apply it to this method and make that null logger the default. This enables us to get away from constantly checking to see if the logger is there.
00:01:10.119 We can confidently call those logger methods, and if it's a real logger, it will work, and if it’s a null logger, it simply does nothing. A null object is essentially a way to simplify certain kinds of code. As you've seen, we do not really need a library for building null objects because we can just build one. So, why build one? One reason is that I wanted to make easy things, easier. This is the equivalent code for building that same null class. We just say 'k.build' and 'conf.mimic_logger,' and it will mimic that logger interface. It’s a little bit simpler and shorter.
00:02:10.520 Another reason I wanted to do this is that there are several interesting variations on the null object pattern. For instance, here is a black hole IO object. It is an IO object, but beyond that, it acts as a black hole, meaning it will return itself from any method that is called on it. This allows us to chain methods infinitely, which is nice to have if you’re doing IO.
00:02:45.599 The second example is a traceable null object. This null object knows what file and line it was created on, and this is handy if you are debugging and trying to figure out why you have a null object when you expected to have one.
00:03:10.640 I would like to tell you that in implementing this library, I had a solid business case, an application that required null objects all over the place, and I extracted this code out. However, that would be a lie. I have a confession—a bit of a dirty little secret. The truth is I just love meta programming. I think it's fun. Different programmers find different things fun. Katrina talks about therapeutic refactoring—refactoring just for the sheer pleasure of it. Some programmers enjoy code golf, reducing a program to the smallest possible number of characters. This is, believe it or not, a to-do list application in 140 characters.
00:04:04.799 I meta program for fun, and if you’re going to meta program for fun, Ruby is a pretty cool language to do it in. After all, it is a language that was created to increase developer happiness, and it's equipped with nice features for meta programming. Of course, you can meta program in lots of languages. In C and C++, you do it with pre-processor macros or template meta programming. C# and Java have elaborate reflection APIs, and Lisp is legendary for the kind of meta programming you can do with macros.
00:05:13.240 The trade-off you make there is that you have to write your code in the format that those macros manipulate. The commonality among all these languages is that there are kind of two levels—there's the code level and then there's the meta level. Meta programming in Ruby is a bit different because you can take an array, ask it how big it is, and it will tell you, which is the ordinary programming. Then you can also ask it what other messages you could send to it, the same way you asked how big it was, and that’s really meta programming.
00:06:41.600 That meta message will respond with an array, and you can ask that array what its size is, and so on and so forth. The point here is that it's all kind of mixed together. There aren’t separate levels of regular programming and meta programming. I feel like Ruby has a punk rock meta programming ethos. When Ruby decides to sew a new patch on its jeans, it just sits down and sews the patch on while still wearing the jeans. Sometimes it sews the jeans to its leg, but mostly it works.
00:07:30.700 This makes meta programming in Ruby really accessible, and I think that's probably a big part of why I enjoy it so much. Anyway, back to the code. Obviously, this toolkit for generating null object classes is going to focus heavily on generating classes. In Ruby, when we want to create a new object, we send the 'new' message to the object class, and when we want to generate a new class, we send the 'new' message to the class class. There are no two different levels—you’re not entering another language here; it’s all the same.
00:08:49.480 If we want to specify that we derive from a particular base class, we can pass in that base class as an argument. When we generate classes in this fashion, they come out anonymous. They come out kind of ugly—they don't have a name, they just have a number. But the first time we assign one to a constant, it takes on the name of that constant and from then on, knows its own name. This is a little surprising at first, but it’s very convenient.
00:09:58.520 So this is the first part of generating a null class—it’s going to be just 'class.new' and we’re going to pass in our base class. If we base these on BasicObject, it seems like a good default behavior for a null object would be to respond to any message with nil and do nothing. It should also report that it will respond to any message. How do we do that? Well, it turns out to be incredibly simple. First of all, we implement 'method_missing' to respond to any missing message.
00:11:17.080 If you’re not familiar with the syntax where it’s just the lone asterisk, that means it’s accepting any arguments and doing nothing with them. I have seen that called the Naked Splat, but it occurred to me this morning that this could also be called the Lone Star. To complement this, we also implement 'respond_to?' which accepts any arguments and then just responds true to everything. That’s it—that’s the core of our null object class generation right there. Just a few lines of code; it's an incredibly simple piece of code.
00:12:10.599 This stuff makes me happy, and I've been thinking about happiness and joy lately. I've been considering what sorts of things bring me joy. When I think about that, one of the first things that come to mind is music. Has anyone seen the movie Garden State? This is one of my favorite movies.
00:12:58.720 There’s this scene in that movie that has always stuck with me. Relatively early in the film, Natalie Portman’s character meets Zach Braff’s character in a doctor’s office waiting room. She’s listening to music on this great big pair of headphones and says, 'You’ve got to hear this one song. It will change your life—I swear!' She gives him the headphones, and this statement, the reason the scene sticks with me, is that it sums up how I’ve felt about a piece of music. It’s the joy that music has brought me.
00:14:03.400 I think about this: has a piece of code ever brought me that kind of joy? Can code change your life? As I thought about this further, I realized that Ruby changed my life. I used to work at a big faceless corporation. I wrote a lot of C++ and even some Visual Basic. I lived in a cubicle and filled out my share of TPS reports. Then I learned Ruby, and it was fun.
00:14:56.000 But there was more to it than that. I got involved in the Ruby community, met people who were organizing meetups just for fun. I met people who were organizing conferences just for fun. People who were optimizing their lives for happiness and also those who were optimizing their jobs for happiness. From there, that led me down this long road to this moment, where I am a much happier hacker today than I was back then—because of Ruby.
00:15:31.600 Now back to the code. So far, we’ve been building these null classes on BasicObject, but I realized I wanted to enable users of this library to vary the base class. Maybe they want it to be based on Object instead of BasicObject. Another feature I wanted to support is something called impersonation. The idea of impersonation is that you’ll sometimes have a piece of legacy code that has hard-coded type checks, and if you want to introduce a null object into that code to pass through those checks successfully, it will need to actually be the class those checks are expecting.
00:16:40.720 So I wanted to provide the possibility of inheriting this null object from some arbitrary class using impersonation. This throws a wrench in the works because, so far in that build block, I’ve been calling these actions on a class that’s under construction. How can I do that if I'm not sure yet what the base class is going to be? I can't have a class under construction if I don’t know the base class yet. So, I realized I needed to start queuing up some deferred operations until later.
00:17:39.120 That sounds like a pretty big re-architecture. Let’s see what that entails. First, I needed a queue for operations. Then I needed to arrange so that once the null class is finally generated, all of those deferred operations would be performed. That was a simple matter of iterating through the operations and calling each one with that null class as an argument. Finally, I defined a helper for deferring operations called 'defer.' It takes a block, turns that block into a Proc implicitly, and stores it into that queue of deferred operations.
00:18:34.640 Let’s see how this applies to the mimicking feature that we’ve looked at a bit already. We can say 'b.mimic' and give it a class that it’s going to mimic, like Logger. Here’s the code for that before I introduced deferred operations. It does a module eval of the class that’s being defined, going over the instance methods of the class to mimic, and it defines a sub-version. Here’s the code after I introduce deferred operations—the only significant change is that part of that logic got moved into a deferred operation, saying to defer this part of the operation until later.
00:19:16.760 I love this: it's clean, it adapts the language to exactly what I want to say, and I got a major change in behavior from a relatively minor change to the code. Back to Garden State for a moment. One of the reasons that this scene sticks with me is that it says something profound about the practice of joy because a couple of things are going on here. First of all, you can see Portman’s character really loves this music, but it goes beyond that. She loves this music so much that she feels compelled to share it with someone else.
00:20:56.160 I think this is a fundamental truth about joy: we complete our joy when we share it with someone else. This is the moment that brings that joy to its fullest fruition. This is why I’m sharing this code with you today. One of the best ways we have as programmers to share joy is through pairing. Two programmers sit down in front of a keyboard—maybe right next to each other, maybe remotely—and they work on the same problem together.
00:22:08.480 I have experience with pair programming. In particular, last year, I spent a significant amount of time doing nothing but pair programming. I’ve paired with dozens and dozens of different people from all over the world, all different skill levels, spending hundreds of hours doing this. This experience brought me immeasurable amounts of joy.
00:23:35.920 I also gained a unique perspective. I now know what it was like to come to the Ruby community 10 years ago. These pairing sessions gave me the privilege of finding out from the newbies I paired with about what it’s like to join the Ruby community today. Over and over again, I heard the same things: they told me how welcoming, warm, helpful, kind, and excited the Ruby community was to them.
00:24:34.360 Friends, we sometimes face drama in our community; sometimes, we feel some community fatigue. But make no mistake, we still have the finest community in this industry, and you all are a part of that. This experience of pairing was wonderful, and I wanted more people to share that experience. I’ve been on a personal campaign to encourage more people to pair with each other, more widely, more diversely, and more often.
00:25:23.560 Even if you’re already doing pair programming at your job, consider pairing with someone you’ve never paired with before. I’ve been asking people to put this ‘pair with me’ badge on their blogs and websites, or to use the ‘pair with me’ hashtag. With the help of the community, I’ve also put together a website called ‘Pair Program With Me’ that has resources for getting started with remote pair programming.
00:26:04.720 The results of this have been great. I’ve been pleased to see where this has gone. Here are some random things people have said about it: ‘Being re-energized in my quest to be a Ruby dev,’ or ‘I might be hooked on remote pairing,’ and ‘This ‘pair with me’ thing is really deepening my sense of community.’ The cool thing is that these days there is no excuse for not pairing with someone. Even if you're a solo developer in the middle of nowhere, if you have an internet connection, you have the ability to spend time pairing with another programmer somewhere—it’s fantastic.
00:27:20.200 So, back to the code: interface subsetting—there’s a fancy term for you! What is interface subsetting? Back to mimic—we’ll talk about this a lot. Let’s say we want to mimic a logger, meaning we want to stub out methods like ‘info,’ but we don’t necessarily want to stub out core methods that are on every object, like ‘object_id.’ We really want to subset the interface. The first thing that might come to mind when trying to come up with this interface subset is to call instance methods with false arguments.
00:29:25.680 This, as I was discussing earlier, gives you the instance methods defined on that class, not its superclasses. Unfortunately, this approach doesn’t hold up. Let’s say we have a class called ‘my_logger’ that derives from ‘logger’ and adds one more method. What we want when mimicking ‘my_logger’ is to include all of the methods from ‘logger’ plus that one new method. But that method is not included, so this is not a sufficient interface subset. We need to solve this differently.
00:30:37.560 Here are the building blocks we’ll use: First, you can call ‘instance_methods’ on a class, which will return an array of symbols representing all the instance methods. Second, Ruby's arrays have set operations defined on them: you can find their intersection, union, and subtract one set from another. Let’s combine these to say: give me a list of methods which are defined on that class that we want to mimic, minus the methods defined on Object.
00:31:44.400 We then step through each of those methods and find a sub-version of each. That’s all there is to it. Interface subsetting turns out to be not as scary as it sounded, but make no mistake—this is a pretty advanced operation that's incredibly simple due to the way we can utilize the building blocks Ruby provides.
00:32:31.840 To draw this all to a close, what I want to leave you with is that meta programming is awesome—at least I think so.
00:32:40.240 Secondly, I really encourage you to embrace joyful coding. Make sure that at least some of the time you spend each week involves coding for fun, whether that’s refactoring, performance optimization, or just responsible or irresponsible coding.
00:33:05.840 This stuff is important—it stretches your mind, and if you show me a developer who is not finding enjoyment in their coding every week, I will show you a developer who is not working at their peak effectiveness.
00:33:26.720 I also want to encourage you to keep your joy. This conference has been fantastic. You will go home feeling energized and excited, wanting to try new things, but that feeling will fade over time, especially if you’re not attending another similar conference for a while.
00:34:21.360 However, I know a way to bring back that feeling repeatedly. Time and again, I’ve looked at my calendar and thought, ‘Oh god, I’ve got a pairing session scheduled. I just want to go watch TV.’ Then halfway into the pairing session with someone I’ve never worked with before, I find myself excited and energized.
00:35:14.600 I find myself making notes about projects I want to try; I am inspired! I get to experience that same charge of excitement—and every time I finish, I am glad that I had that pair programming session.
00:35:43.280 So, most importantly, I want to encourage you to share your joy. To help you do that, I've been passing around caring cards—hopefully, you’ve seen them circulating around the room. They’ve got a URL on them and you can take those home to connect with someone else to pair with.
00:36:14.720 You might just be connected to someone you previously met at the Ruby Nation conference or from somewhere else and now you don’t have the excuse of not knowing who to pair with. I hope you’ll take one of those cards and use it to reach out.
00:36:42.560 I encourage you to share your coding joy with someone else. You never know—it might change their life. Thank you very much!
Explore all talks recorded at LoneStarRuby Conf 2013
+21