Talks

The case of the missing method — a Ruby mystery story

The case of the missing method — a Ruby mystery story

by Nadia Odunayo

In the video titled "The case of the missing method — a Ruby mystery story," presented by Nadia Odunayo at EuRuKo 2018, the speaker takes the audience on a narrative journey exploring method lookup in Ruby programming. The talk intertwines a detective story format with technical content, focusing on a specific case involving method discovery in Ruby objects.

Key points discussed in the video include:
- Introduction of the detective persona: Nadia adopts the identity of 'Deirdre Buck', a private investigator specialized in Ruby-related issues, which sets the stage for her investigation into a friend's coding dilemma.

- Character setup: The main characters include Mike, a junior Ruby developer, and Jenny, his friend and housemate, who is competing with him for an internship at the Ruby Institute of Professionals. Their friendship and rivalry create the backdrop for the investigation.

- The mystery of the 'edible' method: Mike is troubled by discrepancies in Jenny’s notes about method lookup. They discuss how Ruby classes derive methods from their class objects, specifically exploring the relationship between classes and their methods through practical coding examples.

- Investigation steps: Nadia describes her investigative methods, including utilizing Ruby’s features like ObjectSpace and method ancestry to trace where the missing method might be located.

- Concept of singleton classes: The investigation concludes with the discovery that the 'edible' method is located on the singleton class of the Cake instance, emphasizing the importance of understanding singleton classes in Ruby.

- Real-life application and reflections: The storytelling transitions into practical advice on how these concepts relate to real-world Ruby programming, including the creation of Domain-Specific Languages (DSLs) and their significance in improving code structure and managing complex systems.

- Conclusion: The talk wraps up with insights on the importance of understanding method lookups and classes in Ruby, and how they can prevent confusion in programming tasks, particularly with DSLs that underpin popular frameworks like Rails.

Overall, this presentation combines technical education with storytelling, engaging the audience in both a narrative and educational context while leaving them with important concepts regarding Ruby's object-oriented nature and method definitions.

