Design Patterns

Summarized using AI

Go Ahead, Make a Mess

Sandi Metz • October 26, 2012 • Earth

In the talk "Go Ahead, Make a Mess," Sandi Metz addresses the inherent messiness of software development and the significant challenges developers face when making changes to existing applications. Metz argues that perfection is unattainable and that one should embrace the mess while utilizing object-oriented design (OOD) principles to manage it effectively. The video outlines several key points and examples to illustrate how OOD can help navigate complexities and dependencies within software development.

  • Understanding Messes: Metz describes the evolution of an application from a joyful creation to a tangled mess filled with dependencies as new features are added. Developers often experience frustration as requirements change, and the application design fails to accommodate these changes efficiently.

  • Knowledge and Dependencies: The core of the mess is linked to the knowledge embedded within objects and their dependencies on each other. The inability to pull on a single thread or component without disrupting others highlights the challenges involved in maintaining code.

  • Omega Messes: Metz introduces the concept of 'omega messes,' which have no dependencies or interconnections with other parts of the code. She emphasizes that recognizing and categorizing parts of the code can guide developers in deciding what changes are necessary and beneficial.

  • Example of Refactoring: Throughout the talk, Metz demonstrates refactoring code using sequence diagrams to illustrate how dependencies can be visualized. She provides an example where a method for calculating shock costs complicates into a large case statement. By restructuring the code, she illustrates how to separate concerns through the creation of factories that encapsulate behavior and reduce overall dependencies.

  • Object-Oriented Design Principles: Metz stresses that OOD provides tools to better manage the mess. By sending messages rather than implementing behavior directly, developers can reduce knowledge about dependencies and encapsulate processes within distinct objects.

  • Removing Dependencies: The goal of applying OOD principles is clear: to create designs that limit and control dependencies, allowing parts of the application to function independently. Metz advocates that this makes the software easier to maintain and evolve over time.

In conclusion, Metz encourages developers to leverage object-oriented design not only as a solution to manage current messes but also as a preventive measure against potential complexities in future software development. The key takeaway is to embrace the inherent difficulties of programming, employ effective design strategies, and foster an environment where changes lead to growth rather than chaos.

Go Ahead, Make a Mess
Sandi Metz • October 26, 2012 • Earth

Software is always a mess. You can't avoid this mess, and if hubris goads you into attempting to achieve perfection, you'll just make things worse. Perfection is a distant, dim land on the unreachable horizon. You'll not be going there today.

What you can do, however, is use the techniques of object-oriented design (OOD) to make your messes manageable. OOD is good at messes. It understands their origins, predicts their courses, and foresees their outcomes. It shines a light down the dusty nooks and crannies of your app, showing you what to do and what to avoid.

This talk shows you how to use OOD to create the best kinds of messes, those that let you get software out the door today without regretting your actions tomorrow.

Rocky Mountain Ruby 2012

