 Hello, everyone. That's me on Twitter. Feel free to follow me and tweets and take photos, stuff like that. No problem. Before I start, I want to say big thank you to the organisers for putting on a really good show and really looking after us today. Thanks very much for that. I'm here in Belgium and I'm all on my own. If you see me around, I'm quite shy. You'll probably see me in the corner hiding somewhere. Feel free to come and say hi. Ask some questions, that kind of stuff. This is my first time in Belgium. Before I came, I knew Belgium was famous for a few things. Obviously, you're famous for your waffles and your beer and your chocolate. I wanted to do a bit more research first before I came. Did you know that Belgium was the first country in the world to have a national lottery? Congrats. You also invented the Smurfs, which I've kept my children quiet on many a weekend. Thank you for that. You've also got more castles than any other country. I'm definitely going to come back and visit and try and take a look at these spectacles. I'm from the UK, as you might have guessed, and we're famous for a few things as well. Our British cuisine, for example, our affordable housing. You can buy this garage, I mean, studio flat, for a mere 136,000 euros. Also, our work-life balance says a guy with a baby and a laptop and a music stand. I don't know what he's doing. Anyway, I'm here to talk about changing software and how to make software easier to change. It's said that the one constant in software is change. How can we make our software easier to change? That's what I'm going to try and talk about today. In particular, one thing, this acronym, OCP, not omniconsumer products, because they make some horrible things. Instead, I want to talk about the open-close principle. What is it? This guy is called Bertrand Mayer. He invented the Eiffel programming language and also the concept of design by contract. In his book, Object-Oriented Software Construction, in 1988, he coined the term of OCP. OCP states that your classes should be open for extension but closed for modification. In this talk, we're going to explore what that means and show you some examples of how you can actually do that in your code. More specifically, Mayer says that classes can only be modified to correct errors. If you need to change or add new features, you need to create a new class to do that. Shortly after, Mayer and his principle came solid. Solid is a set of guiding principles that complement each other that help us have better object design. Solid was created by this guy, Uncle Bob, and it's made for five principles, and they are single responsibility, open-close, Lisk-off substitution, interface segregation, and dependency inversion. Obviously, I memorised it with that and didn't read it at all. So why is the Eiffel code principle important? So it's risk and cost. So it said that if you're changing stable working code, you've got a relatively high probability of introducing bugs into that. So it's less risky if you can just create new code without changing existing code. And also on the cost front, it takes more time to change existing code because you have to look at it, understand it, try to look at what's going on, make those changes without bugs, and then fix those bugs. So it's this risk and cost idea. And when we're changing code, we kind of have these two options, simple versus easy. So simple on the left-hand side, this is where you make your code as simple to understand and simple to change as possible. And it has this kind of graph, so it's cost up on the side and time along the bottom. So in the beginning, it takes a bit more work upfront to make your code nice and changeable. And then as time goes on, you reap those rewards because your code is much easier to change if you have that upfront time invested. Versus easy, and this is where lots of startups tend to fall down, is they just need to hack in, make the easiest change they can possible. And it's really fast at the beginning, your shipping features. But then at some point in the future, you'll get to a point where change is really hard and even the simplest change seems like it takes forever. So in my opinion, you should be gambling on success. So whatever product you're working on or project, you're gambling that it's going to succeed and it's going to succeed for the long term. So you should really be thinking about the simple side of things because in the long term, you don't want pain. So Dave Thomas gave a talk at Lundstar Ruby this year called My Dog Talked Me To Code. It's a really good talk, so you should definitely go and watch that. And in that talk, amongst other things, he says, forget all the rules. So forget solid, forget Sandy Max's five rules. This is the only rule you need. A good design is easier to change than a bad design. And as developers, we need to embrace change. And just like you, I know what it's like. You work on a feature, it gets shipped, and almost immediately they want to change it. And you're like, man, I just worked on that feature. But this is our job. So stop your whining. Let's embrace change. Let's make our code easier to change and in turn make our lives easier. So a slight sidetrack from OCP for a second. So what do you think is the number one reason that makes our programs harder to change according to, well, me? It's this. Conditionals. And the reason I say that is because conditionals are magnets for business rules if such and such do a thing. And at the beginning, when these things are simple, it's fine. But what tends to happen is they tend to be a magnet for your business rules and your conditionals get more and more complex. You end up with more and more branches. And then what happens is they end up being duplicated around your system and this is when change becomes really hard. So if you can, try and avoid ifs. I'm not saying never use an if today, but just try and avoid them. There are other techniques you can use and some of those we'll see surely. If you can't avoid using a conditional, at least name the concept. So at the top here we have an example where we have a book that's on loan and its due date is in the past and it hasn't been returned yet. Instead of having that, try and name that concept. So in this case, in terms of a book loan, this is describing a book being overdue. So name the concept and encapsulate that logic somewhere. It just makes it easier to change, easier to understand. So now I'm going to go through a few examples of how we can use the open-closed principle in a few different ways. And remember that the open-closed principle is about creating new classes without changing existing classes. So first of all, let's talk about inheritance. And this is the original idea that Mayor had of how you would implement the open-closed principle. So it's very simple to start with. So we have a car example here and a car can accelerate, change gear, probably a whole bunch of other things. And if I wanted to create a new functionality like a convertible, for example, I can create a new class called divertible, derive off of car, because a convertible is a type of car, add the new functionality that I want, and we're done. So very simple. So, as I said, inheritance was the basis of the original open-closed thinking, but there are some trade-offs. Inheritance is relatively inflexible. It's harder to compose things if you want to mix and match stuff. So we try and avoid inheritance if we can. Now, let's look at some other ways that we can do it. So first of all, dependency injection. So this is where you can pass collaborators into a class and then use them internally. So what does that mean? So here we have an example of a library and it has a method called loan that takes a book. And it does a bunch of stuff, but the thing we're talking about here is it's going to log to file whenever we take a loan. Now, this is not particularly open-closed because let's say in the future you want to change how things are logged. So at the moment we're logging to file we maybe want to log to a database or some third-party service. If we wanted to do that, we'd have to go into this class, change it for that to happen, but we want it to be open-closed. So what we can do is we can extract out the login part into its own class and call it a file logger, for example. And then we can pass that in to the library. So here we've got the constructor that takes the logger. You can give it a default so it maintains its existing behaviour. And then we use that logger internally. So in the future, if you want to change how login is done, we don't need to touch this class. This class stays closed, but we can extend it by creating a new class and injecting that instead. And this is how it would look if you wanted to call it. So using the default, the API that Zach has sent us was before, but if you want to have the option of having different loggers, you just pass them in. And it gives you more flexibility because then, for example, if you wanted to log to lots of different places, you can create one logger that logs everywhere and internally it would just call all of your other loggers. So the pin injection is for when you have a role that needs to be changed for a class. So Sandy Metz did a really good talk at RailsConf this year. So if you want a more in-depth explanation and some more examples of how to do this, then definitely check that out. So the next one is the decorator pattern. So this is just around wrapping an existing object to extend its behaviour. So here we have an example. So we have a method for importing products. It takes a file path, and it reads it as a CSV file, loops through all the rows. It then does some validation. So if the name is present, then it does some stuff. So for this example, there's a couple of problems with it. So first of all, it's reliant on it being a CSV. So we could use dependence injection to deal with that. We could support other ways of reading files. So I'm not going to talk about that part for now. Instead I'm going to focus on the validation and the conditional. So as I said before, ifs and conditionals are where your business rules, it tends to be a magnet for your business rules. So what's highly likely that's going to happen is that these rules will change. So at the moment it's just the name that has to be present. But in the future you can imagine that someone will say, actually the product ID has to be there, or the description, that kind of thing. So what I really want to do is extract this out and make this class or this method open-close. So how to do that is let's create another class. Let's call it product row, for example. And this can take the CSV row into its constructor and we store it. And then if we add this valid method, we can encapsulate that bit of validation in there. And then we can use that in our class. So as a quicker side, you can dry this up a bit. So if there's a thing called simple delegator, and if you're not aware of what it is, so you drive off of it, it's part of the standard library. And whichever object you pass into the constructor, it will then store that. And then any messages you try and send that your class doesn't know about, it will get delegated to the object passed into the constructor. So this is much cleaner, nicer. So if we now use that in our original example, so I've just split this up into two methods. So the top method now just deals with reading the file from CSV. And then for each row, we just wrap each of those CSV rows with our new product row class. And then in the method underneath, we can get each of those, loop through them, and if a row is valid, we do some work. So that's a bit easier to read, and we've extracted out our validation. But we still have a conditional, so I'd like to remove that. And we can do that by using select, which is on innumerable. So now in our top method, we're just reading the CSV, each of the rows, we then wrap with our new product row, and we use select to just get out the valid ones. And then inside our method that does the actual business, the interesting stuff, it's just a simple loop. We just, for each of the valid rows, we can do some stuff. Now we don't have any conditionals, and we've extracted out the logic around validation. So a decorator pattern is useful when you're separating concerns, for one thing, and also when you don't have control of when an object is created. So in this example, the CSV row objects we were in control, that was created for us by the framework, but we can extend its behavior by wrapping it in a decorator. So the next example is the command pattern. And the command pattern is for encapsulating behavior in a class, and it allows you then to pass that behavior around. So in this example, we have an image class, and an image can open a file, and it will store it. And you could probably have some other things in here, like what dimensions the image has, or what color a particular pixel is, that kind of stuff. But we've also started to add some methods around effects. So we've got a blur method and a grayscale method. And when you see this kind of stuff, it's not a big stretch to think that in the future there will be more effects you want to add. And if you did, you'd have to edit this image class. So what I want to do now is make this image class more open-close and take out these effects. And this is how you'd call it at the moment. So you'd create an image, and whenever you call an effect, it would take the current image, apply the effect, and return a copy of that image. And then you can chain those together. So the API is quite nice, but the class itself isn't open-close. So what we can do is we can create some extra classes, we can extract out those effects, and then if we make a slight change to image, we can add this apply method that takes a list of commands, and then we can use reduce to go through and apply all of the commands. So if you're not familiar with reduce, basically it takes a list of things, in our case commands. It will iterate through all of them, and then it will end up with one single result at the end. And how it works is it has this idea of an accumulator, and you can set the initial value of the accumulator by passing it in to reduce. So in this case, we pass in self, which is the current image in its current state. And then for each time we iterate through, we pass the accumulator as it currently is and the current command. We can apply that command and whatever the block returns, which will be the new image that becomes the accumulator. And then whatever the accumulator is at the end we pass it in to reduce to go through. So now we can use it like this. So instead of having a chain of commands like that, we can have just image.apply and you pass in the class, the command that you want for the particular effect. So the key thing here is that in the future, when there's a new effect, let's say you want, I don't know, some polarizing or something like that, I don't need to change image. Image stays stable, doesn't need to be changed. I create a new class that does that effect and then I can just pass it in here. So the command pattern is all around encapsulating a behavior and then allowing you to pass that behavior around and use it. Okay, so this next example is slightly longer. So hopefully you're ready for this. Okay, so service locator pattern. So this is around looking up functionality at runtime, depending on what your needs are. So here we have an example. So we have a class notification center and it has a method that sends a welcome message to a user and at the moment it sends it via email. So we have this internal method called send email, text an email address, and it takes some kind of content flag so it can go and look up the content for this particular message. And this is fine, no problem. But in what happens when a new requirement comes up, your boss says, right, users love getting emails all the time from us, but some of them want to get their notifications through SMS instead. So we want to add the option for them to pick SMS in their settings. So obviously we do the easy thing. We add a conditional. We say, right, user, look at what their notification method is, their preferred notification method. If it's SMS, we'll then call this internal method called send SMS, which takes a mobile number and again this content flag, and then we'll send them an SMS. Okay, great, fantastic ships. All goes well. Your boss is super happy. And he says, a few weeks later, he says, right, ask on so well, we want to add another option. We've got some super users that want to allow webhooks. So they want to give us a URL and they want to integrate with their Slack or something like that for other notifications. And you say, sure boss, no problem. Let's add another conditional. We'll check for webhooks, we'll do the same thing. So this is code rot to me. And what you see here is that humans follow patterns. So you go to a code base, you see how things are done at the moment and you just copy what's currently done. That's the easy path. And this is one of the reasons why I've tried to avoid conditionals because you just see this stuff grow over time. So when a new requirement comes, no, no seriously, right, we're not going to add any more conditionals. This is not the right thing to do. Instead, we're going to create a class. So for each of our notification methods, so for email, SMS and webhooks, we're going to create a new notify class and we're all going to have this deliver method that takes a user, and from that, they can get the information they need to be able to send and they'll take this content flag to get their content. However that works is not important for now. Once we've created these classes, let's do some small refactorings over some time now to implement this and try to make this more open-close and a bit easier. So the first thing is, we'll get rid of all those internal methods and we'll just use these new classes we've created. One. Now step two is let's just clean that up a little bit. So we had a big if statement. Let's just turn it into a case statement. We haven't changed the logic. We still have this conditional. But now it's a bit easier to see some duplication. So you can see we have this new deliver user welcome on all of those cases. So what I'd like to do now is just refactor that out and just remove that duplication. So if we just split the looking up or at the bottom, it takes a user and then depending on the notification method we'll return the class that can deliver notifications in that method, in that way. And then above it in our null, in our existing method we'll just call the method that looks up the class and then call deliver like that. So what I want to do now is just extract that lookup into a separate class because I think that's a separate concern. And so now what I've done now is I've just created a new class called Notifier Registry and that has a Notifier 4 method and you just pass in the notification method. So you pass in email or SMS and that will return the class that can fulfil that. So now this class is now open and closed because in the future when I add more ways to notify users I don't need to change this class. This class will just look it up from the registry. And our registry just looks like this. It's just the big case statement we had before. Now this is not particularly open and closed because as I said in the future when I create a new class that does some stuff I need to come in here and change this. So let's look at how we can make this open and closed. So if you look at this closely you'll see that it's actually just a mapping so we have a symbol equals a particular class. A symbol is a particular class. And in Ruby and other languages we have a construct for this we have a hash. So now we've removed the conditional all together and in our registry we have this hash that maps our methods to our classes and then we can pick out the appropriate class from the registry using fetch. So fetch is a method on hash and if you're not familiar with that you give it the key you want to look up and if that value doesn't exist in the hash then it will return a default. So we're defaulting to email notify here. So the rest of this now is how can we change our hash to be more open close? Again still at the moment whenever I create a new class I have to add that class to the hash. So we'll come back to this in a second. One of the benefits now of having all of these things in a registry means that you can power other parts of your system from the same list. So if we had let's say a profile screen for our user that allows them to pick how they want their notifications we can drive it from our registry. So here we just have the notification registry we pick out all the methods and we generate a drop down from it. So you can actually power other things from your system from the same place. So now the problem we have is how do you populate our registry in an open close way? And there's a couple of options. So first is to treat it as just configuration. And this might look something like this. So maybe in your initializer if you're in Rails or some part of the load loading of your application you just say well I'm just going to have this as configuration. And this is okay. There is a downside though. It means that you have to create a class and you have to remember to add it to this configuration. And you can forget. You can have typos. And there's a way to this to go wrong. But it is super simple and super easy. So there's always trade-offs. Another option is to maybe have some auto registry. So let's get classes to register themselves with the registry and then be available. So one way to do that is to by convention. So to do this first we have to change our registry slightly. So remove the hash entirely and just have an empty hash. And then we have a new method at the top called register. And that will take a method. So that will be email or sms. And the second parameter is the class that fulfills that method. And then we just store that in the hash. So the method is the key and the class is the value. And then we have our same look up and we can do that by adding a new method called load. And this will be called at the start-up of your application. And for a particular folder in your app it can require all of the classes in that folder. We then look at all the constants in your system. Loop through each one. And look for all of the ones that end in Notifier. We can then strip off the Notifier bit and keep the first bit and make that the method. So if it was email Notifier you should strip off the Notifier and just have email as the method. And then we can get the actual class. And then we can call register that takes the method and Notifier. So this would work, but there are some downsides. So first of all your classes have to be named in a particular way. And the other thing that's potentially wrong with this is that you can have classes register themselves where they're not actually Notifiers. Maybe they just happen to have the same name. So you end up with some classes in your registry if you're not careful that shouldn't actually be there. Another way is to allow classes to self-register. So let's see how that might work. So if we make a slight tweak to our registry class and our register method now just takes a class and a class only. And then internally it asks the class what method it satisfies. So if in the case of our email Notifier it would just respond and say it supplies email. We use that as the key in our hash and then the class is the value and then our lookup stays the same. So I've created this module here so it's a bit complex but don't worry about the detail. The important part here is this send notifications via a few lines down. So this would add a class method to your Notifier classes if we included it and it allows you just to supply the key for how your how your classes get delivered. It will store that and then it calls register internally and it passes in self and self at this stage is the class itself. So how this would actually look. So this is an email Notifier. We'd include the module and it gives us this macro. So send notifications via email because this is our email Notifier and then we have our standard deliver method. So here we can call our class whatever we like but the class says what it is, what it fulfills. Now this totally works. So if you were to do this what happens is whenever this class is required it would register itself with the registry and if you power your UI from the registry it would then appear as a new option in a drop down and when you actually go to the Notifier we'd look up the Notifier from the hash and use that to deliver. So it totally works except it doesn't work. If you're in Rails that won't actually work. There's not entirely true. In production it would work because all your classes are required and this would work when that happens but in development and test your classes aren't required all in one go. They're only required when they're referenced and because our classes are never referenced they never get loaded and so they never get into our registry. So you'd always end up with a default and it's due to this setting here. So how can we fix that? So how we can fix it is relatively simple whenever we go to look up a Notifier from our registry we can just check to see whether it's already been loaded and if it hasn't we can just go to our particular directory that has our Notifiers make sure they're all required and then return. We can set this flag to make sure we don't do this all the time. So if you were to do this this would actually work and I've got a small demo to prove it so I'm going to do this totally live coding. So here we have an example so here we have the drop-down where the user can pick the notification method, it saves it and when we click Notifier it's going to send the notification by the selected method and you see here in the log just in red this is the method that was used so that was sent via SMS. So now what would happen if I wanted to add a new way? So here we have an existing Notifier just looks like I've just seen before or I should be typing. So let's say I want to add a new method that sends a notification to all existing using all existing Notifiers so all I need to do is to create a new class so and I can call it whatever I like so we're going to notify all the things we'll include our module that does does our magic stuff we create we add our macro that says how we deliver things we add our deliver method just like all the other classes do and I'll come back to this in a second so I'm just going to create a quick help method here this is going to give us a list of all the existing Notifiers in the registry and we're just going to do a quick check we're going to reject ourselves otherwise we end up with some infinite loop nightmare and then inside Deliver we just loop through all of these Notifiers in the registry we're going to call Deliver on each one of them and so if this method is selected we should be able to notify via all existing methods so I just created a class I didn't restart the app now when I go to the UI because it is driven by the registry I have a new option that I can save it saves it I want to click Notifier it sends a notification to all existing notifications thank you so that was a big long example and hopefully I was able to explain the way that was followable but the point here is that this was to kind of take it open close to the nth degree I wanted to extend our application without changing any code and I was able to do that by just creating a new class put it in the right place and we had new functionality and just talking about how recapping how we populated our registry so there was three different ways and each one has got pros and cons so the first way we looked at was configuration the pro to that is it's super simple and really easy you get a side benefit of that which means you can register different things in different environments so let's say you had something called an external service and in staging you wanted to do something slightly different you didn't want to call the external service for some reason you could use that for your configuration but con to that is there's two steps to it you have to create the class and remember to add it to your configuration there's also the convention thing we looked at that's really nice because you just create a class of a certain name the downside is it has to be named in that convention which sometimes you don't want and also you get the thing where classes that just happen to have the same name might register try and be registered and then the last thing we looked at was self registry where the class kind of broadcast what it supports which is really nice because you just create a class you call it whatever you want and it just works the downside is it can be a bit too magical so maybe you have new people on the team and they just don't know how this thing wires up so they're pros and cons to all these things so the service locator pattern which is what we're looking at at moment this is where you look up behaviour at run time and then when change comes you just need to create a new class so for me this is all about balance and trade-offs and I've gone for a whole bunch of patterns there now this is not a license for you to go out and go pattern crazy and just invent all these patterns and just apply them all to your code so I've kind of used them where it makes sense and just good object design really helps with making your code more changeable so here's a quote from a really famous guy so it may seem like overkill in the beginning but as your code base ages you're going to rid the rewards of good object design and if you want to tweak that it's totally fine and yes I did just quote myself but changing software is more than just a bunch of design patterns what you need to remember is that code is much easier to change if it's easily understood and that means naming things well making things small that kind of stuff also remember that code is red many more times than it's written think of your co-workers think of your future self I've written some code and I thought it was good I come back to it six months and it's like what the hell does this do? I don't even know so just think really carefully when you're writing code make it easier for your future self in particular and also as we saw in one of those examples we follow existing patterns in our code existing styles so what happens is if you start off badly you come back to existing code and you want to change it you follow what's currently there you don't necessarily change into better ways of thinking so you may have spotted a theme through this talk and I want to just say it's really okay to create more classes right make your classes small well-focused, named well and whenever I say this to Rails developers in particular they kind of freak out and they're like where do I put my classes? they're not models or views, I don't know where they go and I would say first of all it doesn't matter, just put them somewhere don't use that as an excuse not to do that but what I tend to do is group classes by functionality so maybe have a folder that's around security or a folder around authentication or whatever it might be and group by functionality rather than pattern that's probably bad I would say so just to finish up some things to consider create classes that are focused on on small things go look at solid if you haven't looked at it already and remember this kind of trade-off between simple and easy immediate short-term short-term wins and I know what it's like if you've got an investor demo in an hour you just have to get stuff done, that's fine but kind of think about it, if you have a bit more time try and think about the future and it's all about balance and trade-offs and some guidelines that I try and follow myself is name things well make things small avoid conditionals and also try and avoid nails so I haven't covered that in this talk but it was really cool so check that out so I work for loyalty line we're currently hiring I have stickers and t-shirts if anyone wants one, come and say hi ask a question, I'll give you a t-shirt, no problem this has been on Twitter feel free to tweet me questions and stuff that's it, thank you