00:00:00 Join me, given the party last night. Today, I'm going to tell you a story, but first, I have a question for you.
00:00:05 Do you have a side gig? You know, something that brings in a little extra each month? I do.
00:00:12 By day, I'm a product manager for a software team in a bank. But by night, I'm a private investigator.
00:00:18 And what is it I investigate? Ruby crimes. Not jewel theft, but the programming language.
00:00:24 Why did I decide to go into private investigating? Well, there have been rumors of a shady mastermind causing havoc and confusion among Ruby developers worldwide.
00:00:32 His constant meddling in the source code has gotten out of control, and I wanted to help put a stop to it.
00:00:39 But I couldn't do this under my real name. I needed to protect my identity and so I chose 'Deirdre Buck'—D for short.
00:00:45 Why did I choose this name? Well, it was solely for the purpose of making a joke.
00:00:51 Today, I want to tell you about one of my more memorable cases: the case of the missing method.
00:01:07 Chapter one: I'm sitting alone, bored in my office, when the doorbell rings. It was Mike, and he didn't look too happy.
00:01:15 Let me tell you more about Mike. He was an acquaintance of mine. We had some mutual friends, and we saw each other now and again.
00:01:22 He was 24 years old, a junior Ruby developer who got excited about test-driven development.
00:01:30 He had been applying for an apprenticeship at the prestigious Ruby Institute of Professionals, managing to get through all of the stages.
00:01:42 He beat hundreds of applicants to reach the final stage, and this was happening in two days.
00:01:54 There were two people left fighting for the last spot: himself and a woman named Jenny.
00:02:00 Jenny was 27 years old and also a junior Ruby developer. She loved all things Rails.
00:02:07 Moreover, she was Mike's best friend and housemate. They had quit their consulting jobs together to break into tech.
00:02:13 Not long after, they decided to live together. For the interview, they agreed to work together to prepare so that each of them had the best shot.
00:02:26 They said, 'May the best person win.' So, they'd been asked to research various topics for the final stage.
00:02:32 One of these topics was method lookup, which had been assigned to Jenny. That's why Mike had come to me.
00:02:44 Something didn't add up in Jenny's notes, he explained. Jenny had been unusually stressed and panicked.
00:02:50 She wouldn't hear Mike out, convinced she was right and that they didn't have time for his doubts.
00:03:01 If I helped him find the answer to this mystery, he'd be able to confidently correct Jenny and save them from interview failure.
00:03:13 He reached into his bag and pulled out some sheets of paper, which were Jenny's supposedly flawed notes.
00:03:21 I asked him to walk me through them. Jenny had boxes representing Ruby objects.
00:03:26 All these objects had a label called 'class,' which acted as a reference to the parent class of the object in question.
00:03:38 Some objects are instance objects, with the class label referring to another Ruby object of type Class.
00:03:42 All objects of type Class also have their own class label and a methods label that points to a table of methods instances can call.
00:03:54 Jenny's handwritten notes asserted that any class you define is an instance of a class object called Class.
00:04:07 So, if we were to write 'class Cake' in our code, we create a class object named Cake, which is an instance of Class.
00:04:18 Therefore, all classes are of type Class with a capital 'C'.
00:04:26 Jenny's notes also contained code: 'class Cake' with two methods.
00:04:32 An instance method called 'tasty,' which returns true if the flavor of the instance was carrot, and a class method called 'edible,' which always returns true.
00:04:44 She wrote, 'Imagine we had a cake instance called carrot.'
00:04:50 The diagram depicted what the method lookup chain would look like.
00:04:56 The diagram showed an orange box labeled 'carrot' with a class label pointing to another orange box labeled 'cake'.
00:05:07 That box also had a class label and a methods label pointing to a table with the entry 'tasty'.
00:05:12 The class label then pointed to a box labeled 'Class,' which had its methods label with the entry 'edible.'
00:05:21 Next to the diagram, she wrote: 'A method definition always comes from an object's class.'
00:05:30 At this point, Mike shook his head in frustration and said it couldn't be that the 'edible' method lives on the parent class for all classes.
00:05:36 He asked if he could show me something and if he could jump onto my computer. I agreed.
00:05:44 He moved to my desk, opened a terminal, got into pry, and loaded the Cake class from Jenny's notes.
00:05:52 The first thing he did was show me that the class of Cake is indeed Class. Then he searched for the edible method in all the instance methods for Class, but it wasn't there.
00:06:06 What a mystery! I was stumped and not sure how to proceed, but I thought if anyone could debug this, it was Deirdre.
00:06:12 She loves a challenge, and besides, this meant a lot to Mike. He was prepared to pay me handsomely, so I agreed to take on the case.
00:06:23 Chapter Two: Ever heard of Google? Maybe if you care more about privacy, you use DuckDuckGo.
00:06:31 Well, when I'm Deirdre, I don't believe in these tools. I don't trust them. It's no coincidence that I've become the best Ruby PI the industry has to offer.
00:06:44 But without search engine tools, what did I have? Books. Books and more books.
00:06:51 I spent a whole day quickly skimming a load of books, but I couldn't find anything useful.
00:07:00 So, I decided to form a hypothesis and go from there. The edible method, while not in Cake, must be somewhere in the ancestry tree.
00:07:05 What's the ancestry tree? It shows all the classes and modules that a class inherits from— all the possible places our method could come from.
00:07:13 I created a 'where' method that took two parameters: an object and a method. This would help me search the tree.
00:07:21 It looked through all of an object's classes in ancestors to find a class where the instance methods included the method we were looking for.
00:07:31 To check if it was working, I created an instance of Cake and checked that I could find 'tasty' on the Cake class.
00:07:38 It was time for the moment of truth: the edible method must be somewhere. But it was nowhere. Nowhere at all. What a mystery!
00:07:56 Confused, I thought a change of scenery might help. I decided to head to my favorite co-working space.
00:08:03 Here, I feel at home, surrounded by people hacking away. I quietly settled down at one desk.
00:08:10 However, my naturally inquisitive nature led my eyes to stray to the screen of the guy next to me, who was experimenting with an IRB tool called 'ObjectSpace.'
00:08:24 I asked him, 'What's that?' It looked interesting. He responded, 'It's a way to interact with all live objects within a Ruby session.'
00:08:31 He showed me how to count all the live class objects in the session. I thought it might be time for a break, so I decided to play around.
00:08:43 In IRB, I counted all the class objects in the session I just started. I thought, '936.' Let me create a class and see if that number goes up.
00:08:56 I checked again: '938.' That's strange, I thought. I might be seeing things, let me try again.
00:09:12 When I checked again, the number was '940.' What a mystery! But I couldn't spend too long thinking about it, as my phone rang.
00:09:21 It was my friend wondering where I was. I'd completely forgotten I was meant to go to a tech lecture with her.
00:09:30 I felt anxious, not having much time to complete the case for Mike. But I'd also been canceling a lot on this friend lately.
00:09:42 I thought I should make some time for her, so I rushed out the door.
00:09:50 Chapter Three: I remember turning up just in time for the start of the lecture on a language called Smalltalk.
00:10:01 I wasn't interested at all; I only cared about Ruby, but I was there for my friend.
00:10:09 The lecture said Smalltalk had been created in 1970 and had led to the birth of object-oriented programming.
00:10:21 However, I couldn't concentrate much longer. I kept thinking about my play with ObjectSpace.
00:10:29 After all, each time I created one class, two new objects were created in the session.
00:10:37 My friend urged me to pay attention, so I did. When I looked up, the lecturer posed a question:
00:10:42 'What is the class of a class in Smalltalk?' A code snippet appeared on the screen.
00:10:50 The lecturer printed a polygon object and asked: 'What is the class of the polygon object?'
00:10:56 The answer returned: 'Polygon class.' She then asked the system for the class of the polygon class.
00:11:03 The answer was 'meta class.' 'The class of a class is called a meta class,' she explained.
00:11:10 She continued, stating that all languages inspired by Smalltalk have a concept of meta classes.
00:11:16 This included Objective-C, Java, Python, and Ruby. Suddenly, it clicked for me.
00:11:24 One class, two objects— I made my apologies to my soon-to-be no-longer friend.
00:11:31 I rushed home, thinking I would try my luck to uncover the edible method.
00:11:39 Of course, it couldn't be that easy. I first decided to check all methods that exist on the Cake class.
00:11:50 Faced with a long list, I decided to filter it down to methods that included the word 'class.' This was much better.
00:12:08 Two methods stood out: 'superclass' and 'singleton class.'
00:12:15 I decided to check the ancestry tree for Cake. I knew these were all of the objects where 'edible' wasn't hiding.
00:12:29 I checked what superclass returned. It wasn't the answer since 'Object' was already in the ancestry tree.
00:12:39 I then tried a singleton class, which was new to me. When I checked the ancestry tree again, new entries appeared.
00:12:48 Excited, I went back to my 'where' method. Instead of exploring the ancestors of an object's class, I explored the ancestors of its singleton class.
00:12:55 It was the moment of truth. I confirmed that the edible method was hiding on Cake's singleton class. Case closed.
00:13:06 Chapter Four: I'm delighted and excited to share the news with Mike. Should I retire after this success?
00:13:15 I decided to call Mike. The phone rang for what seemed like forever, and I was worried I would never reach him.
00:13:25 Finally, he answered, and I said, 'I've solved the case; can I come round?' He was excited.
00:13:32 'Of course, come round! I have the loads ready and waiting for you!' he exclaimed.
00:13:40 Although the case was solved for Mike, I still wasn't satisfied. I had just discovered a whole new concept in the language.
00:13:53 What are singleton classes? Instead of going directly to Mike, I took a detour to visit my friend Ellen.
00:14:05 Ellen was 43, a freelance developer who regularly contributed to the Ruby codebase. I told her about my case.
00:14:16 I wanted to know what these singleton classes were all about. Ellen explained they are hidden classes created internally in Ruby.
00:14:27 They hold methods defined only for one particular object. For example, an instance of Cake's singleton class would hold methods specific to 'carrot' only.
00:14:39 She shared that knowing about them becomes useful when you’re working on tailored behaviors in your code.
00:14:54 She recalled working with a client called Budgeting Inc—a clever AI finance tool for small business owners expanding globally.
00:15:01 When they rolled out unique versions of their software for each city, Ellen was horrified by the codebase.
00:15:10 Different developers had handled each city's implementation, often using inconsistent approaches, leading to lots of duplication.
00:15:22 This resulted in wasted development time, bumper bugs, and a frustrated team unhappy with the cognitive load.
00:15:36 Not knowing how to proceed, she decided to create a DSL, a domain-specific language. I had to admit I found this a mystery.
00:15:48 She invited me over to a computer to show me a basic version of a DSL. She opened a Pry session with a class method called 'construct.'
00:15:55 The 'construct' method utilized a block to set up a variable to initialize via the new keyword and called an instance of 'our' on the city.
00:16:07 Ellen emphasized I should pay attention to this line as it would prove important later, then returned the city variable.
00:16:14 The code also had an attribute reader called taxes, initialized as an empty array, with a method called 'tax.'
00:16:21 The 'tax' method took a name and pushed the tax into the taxes collection. It was time to give it a go.
00:16:30 She created a city called New York and added some taxes, then printed the taxes out.
00:16:38 Ellen remarked it was a very simple DSL. 'We can quickly build these lightweight city objects,' she said.
00:16:45 Imagining additions like listing banks and finance schemes seemed easy. We only used names for taxes, but what about rates and thresholds?
00:16:55 Using this simple starting point, Ellen suggested we could extend the city instance class for more complex objects.
00:17:02 She emphasized the interaction with the same city in the command line, creating subclasses of City for taxes and banks.
00:17:12 Ellen explained that this was the DSL she created for Budgeting Inc, allowing for rapid scaffolding of each new city.
00:17:25 It handle uniformity to spin up identical city instances with various names and tax structures.
00:17:34 But then Ellen challenged me to think of a place in the UK, because that’s where I’m from.
00:17:41 I suggested Bath, the scene of my last investigation. We added 'Bath' and associated taxes.
00:17:48 Ellen then asked me to think of something that made people unhappy. My suggestion was deemed too controversial.
00:17:57 Instead, she chose the constant rain there's concern in the UK—when it rains, the government implements an amnesty for taxes.
00:18:05 We removed Bath's taxes. When it rained, the government called an amnesty, and all taxes disappeared.
00:18:12 However, our friends in New York had heard about this rainy-day amnesty and attempted one as well.
00:18:20 But it failed with an 'undefined method rainy_day_amnesty for city instance' error.
00:18:31 Ellen revealed what that was. She called the singleton class on New York and showed that it matched the previous instance.
00:18:39 When we begin using DSLs and call methods like 'instance_of?', we're leveraging the singleton classes to store method declarations on relevant objects.
00:18:48 Ellen indicated we needed to return to the high level while understanding the DSL's purpose.
00:18:55 Creating a DSL enabled developers to spin up city instances effortlessly.
00:19:06 She abstracted out the similarities between any city, offering developers access to the foundational elements needed.
00:19:13 This led to a more maintainable codebase. Developers focused on customizations necessary for each new city.
00:19:21 Thus, the developers were happy interacting with an effective system. They had a clearer overview of the domain.
00:19:30 The product owner was pleased because there were fewer bugs, deliveries were faster, and she could communicate requirements in DSL terms.
00:19:39 Ellen explained why understanding singleton classes is beneficial. She asserted it’s crucial for identifying the definition of methods at any moment.
00:19:50 Once you enter the realm of creating classes and methods dynamically, the class hierarchy becomes more interesting.
00:19:55 Understanding where singleton methods and classes hide can save you a lot of headache.
00:20:06 Ellen asked if I knew what the class of a singleton class was. I admitted it was another mystery.
00:20:20 She tasked me with investigating that as homework. I still haven’t gotten round to it yet.
00:20:26 Perhaps one of you could help me later. Anyway, Ellen said to be cautious.
00:20:30 While DSLs can be effective, they aren’t always the answer for complex business rules.
00:20:37 You need to customize behaviors for certain cases, and even then, approach DSLs with caution.
00:20:43 You don’t even have to write DSLs to benefit from understanding how they work. For instance, when using Rails, you encounter them daily.
00:20:56 Ellen showed me that ActiveRecord migrations were carried out via a DSL.
00:21:04 When we write 'create_table :users do,' that’s using a DSL to specify column formats.
00:21:14 She pointed out that when we specify how our Rails app handles HTTP requests, that’s also done via a DSL.
00:21:24 I realized I had always just been doing these tasks by rote, never considering what was happening behind the scenes.
00:21:35 When I typed the resource keyword in my routes.rb file, I had never paused to think about what transpired.
00:21:44 Ellen explained that when people refer to Ruby's 'magic,' it's actually just a body of well-organized DSLs.
00:21:54 She also noted that the RSpec testing framework, with its describe concepts and blocks, is a DSL as well.
00:22:06 With all these frameworks and DSLs, knowing about singleton classes can aid debugging, especially when inheriting a codebase.
00:22:17 If you see strange bugs involving certain methods, singleton classes might just be a factor.
00:22:27 Feeling empowered by this conversation, I headed to Mike's house, excited to share the news.
00:22:38 However, when I arrived, I found Mike had tears in his eyes. He had obviously been crying.
00:22:46 He held a few pieces of paper in his hand, raising them towards me, offering them for inspection.
00:22:55 These seemed identical to Jenny's method lookup notes he brought to me the day before.
00:23:05 Looking through the papers, I noticed a difference. The box labeled 'carrot' had a class label pointing to the Ruby object 'Cake.'
00:23:12 It also had a methods label for 'tasty' but read 'cake singleton' instead of 'class.'
00:23:19 Mike fell to his knees, breaking down in tears. 'Jenny knew about singleton classes all along!' he cried.
00:23:25 He confessed, 'I went into her room to find the notes in advance and found this copy.'
00:23:33 Jenny had been so desperate to secure the job for herself that she set out to intentionally mislead Mike.
00:23:41 She hoped Mike would fail the interview and look underprepared. I felt disappointed in myself.
00:23:54 I had been so focused on the main villain—the shady mastermind—that I failed to spot the villain right under my nose.
00:24:00 My best friend tried to sabotage me. At this point, Mike started crying again, saying he wouldn't go to the RIT interview.
00:24:08 I reassured him, 'Nonsense! You can't give up now.' I sat down next to him and gave a comforting pat.
00:24:16 'You can do this! I have just the thing to set you apart from Jenny.' He looked up, hopeful. 'Have you heard of DSLs?' I asked.
00:24:32 I proceeded to tell him everything Ellen had shared with me. Though Mike still looked devastated as I left him, I had confidence.
00:24:38 I inspired him with the knowledge and power of singleton classes. He would pull himself together and secure the RIT internship.
00:24:50 Two months later, I managed to drag myself to Ruby Hack Night. While milling about enjoying free food and drink, I heard whispers about Mike.
00:25:01 I looked across the room and saw Ellen. I walked over, we caught up, and I shared my reflections about the case of the missing method.
00:25:09 My takeaways? Singleton classes hold methods specific to particular objects, and understanding them opens up a new world.
00:25:21 It allows for dynamically creating classes or methods on the fly, especially in complex applications with DSLs.
00:25:31 I mentioned if I still feel I can get by ignoring them in my day-to-day work. 'Not really,' Ellen said.
00:25:44 'If you're writing DSLs, you definitely want to understand them. They underpin frameworks like Rails.'
00:26:02 'Yet, day-to-day, you can manage without them,' she added.
00:26:09 'However, reason number one she completed the project to a high standard was understanding exactly where she defined methods at any given moment.
00:26:21 'Once you enter the dynamic space, method lookups get more complex.'
00:26:31 'These concepts can save you from headaches, especially when dealing with buggy code.'
00:26:41 I left the hack night deep in thought. Ellen inspired me to explore more of Ruby behind the scenes.
00:26:46 There was so much I didn't know, and I had only scratched the surface.
00:26:50 Having been a general Ruby PI, I thought it might be time to find a niche to reach the next level.
00:27:16 Okay, hi everyone! It's time now for the bids for the next location.
00:27:21 We have three contestants. I'm doing this because the Lord will also be bidding and there's a conflict of interest.
00:27:28 Let's have everyone who submitted bids sit in the front. So we'll start first come, first served.
00:27:36 Miles is up for Bristol, England.