00:00:09.599 I'm here today to tell you a story, and it might be a story you know.
00:00:15.280 You love your life, and you love Ruby, and you love Rails. You wrote an amazing app, and everyone thinks you're brilliant.
00:00:28.840 Then the customer asks for a little change. So you tunnel off and open up your text editor. You grab all the files and make one little change. Then you make another, and then a few more. You get all the tests running again, and you check it all in. You throw it proudly into production, and then they tell you they want to change their mind. They didn't really want this thing; they wanted that thing instead.
00:00:45.120 So you open up your text editor again, grab the files, and this time you make a bunch of changes. Then you make a whole bunch more. Frankly, this is not as much fun as you thought it would be, but you get everything running. You check it all back in and deploy it to production.
00:01:04.000 Then they ask for a new feature, and now it's a crisis. Everyone's hair is on fire. The app just was not designed to handle this. You do whatever it takes to make it work. You hack away at it with a machete until you get it running, and then you throw it back into production.
00:01:16.880 You start wondering if maybe there's a way to check code in without putting your name on it. Then one day, you realize that the app is a wreck, and that you hate Rails, and you hate Ruby, and you hate your life.
00:01:29.759 We all know that story. In the beginning, the app was a delight. You felt great, you were getting so much done, and that feeling of deep satisfaction came from how efficient, effective, and useful Rails felt.
00:01:42.799 Unfortunately, for many apps, this feeling peaks right about the time you release the first beta and then goes downhill ever after. Things get worse and worse. You were fast, now you're slow. You were happy, now you're sad. You were cost-effective, and now you're a money pit.
00:02:02.000 The app was amazing, and now it's just a mess. This does not mean that it's time to look for a new job. Amnesia won't help unless you change something. Every app you write, you'll end up hating. These applications are prisoners of their designs, and they've taken you hostage.
00:02:13.280 You can't outrun this problem; you have to do something different. You have to learn to understand the mess. The problem with messes is that they're messy. They're hard to understand; everything is tangled up together.
00:02:24.000 They're like big tapestries made up of many different threads where the warp and weft are woven over and under. You can't pull on any thread without dragging something along from a different part of the tapestry. In the beginning, everything is idyllic, but as soon as you start making changes, that illusion gets shattered.
00:02:32.640 Your app isn't a pastoral scene with cute furry little lambs. No, your app is trying to kill you. Things are so woven together that you can't pull on any single thread without breaking many things.
00:02:44.000 And this coupling, this mess, is because of knowledge. Your app is made of objects, and objects know things. They always know things about themselves, and sometimes they know things about others.
00:02:58.240 It's the knowledge of others that weaves objects together. When an object knows something outside itself, that's a dependency. We all know about dependencies: when something you depend on changes, you might be forced to change in turn.
00:03:07.440 You cannot avoid dependencies since objects have to collaborate. They always know things about one another. But there are many ways to arrange code to solve any problem, and you can easily arrange dependencies so that things turn out badly.
00:03:21.600 Controlling dependencies requires understanding the stability of the various bits of knowledge in your app. Everything any object knows can be ranked along a continuum from completely stable to completely unstable.
00:03:36.639 It doesn't actually matter how stable something is; it just needs to be more stable than the things that depend upon it. Stability is relative, and things that are wildly unstable in some circumstances, from some points of view, might be very stable from others.
00:03:48.960 Sometimes you might not even know if things are stable or not; you're confused about how stable a bit of knowledge is. This is where object-oriented design gives us hope. Object-oriented design is the ultimate dispenser of programming treats. It lets you write code that your future self will love, even in the face of confusion and instability.
00:04:01.599 It knows how to separate the stable from the unstable, showing you how to depend on the first and hide the second. It gives you a way to manage the mess so that you can write apps that are efficient and fun forever. It changes everything. Object-oriented design lets you stop worrying and learn to love the mess.
00:04:21.120 I'll show you how. It's easy. Three examples: the first example will set up the problem, the second one will complicate the code, and in the third example, a miracle occurs.
00:04:35.440 The arc of this talk and the arc of the examples are based on a simple premise: concrete code is easy to understand but costly to change. Abstract code is harder to understand at first glance, but it's much cheaper to change.
00:04:50.880 The principles of object-oriented design move your code toward more abstraction. It's not that there aren't costs involved; it's that the benefits outweigh the costs, as you'll see in the examples and throughout the talk.
00:05:04.000 Example number one: something bad just happened here, and I can fix it. Example number one is to label the knowledge. Imagine there's a game where people race bicycles. Players have to buy parts, and one of the parts they can buy is a shock.
00:05:18.480 Before buying that shock, a player wants to know what the shock is going to cost. Here's the code that's already written: Players on shot costs a game gets a new instance of shock and sends it the cost message. This method is a big, ugly, complicated mess; it's pretty much incomprehensible.
00:05:41.280 The customer told us they weren't really sure if it was right. They know it's going to change, but they need more information. Some time needs to pass until they figure out how it should work. Even though you can't see the code, assume it has these qualities: nothing inside this method can change that will force a change out in the app.
00:05:54.520 Nothing out in the app can change that will force a change inside this code. So this mess is due to those qualities. This is a special kind of mess, and I'm going to give it a name: an omega mess.
00:06:04.000 Omega messes are at the end of the line and have no dependencies. You can think of every kind of mess in your app as falling into one of two categories: it's either an omega mess or it's not. So the question is, what should we do about this code? It's heinous; it's really embarrassing. You would not want your friends to see it.
00:06:19.200 What will be the consequences of this code arrangement if you walk away right now? Let's postpone that question for a minute; hold on to it. We'll get back to that. Let's look at a picture first.
00:06:36.080 This is a picture of objects and the messages as they pass between them. It's a sequence diagram, and I love them. It's also UML, but trust me, it'll be okay.
00:06:50.240 Here's how sequence diagrams work: the boxes represent objects. The objects can be an instance of a class or a class itself, but they are just objects. We don't care. They repeat at the top and the bottom.
00:07:03.360 This vertical dashed line connects the boxes, that's two same boxes. The horizontal solid line represents a message being sent. The filled-in dark arrow is on the end of the receiver. This vertical gray bar tells you the game is busy in the shock cost method, and the result goes back on a dashed line.
00:07:12.560 Again, the filled-in arrow is on the side of the receiver. I drew all these pictures with web sequence diagrams. I took their name off the rest of the slides, but there's credit at the end.
00:07:27.040 I'm going to draw some pictures on the slide. I think you can probably see them. I'm going to put arrows that represent external dependencies and then dashed lines with zeros; they will represent internal knowledge.
00:07:36.480 Then I'm going to color code it for stability: very unstable things are red, down to really stable things being green.
00:07:43.520 So what this diagram shows is that the game depends on the name of the shot class. It also depends on the fact that the shot class knows the new message; it depends on the fact that it knows about the cost message, and it depends on knowing who the receiver of that cost message is.
00:07:55.760 Shock knows that it implements cost, and it knows how it does so. From the drawings on this diagram, you can see that shock has no external dependencies; it's at the end of the line, it depends on nothing else.
00:08:08.320 Game depends on a surprising number of things about shock. This sequence diagram is a much truer representation of the relative importance of things than the code itself. The big mess that dominates in the code might be 100 lines long; here it is represented by this little gray bar.
00:08:23.440 From outside of shock, all you need to know is that you can invoke it by sending this message, and the mess is therefore hidden behind the message. This view of reality can be deceiving because it feels like the amount of code ought to relate somehow to importance.
00:08:38.080 It might be true if we wrote perfect code, but that's often not the case. This implementation of cost is like a big, loud, boisterous guy at a party who dominates the conversation, surrounded by introverts who can't get a word in edgewise.
00:08:52.320 When you walk into the room and see him, it's easy to think he's the most important thing. But the stuff here that needs to be listened to is the introverts; they hold a lot more information.
00:09:03.760 Do not be misled; it's not about the code. It's not about those classes filled with characters that you typed into that file on disk. It's about the living, breathing, running application in memory. It's about the message.
00:09:19.040 Now, having seen a bit of code, let's step back and diagram it at ten thousand feet. We're going to plot it like it was a sentence.
00:09:32.800 So this is a plot. On the horizontal axis, we have stability. Really stable things go over on your left while very unstable things will be on this side.
00:09:41.120 Now, the vertical axis shows what the object knows—whether the information that the object has is within its purpose or outside of its purpose. You can think of that as being whether or not it's the object's job or responsibility.
00:09:54.560 Knowing which quadrant a bit of knowledge falls into tells you how to behave. The top left quadrant: stable things that are within your purpose are part of the public API.
00:10:06.559 Unstable things that are within your purpose are private behavior, and they should be hidden behind the public API. Anything that's below the line is a dependency.
00:10:18.720 You should expose your public API and hide private behavior behind it. Stable dependencies that are outside of your purpose you have to have in order to collaborate with other objects, but you should minimize them.
00:10:32.000 Here's the key: unstable dependencies that don't belong to you should be moved. If knowledge falls into this quadrant, something about your code needs to change.
00:10:44.000 On the sequence diagram, we saw that shock knew these two things: it knew the name of the cost method and the internal calculation.
00:10:57.680 Game also depended on the message, the cost message, the name of the shot class, and the cost receiver. We're going to dump game for now and just talk about shock.
00:11:11.520 The cost method is about the most stable thing shock knows; it's part of the public API. Other objects can safely depend upon this piece of information.
00:11:25.760 Its internal implementation is very unstable, which we know, but it does not matter because it's completely within shock's purpose. Shock is allowed to know this, but it ought to hide it behind that message.
00:11:37.440 So these plots tell us to do two things with that bit of knowledge, which is already true about the shock class. Example one is about the simplest bit of code on earth; I've been talking about it for 10 minutes.
00:11:53.600 So I ask you, what are the consequences of walking away? We all know the cost method is ugly and embarrassing, and we all know it's going to change.
00:12:05.440 At this point, design asks only one question about this code: it wants to know what is the future cost of doing nothing? Now, you will never know less than you know right now. If it does not cost you money to do so, you should wait.
00:12:21.040 The most cost-effective design strategy is often to do nothing; this might be such a case. Since the cost method isn't an omega mess and has no dependencies, there is no way that it can affect your app, or any changes in your app can affect it.
00:12:34.399 It is not connected in one of the threads on your tapestry. Having said that, it's okay to leave it. If this code were mine and I had 10 minutes, I would make a few changes. I would inject that dependency; it makes my testing a lot easier.
00:12:48.399 I would refactor this code into a bunch of little atomic methods with intention-revealing names. You might not; that's a judgment call. I do these things almost without exception because doing a refactoring that simplifies code is like buying a ticket in a lottery that's rigged in my favor.
00:13:01.760 It pays off so often that my best strategy is to play every chance I get. I don’t consider that refactoring design; it's just housekeeping, just cleanup—the last scan through a piece of email to make sure you don't have typos.
00:13:16.320 For now, we're just going to leave the code as is. So we're done with example one. Let's make it more interesting: the game's a big success, and now they want more shocks.
00:13:28.880 Each shock is going to have a different cost; there will be a different cost calculation with every shock. It's really nice to be in Colorado where I don't have to explain what a lefty shock is, while others might be confused by that.”
00:13:43.120 A well-intentioned programmer has come in and made the change, adding type to the game. The player picks a type, which gets passed into the shock cost method, and then passed on to shock in its initializer. The changes to shock reflect this: it now actually remembers that type, but it has a big case statement with different calculations.
00:14:02.960 Here’s the sequence diagram for this code. I told you before that sequence diagrams give a better representation of what’s going on in code, but they’re not perfect. There are coding sins you can commit that go unnoticed in sequence diagrams. Like, the types are being passed in, and I put a comment about the conditional messes.
00:14:17.920 But really, cost is still represented by just a little gray bar at the end of the line. I told you before that omega messes have neither dependents nor dependencies.
00:14:35.760 Is this code still an omega mess? Here’s a list of things that shock knew—it used to know just one cost calculation, and now it knows four. In addition to that, it knows the symbols for four shot cost types, and it knows the mappings between the two.
00:14:51.919 These things are known to but not owned by shock. What will happen if the application adds another shock? What will happen if any one of the cost calculations changes?
00:15:06.960 Suddenly, there are many ways in which the outside app can change, forcing you to change things inside the cost method. The case statement caused an explosion of dependencies. It's no longer an omega mess; it's something else entirely—it’s what I'm going to call meta-knowledge.
00:15:22.560 Meta-knowledge is knowledge about knowledge. Omega messes should be hidden inside the pieces of that puzzle, but meta-knowledge is about how the puzzle is put together.
00:15:36.080 Object-oriented design, and it's actually the domain of design. Let's move back up; we're going to use object-oriented design to rearrange the meta-knowledge to remove those dependencies.
00:15:52.479 We don't need to talk about the shock cost method; shock should still own that. Let's take a look at the shock cost calculations. When we had just one calculation, it belonged and was within shock's purpose.
00:16:05.439 But now that there are four calculations, it's incredibly unstable and probably should not be known by shock. This is not shock's job. The fact that there are four different types of shock is the same deal; it’s incredibly unstable.
00:16:19.680 You know it's going to change; it doesn't belong in this class. This is a dependency where some outside change is going to force a change in this method.
00:16:31.839 The mappings between what type gets what calculation are probably more stable, but they probably don’t belong here. These new dependencies are what make code costly to change.
00:16:45.360 This method used to be independent, and now it's woven into the rest of the app. It's not only costly to change but likely to change. Where you have four types, you might end up with three or five.
00:17:02.560 Adding that case statement ruined a perfectly good omega mess. This is unfortunate because object-oriented design has many techniques that will let you avoid this.
00:17:16.400 They're simple; it just takes a little bit of knowledge of object-oriented design. Here’s the guiding principle: I’d rather send a message than implement behavior.
00:17:29.920 I don't want to know things; I just want to send a message to some other object. Well, that's great, but it's really clear that what happened here is there was no one to send a message to.
00:17:43.600 That's how this happened. Shock is at the end of the line and already knew how to calculate one cost, so when we asked the question of where we should put this new code, the shock cost method seemed like the obvious place.
00:17:56.960 But that's the wrong question; it is not the question that object-oriented design asks. We got in this mess by asking, where should I put this code? We can get out of the mess by asking, what message should I send?
00:18:09.920 Then we'll make up an object if we have to, and we'll send that message. So let's look at object-oriented composition. I would explain it to you, but it is so simple, I'll just show you.
00:18:24.640 We have this ugly, dependent-laden code that we want to refactor; we would rather send a message than implement behavior. We don't want to know things; we just want to ask someone.
00:18:38.320 So, what message should I send? How about compute? We like compute; it’s a good message! Where should I send it? I don’t know; let's just make something up.
00:18:51.680 I'll create a new class and name it something related to shock cost. I'll move the mess down into its compute method, and now it’s hidden. This returns that mess to an omega mess.
00:19:05.760 I can now safely hide it behind the compute message. Since we now have someone to ask, I'll just change the original code to get an instance of that class and send it compute.
00:19:18.080 Rinse and repeat: you can hide all the messes by making a new class for everyone. Here’s where we are now: I promised you a miracle, but this doesn’t really seem like one, does it?
00:19:31.760 It's hard; it's hard for people to see this whole refactoring because they imagine going here and ending here. This does not feel like an improvement. As a matter of fact, the case statement still has a ton of dependencies.
00:19:50.080 I made up four new tiny classes; it’s easy to ask the question: is this a real improvement, or did I just complicate things in the name of design?
00:20:04.120 What did this accomplish? I used to have four shot cost calculations, and now I have four classes. I used to have the mapping between four types and four calculations, and now I have the mapping between four types and four classes.
00:20:18.399 There is an improvement here: every calculation has been removed from that case statement and put into a class of its own. They can now change independently; you can edit those files without breaking other code in your app.
00:20:31.840 However, there are still dependencies in this case statement. If you add or remove a shock, you still have to change code here, and I dislike that. Let’s fix that.
00:20:46.320 Notice the pattern: type, name, class name. This is like saying... Because we control these names, we can do a very Rails-like thing and create a convention.
00:21:01.279 It's easy to create a string that holds the name, the string of the class we want. If we can construct that string, we can use a tiny bit of meta programming to turn it into the class.
00:21:15.440 Now I can hear all the really good Ruby programmers freaking out because of eval. Like, you probably shouldn't do that.
00:21:30.240 This is like a JavaScript eval; it turns it into the object. To make Wayne happy, don’t do that; you can do this instead—Ruby has this list of constants where you can index in by the string name and get the class back.
00:21:44.160 Saying object.const_get(class_name) is exactly like saying foo shot cost. But if you're a Rails programmer, which you probably are since you're clearly using titleize, you don’t have to do that.
00:21:58.000 You can just send const_get to any string, and you get the class back—that’s an object. We’re object-oriented programmers.
00:22:10.080 This transition from making up a class name and turning it into the object in a class is something that it’s really useful to get comfortable with. So, we manufactured an object.
00:22:22.080 I use that word deliberately because this is a factory. Now, I know some of you break into a cold sweat when you hear that word because of PTSD from coming from a language where everything's hard.
00:22:38.079 But you're in Ruby now, and the pain is over. All right? We love factories. Not only do we love factories, but I want this word—go forth and claim it! This is a perfectly good word.
00:22:55.760 It means exactly what we want: an object that creates some other object is a factory; that's all it means. It doesn't mean it's hard; it doesn't mean you're going to hate yourself; it just means you use a bit of code to manufacture an object that you can use.
00:23:09.040 Now that I have that factory, I can remove the entire case statement. I no longer need to know the class names; I don't need to know the shock types, and I don't need to know the mappings between them.
00:23:22.960 I just need to know the convention. I can write code that breaks every time you change something in your app for this code, where if I want to add or remove a shock type, I just create or delete a class.
00:23:35.600 This is a huge win. One caveat: I probably wouldn’t leave it like this. I would extract the factory into some other class, but there’s no point in going into that; you get it, right?
00:23:50.799 The next example: if you can get like the problem very often with object-oriented design is that you need an object to which you can send a message, but you don’t have that object, and factories are the solution to that problem.
00:24:00.960 So that's object-oriented composition. Here's what it looks like: we had the shock class. It had a method cost that did a calculation that we crammed four different calculations into.
00:24:14.000 We fixed this problem by picking out a message, extracting each of the calculations into a class of its own, and then we defined the message and took the API.
00:24:27.520 We had shock send it, and every one of those guys implemented it. Once we arranged code that way, you can add any new shock coster by having it implement the interface.
00:24:42.960 If you create a new class, all you have to do is make it define that message. The message defines the API of the duct type, and it’s the API of the role.
00:24:55.280 Shock’s cost method doesn’t know or care what the class of the receiving object is; it expects every collaborator to implement this role. Think of collaborators as a kind of its role rather than a kind of its class.
00:25:08.720 When you do that, it changes everything. You can manufacture the right kind of thing, trust it to play the role that you expect. Then you can just send the message, and everything gets easier.
00:25:23.120 The dependencies disappear, and your app becomes a box of pluggable parts that are interchangeable, like Legos. Design happens from the message sender's point of view: we don’t send messages because we have objects; we have objects because we send messages.
00:25:38.240 Design is not in the business of dictating perfection; it knows there is no such thing. It only requests that you remove dependencies and the dependence from your messes and hide them behind stable interfaces.
00:25:54.560 It allows you to recognize meta-knowledge when you see it and tells you how to use the principles of design to rearrange code to remove dependencies.
00:26:04.800 So there you go: object-oriented design is just a set of tools. If you have the tools in your toolbox, you can pull them out and use them when the situation calls for it. The truth is, even if you don’t study object-oriented design, if you do enough object-oriented programming, it will teach you these rules.
00:26:19.920 For example, there was a time when I thought I invented the Law of Demeter. I swear I did; I was writing code in a cave and crafted bad, tangled, messed-up code.
00:26:33.920 First, I wrote it long enough to notice the pattern was bad. If I avoided it, my code got better. They say good judgment comes from experience, and unfortunately, experience often stems from bad judgment.
00:26:48.720 Now, I have plenty of experience; I walked into the headwind for a long time, not realizing an easier way existed. You might be special, but no matter how special you are, there's no need to suffer. We can learn from those who have gone before.
00:27:05.760 Object-oriented design says that stability is relative, and you should notice it. Depend on things that are more stable than you are. What you want is always more stable than what they do.
00:27:20.000 What they do is messy, uncertain, and changeable, but from the outside, from where I stand, it doesn’t matter what’s inside that house.
00:27:36.800 If you arrange code so that you cannot see the mess, it does not exist. We stand on the shoulders of giants; we truly do.
00:27:47.680 We are lucky to live in an age where the best thoughts of anyone are available to everyone. I'm not saying that we're all Isaac Newton, but you have to start somewhere.
00:28:00.240 We begin as infants of design, but you can grow and learn, and we can teach each other. It isn’t always easy; there’s no guarantee it will be fun every step of the way.
00:28:14.400 But if you persevere, a time will come when your applications will bring you nothing but joy. You will never outgrow the principles of design. If you learn them, you can use them, make them your own, and you can write applications that you'll love forever.
00:28:29.440 Thank you.
00:28:30.799 Is it time for questions? Yeah, we can do a few questions.
00:28:36.000 Wow, he knew the secret! Come on, Dan, what's your question?
00:28:43.600 Yeah, Dan, come on.
00:28:51.039 My question is, how come you don't use a type class instead of a car in that cost class? You’d have left shock dot cost.
00:29:06.720 You know, there are so many ways to solve this; that is a completely reasonable solution.
00:29:12.320 You could do this with inheritance! It depends on what the shock looks like, what else is in shock, which we don’t have a way to show here.
00:29:26.560 But, yeah, you could! I don’t care how you do it; all I want is to do whatever saves the most money.
00:29:38.559 That was a good point! So in your situation, that might be the perfect solution. I'm sorry; I gave him the preview of the fact that I was getting... I would have asked this question.
00:29:53.920 I have one copy of the book; he just got it!
00:30:05.440 Okay, next! Do we have any other questions?
00:30:17.760 Yeah, it’s right now! You can get it on Amazon if you buy through my link!
00:30:27.760 Yes, can you yell it out? We’ll repeat it!
00:30:39.600 Yes, absolutely.
00:30:42.128 Yeah, my goal is to remove the dependencies. I want to write code that can't be affected.
00:30:56.000 As soon as I get here—oh, sorry! She asked if the goal was to isolate those things as omega messes.
00:31:03.440 Right, to push each branch of the case statement out, so this is a classic object-oriented technique.
00:31:14.480 It actually has a name: replace conditionals with polymorphism! That’s a thrilling name, I know; you would have loved that talk!
00:31:30.560 So there’s a twofold goal here: one is to return every mess to a single omega mess with no dependencies so that I don’t have to change that code.
00:31:44.720 My goal is to hide it, but I also want to remove that meta knowledge—the knowledge of number and make my app not depend upon it.
00:31:58.640 I want to be able to change from three to six to ten shocks without affecting any code except the new code that has to be written to do that one thing.
00:32:14.640 The first refactoring returns the omega messes, and the second refactoring changes the case statement, removing the dependencies.
00:32:29.760 The case statement binds in a lot of knowledge, and replacing it with a factory places that knowledge within the factory, not the case statement.
00:32:43.920 More questions?
00:32:59.680 So, his question was, about using... Sorry, I'm going blind.
00:33:02.640 I used a convention that relied on assembling the name out of a string to generate the actual class name. If I had time, I would have done ten different factories.
00:33:19.760 Think of all the things you can do. You can write a hash that has some string or symbol in it where you look up the class name. You can write a hash where on the left side is a method that evaluates to determine whether to use the class name.
00:33:35.040 The number of ways you can use information to generate the name of the class is almost infinite, and different situations call for different ones.
00:33:52.160 You should use the one that's appropriate where you are. Whatever piece of information you have ought to be something you can look up dynamically to figure out the class of the object you want.
00:34:05.680 In a longer version of this talk, there was an example of Ford that used inheritance to solve this problem. If you read all the blurbs, everybody says to prefer composition over inheritance.
00:34:18.320 They say that because there are dependencies with inheritance that can drive you into a corner that’s hard to escape from. The decision between composition and inheritance is one of degree.
00:34:35.680 If the shock class does a lot of things and is composed of different kinds of costers and other types, you decide on a bunch of roles and plug other objects in behind those.
00:34:49.680 Perhaps composition is the right solution. If shocks are nearly all alike, the entire body of the shock class is almost identical, varying only in tiny specializations. In that case, I could use the template method pattern.”
00:35:05.040 For that specialization, inheritance would be a suitable solution. As a matter of fact, if I had this problem and my shock were large, I would probably use inheritance to address it. I know inheritance has a bad name, but I’m an old Smalltalk user; I like inheritance.
00:35:20.000 I probably overuse it a bit; I'm careful as I navigate the inheritance path not to go too far before I switch it back to composition if it proves not to be the right solution!
00:35:34.080 Thank you! Oh, wait! One more question.
Explore all talks recorded at Rocky Mountain Ruby 2012
+16