 Me if you can't hear me raise your hand ha ha ha ha that joke never gets old Okay, let's get started Okay, so The title of this talk is the four rules of simple design some lessons from watching a thousand programmers work on Conway's game of life It's actually more than a thousand, but I didn't feel like actually counting it about me. I'm a developer That's my cat Zach She's a awesome So I want to start by talking a little bit about coder treat Coder treat which is where a lot of these lessons came from I've been a facilitating it. It's a day-long workshop We work on Conway's game of life We do basically we do 45 minute sessions where we work on the problem And then after every 45 sessions we delete all the code and then you start again And then each session we introduce new constraints like no if statements or no Primitives around across method boundaries different things that let you practice and then we swap pairs after every session It's focused very much on low-level development skills The goal isn't to finish the problem, but to practice trying out new techniques We do TDD iterative design we pair and we really focus on these four rules of simple design which over the years I've started to come to accept as the core design principles For writing code and when you're doing refactoring all the other principles tend to come from them I've found that you can usually just by following these rules You can build up all the rest of the design principles such as solid Etc. The original idea for coder treat happened in 2009 Four of us Patrick Welsh, Nayan Hajwatwala, Gary Bernhardt and me. We were at a conference Complaining and bemoaning about the state of everybody else's code, which is a common practice for developers to do From 2009 to about 2013. I ran these code retreats around the world Spreading it meeting other people having other people facilitate and just sort of doing it So every time I ran a coder treat I would see Usually about 20 to 30 people work on this problem in pairs and ever since we swapped pairs every day I saw about You know, whatever 20 times 5 is Early on in the In the years of code retreat format was heavily influenced Alex Balbuwaka from Romania JB Reinsburg or some other people had some really big impact on how the format itself evolved We started this thing called global day of code retreat. It's a global event where we have code retreats running in cities all over the world 2011 we had a hundred more than a hundred cities take part all on the same day 2012 we had a hundred and fifty plus cities and then last year we had our biggest yet Which we had a hundred and seventy-nine cities all doing the same workshop on the same day So there's a lot of learnings from watching a lot of different people try the problem And so this talk is really about sharing some of the design ideas That I've come up with or not come up with but realized after watching people try to work on this problem It turns out that most developers come up there's about three or four or five different approaches people take and so Seeing it over and over again I started to get an idea of some of the Reasoning behind why they do that as well as how to apply the four rules of simple design to improve the code So this talk I'm going to share some design lessons just a little bit more talking and then I'm going to open up them And I'm going to start writing some code and showing you these examples It's really about subtle design decisions some of the things that I'm going to be showing seem Focused on minutia, and that's really what they are. They're not just these gross Don't write hundred line methods. They're really about very subtle understandings of design aiming for the goal of being able to change your code more rapidly since the only thing that's constant in Software development the only thing that we actually know a hundred percent for sure is that your design or your requirements are going to change as You build your software. You're going to have to make changes to it. So a good design is Probably doesn't exist But a better design if you have a choice between two of them a better design is one that's more easily changed so this talks really about some just a Couple design decisions that I've seen over the years that make code easier to change Four rules of simple design were originally codified in the late 90s by Kent Beck and Have sort of been discussed and everything, but they haven't really changed that much the first rule is that test pass This contributes to your design because if you can't prove that your system works It doesn't matter what kind of design you have you've got to be able to prove that it works The second is that your design and your code expresses the intent It's clear. It's concise. You can look at the code and understand what it's supposed to be doing This often I think of as just good names name your stuff Well spend the appropriate time give it the respect it deserves about Naming things well and if you do that you start seeing influences on your code The third is no duplication or the dry principle. I don't know if anybody's heard of that Out there. It's the don't repeat yourself principle too often. We think about duplication in terms of code But it really states that all knowledge in your system should have one and only one representation and We'll have an example in here of knowledge duplication rather than simply code duplication and the fourth is small Once you've Accomplished these other three look to see if there are there are too many pieces in your system and get rid of things that you don't need This is sort of the least of them the last rule that you apply in general two and three the Expresses intent and the no duplication you iterate between You fix names that exposes duplication you fix duplication that exposes naming problems and you sit and refactor and for me When I'm actually sitting there writing code on a day-to-day basis and on a minute-to-minute basis when I'm making my refactoring Decisions, these are what I'm keeping in mind now not larger scale higher level design guidelines About that Conway's game of life, which is what we work on at code retreat. It's a very simple Thing to work on it's simple to understand But the beauty of it is is that with these very simple rules you can get some amazingly complex patterns I have a couple examples here that unfortunately, so basically in Conway's game of life You have a grid an infinite grid in two dimensions Where each cell in here? It's the white and the black each cell has eight neighbors the diagonals count and A cell is generally considered alive or dead and the point of the problem is to lay out an initial pattern such as these and then to iterate generations to apply some simple rules and Figure out what the next iteration looks like and we'll go over what the rules are there's four rules But basically you can get movement you can get some very complex structures So for example, this is one that is just sitting there iterating running the rules over and over again building generation after generation Here's another complex pattern You can see that there's lots of subtle Subtle patterns and structures inside when you apply these rules So oops, let's bring this back up Infinite two-dimensional grid again cells in the grid are considered alive or dead You set up an initial pattern and then you calculate subsequent generations based on simple rules The rules themselves are if a cell is alive You count the number of living neighbors that it has and it stays alive if you have three or four living neighbors It dies if you have less than three. It's sort of an underpopulated undernourished a lonely environment if you have more than four living neighbors You also die in the next generation and this is sort of an overpopulation Situation dead cells if you have a cell that is dead in one generation and it has exactly three Living neighbors it comes to life in the next generation So just by applying these rules over and over and over again You can calculate subsequent generations and you get those really complex patterns I Already showed those Alright, let's look at some code So as I said, I'm just going to show some some general things that I've seen with some small coding snippets and then doing some analysis on that code based on the four rules of simple design and refactor it into something that Generally is easier to change now It will seem a lot like I'm nitpicking like I'm looking at very small things that in a larger code base Or on your day-to-day you may go. Oh, I don't even worry about that But these are really important and if you get them into your mind you can see and get a lot of benefit out of there So the first one I want to talk about is I'm actually gonna just type stuff in now is In general the first time that people build this they look at it and they say well I have a cell there's this concept of a cell I'm gonna type do my examples in ruby, but I'm gonna trust that people can read ruby. It's not really complicated I'm not doing anything crazy So in your head translate over to some other language if you are in another one So in general people build a cell class they start with it often We've been brought up with a design methodology where you look at your statement of the problem statement of the domain and you find the nouns and You say well, there's a cell in there clearly and so they'll generally come up and Build and build to attribute or an attribute called alive and this is usually either true or false So it's a Boolean Thinking that's what the problem statement is you have a living and dead cells Then since we have to calculate what the next generation looks like they'll generally will generally write something like this Have a method that looks at it in The next generation and you'll say something like well if I'm alive Then let me look at the number of neighbors if it's equal to two or If the number of neighbors is equal to three then I stay alive Otherwise if number of neighbors equals three then I die So this is a very very clear statement of the rules as we read them in there Now what I'd like to look at with this is first off is There any duplication in this code? What's the duplication? Number of neighbors. There's that. There's the number three shows around so and One way that a lot of people do is they go and they say well look at that number of neighbors three Look at that three. Look at this three and three these threes are duplicates. So we can Get rid of that and do something like this if I'm alive and number of neighbors equals two or if my number of neighbors is equal to three and then Say aha, I just shrunk the code that must be a great refactoring But the problem with this refactoring, which is that seems like a reasonable one is that It's misunderstanding. What knowledge is it's looking at that three and thinking that those two threes are the same it leads us to a situation where We now have two different pieces of our code two different pieces of our rule set the Rules for when you're alive and the rules for when you're dead and we have them mashed up together and This makes code hard to change when you have different pieces of your system All sort of mashed together if somebody comes and tells you I need to change the rules for a dead cell It makes it harder to come in here and pull it out And so it's really about looking at it and understanding what the knowledge is So if you get rid of that refactoring and start thinking in terms of what these are should be named We're mixing in a lot of code here. It's kind of a little hard to read It's not very expressive about what the domain looks like so you really might think about if you take a different Strategy and instead focus on your names You might say that if I'm alive then I want to look to see is am I in a stable environment? Pull that out to a method You might also on this one say in a we'll call it a genetically diverse environment So a different refactoring is by focusing instead on the names of it and making it concise making it clear making it very Expressive and looking at it and saying well if I read this code It says if I'm alive in the next generation if I'm alive Then I look to see if I'm in a stable environment otherwise in a genetically diverse environment Now that's all fine and dandy But how do you choose? Which one do you do? how do you choose not to take that three and a lot of the time it's because We are focused on the code level we're focused on this number and so before you Come and say these two threes are the same. I'm going to sort of refactor this take a larger look and look at the a Slightly larger scope the number of neighbors equals equals three which is actually part of this statement This statement is not the same as this statement. It's not about the code. It's about the concept in the code It's about making it expressive and clear what you're actually doing and that's why taking a Naming approach can be very handy So there's the first example the second example is about looking at Do-do-do-do-do-do so we look at this code we want to look at it and look at it in terms of What this alive is so if you look at this if statement There's a little bit of a smell and that we have this if else statement and in general those aren't all that great But if we think about it just having this alive here Makes a really strong statement about what were our code is intending to do this is saying that sort of the default situation for a cell is alive It says I prefer it to be alive and if I asked you what's the other option? It's not as expressive in this it doesn't very clearly state It's alive and dead You're sort of assuming that those are your situations. What you also run into Is the fact that if I need to add what if I need to add a new state? What if I need to add this so what I'm doing is I have this this attribute called alive But it's not really descriptive of the cell What we really are looking for is something that is more along the lines of what's the state of the cell Because it doesn't just ripple between true and false It ripples between a concrete idea an actual concrete state And so we might want to look at it and think of it in terms Let me move these as I'm done so we might take that and say well since alive Doesn't include the other option. It's not as expressive. It doesn't include the entirety of our domain We might change it into something like state And at that point you might say aha Well, then I can do something like this and that's a little more clear It's a little bit more clear to look at that. I should have made this font a little bigger too I'm getting old with my old age But there's a couple problems with this One is that we're missing a default We're still mixing up We're still mixing up the algorithms We're still mixing up the decisions about what do you do when you're alive and what do you do when you're dead if we Change one of those aspects. We then end up in the same code as the other one So if we need to change something about alive, then we are in the same code that has to do with being dead and That's a that's a little bit of a problem because it's dangerous. It's set makes our code a little bit more fragile because if I come in and I make a Add, you know, add new rules to being alive and it breaks being dead Often we run into that. I mean, I know I run into it a lot where we have you make a change somewhere and it breaks something that's really unrelated and so Coming into this We're running into something that I term sorry Procedural Polymorphism Who is that readable? I'll just write it like this procedural Polymorphism So if you think about polymorphism polymorphism is a way to either call a method or send a message to an object and to have more than one behavior happen, I can call a method I could do something like Next generation and it's not it could be one of two different behaviors It could have be one or two different algorithms based on this thing at the top. It's a live in next generation and so What we're doing here is we're taking a procedural technique and we're applying it in an object-based or an object-oriented language So it's not in and of itself bad But it does have the potential to cause problems because procedural polymorphism tends to tightly couple the different branches together I don't know if you've heard there's a lot, you know a lot of times people bring up this idea You know don't use if statements or don't use Branching and this is really what they're talking about is being able to make Make your code very single purpose so that when you do change it, it's easier not to break other things and so the technique that I tend to use is One of my favorite words in the English language, which is reification what reification means is to take concepts and move them elevate them into existence is taking a core concept in your system and making it a first-class entity in your system and the way you do that a lot of times is Look at the look at the actual branching conditions and Think about what they represent So the state equals alive represents a living cell state equals dead represents Represents dead cells and So whenever you find yourself in a situation where you have this procedural Polymorphism where you have if statements a good way to get around it is to elevate them into types So at this point I then could have something like a live in next generation in stable environment genetically diverse environment and so at this point what I've done is I've taken a piece of code that is has very tightly coupled to different aspects of the system to different algorithms and Separate them into two very very simple Constructs and you can even if you want if you're of that nature since this is you know Number of neighbors equals to or number of neighbors equals three You could say well, I probably could just drop it Bring that down bring that extra method that extra message that's being sent I could probably drop it down for this case because it's so focused and So it allows us to name things pull them out into reified objects and then Simplify even further and so at this point I now have taken procedural polymorphism a if statement based branching and Moved it into tight based polymorphism. So this is now tight based polymorphism Which I will go so far as to say is the preferred form of polymorphism for For object based languages an side benefit of this is if you study the solid principles The single responsibility and open clothes and Liskov and interface segregation and dependency inversion This one actually better satisfies which what's called the open closed principle Which states that a system should be open for extension closed for modification This says that if you want to change your system in some way adding new features It's best to add code add new structures Then it is to change existing code because once you have code out there and you've tested it And it's working the worst thing that you can possibly do is to change it because then you have to retest it Refigure out if you've broken anything whereas suppose we have a third type We have something like a zombie cell and it has some sort of rules at this point I can simply add new functionality to my system via extension via adding a new class and So this really does come into play and it's very very nice to have so that's another type of thing it Gives you a good way the other thing to look at is it gives you the opportunity to start looking at these names a little bit better if You look at the domain if you look at this game of life It talks about living cells coming to life and it talks about dead cell or dead cells coming to life and living cells staying alive it Doesn't really talk about the implementation alive in next generation is much more closely related to the Implementation of the system where you're going generation to generation rather than the higher level concepts that are in your domain So by taking these out we can do things like let's give it a better name and so we continue to apply these four rules of simple design by Looking at this conciseness and this expressiveness and saying aha this expresses a little bit better the system that I'm working in So this might be you know eat something because zombies of course eat people so that's the second example that I want to show just around naming and around this idea of using Procedure or converting procedural polymorphism into tight-based polymorphism Based on looking at the names and looking at really what these variables these instance variables or properties mean Okay, so Let's get rid of that one now now that we have cells though We one of the other things about our system is that we tend to have locations We talk about where it is on the board and one of the things that you might want to have be able to do is say you Have a class that represents through not the word but the world Go moving on in your design you might say well, I'm gonna have this world class that represents the grid itself And so a lot of times I've seen a reasonable design would be setting a living cell at some place maybe checking If there is a living cell at another location and this seems like a reasonable thing to write The world may be a bad name for the class, but we won't worry too much about that So we've probably written things like this But if you think about it you also might come into your class living cell and add an X and a Y property and say Okay, well cells have this XY value. They know where they are on the grid I can from an external client call set living say whether check whether it's alive somewhere now There's a subtle duplication here that is not always picked up on Anybody see a duplication here the they share the location. That's something there's an Even more subtle is this XY look at this XY. It's repeated over and over and over again Now if I asked you to change the topology to change the dimensionality of your system How many different places do you have to go in and change for? And you could already and I it's I'm only 30 seconds into typing So you've already got this duplication and this really goes into that idea of duplication of knowledge It's about looking at this XY That XY is a very concrete case of knowledge of our topology knowledge of what the grid looks like knowledge of where we are and It's very easy to remove that and you remove duplication generally by extracting things so what you do is you take this knowledge this concept and Maybe you make a new class called location and it Has the X and the Y at this point You can do you basically are just passing locations around so like this Now if I ask you to change the dimensionality Change the topology of your system. How many places do you have to change it? just the one nobody else really cares about it and I'll repeat again these these are very subtle these are sort of things that in your day-to-day coding you might go well this is just taking it to the extreme and It might be but how many times have you gone in and had to make a change and it should have been a very simple change And then find that you have to repeat it over and over and it doesn't take that long to extract it I don't even have fancy refactoring tools like you do and C sharp and Java if you were in that it would be even simpler to do This again relies on this concept of reification this concept of taking a piece of knowledge a concept in your system and Creating a real thing from it creating something that you actually can see and feel and Another thing is location is such a core part of this system. We're gonna have neighbors we have to figure out where things are relative to each other and Yet, it's so easy to just to go. I'm gonna pass X or Y around and Not make it into a core part of your system We can also if we wanted to Approach this problem from the concept of naming X and Y are awful names The the fact that we know that we tend to think of them as like row and column is entirely convention It's entirely our language. Nothing says here. So if I looked and said X Y, which one's the column and which one's the row? You wouldn't necessarily know you might not have to care, but just from a naming perspective I would rather my method actually be explicit about what I'm doing I'm setting a living cell at the location and So you can come in here and deal with it just from a naming perspective. Oh Now what this would allow you to do is if you had an instance of the object you might Pass it a Tuple and what that does is by taking this and making it Location and giving it a better name. You're taking the duplication You're taking that concept not the duplication, but you're taking the Concept that is poorly named in your method signature and you're pushing that poor naming up your stack a little bit and you can continue to do that up and up and up and eventually I lied I do oops Eventually you can probably do something and Keep pushing it up Eventually you end up saying oh well. I clearly need some sort of duplicate or a some sort of location concept here Okay, so this is a really important one in this and because of the subtlety of this Understanding that duplication and the dry principle is about knowledge in your system. It's not necessarily just about the fact that there's code So we talked about this duplication as well where we have the at both the living and the dead cells have The X and the Y in them now one thing you might want to do and Unfortunately, I see a lot of people doing this is Moving this up into a base class and I'll just say one thing for the love of all that is good and holy Stop using base classes stop doing inheritance and that's a whole nother talk as to why instead Let's look at the solution of this from we do have duplication here It both of these cells contain this location, but rather than taking a very awful and God-forsaken construct like inheritance and Using that as the way to solve this Instead take it as an opportunity to go. Well, maybe it isn't cells that have locations, but maybe locations Have a cell Why does that why what is the cell we already when we built our cell in the past example? We have the cell responsible for the business rules about whether it Continued on in the next generation or the previous generation So if I have this cell with a method called stays alive and I also have this Where it has how many different things is this doing now? It's keeping track of where it is as well as keeping track of business rules This tells me that the cell is Sort of what's the meaning of cell? Is it a good name for it if it's doing both of these things? Is it managing rules? Is it managing the locations? so By taking it out of there instead of just moving it up and getting it out of the way with the base class Actually ask yourself. Can I take it? completely out and By doing that by creating a location object You already have a place and we created this location object based on Something completely different when we were removing the duplication about our topology Where's my little marker? Here it is the other really nice thing about this is that oftentimes you might have one of the things that we we kind of need to do is Have a method one of the things if you Looked at what we had this is probably a method We need part of the game part of the rules of the game have to do with counting the number of living neighbors So it makes sense that you would have a method called give me the neighbors for this Now Where does this method go? Does it go on the cell does it go on the world? We have our x y so we're not yet building that Because though We had extracted out this location object because we had reified this concept into our system We have something that I call a Behavior attractor if you start moving through and very aggressively Reify concepts in your system Take those x y's find that duplication and move them into real parts of your system You end up with a lot of classes That are Exactly fit in your business domain. This location is a very really strong aspect of the rules It's a strong aspect Now it just came to life because we were eliminating some duplication It came to life for something totally different. We were isolating that x y the knowledge of the topology But down the road we end up wanting to Look at what the neighbors of a location are and When you think about where to put methods? There's generally two ways that we do it generally when we make decisions about where to put things we either go Where is it closest to my data or or more likely what code file? Do I have open right now? You laugh because it's true. I laugh because I've done that many many times But when you are pulling these real concepts out Very very often you find that you already have a Concept a class that is accepting of that method It's clear if I came to somebody and said look I have this location object I have a world object and I have a cell object Where should I put something that talks about neighbors of a location? The location object so you end up with oops You end up with these Classes that when you have a new behavior, they're sort of just attracting them They're like come on. I'm the place to do it And so these are what I call behavior attractors and you see them a lot around this You really do start to see this these pop up in your system a lot. Okay Do-do-do-do-do-do Okay My last example Down here. Ah Second, let me pull up my clock real quick. Oh Look. Oh, thanks. I actually threw them on the ground, but I didn't throw them angrily enough Okay, another thing about naming is I haven't talked anything about testing and of course you all aggressively write tests through your code right So one of the things is I'm going to give you an example of a test so One of the when you first start you might say well I'd like to start at the world and talk about adding cells to the world because I need to set up my initial pattern so you might be like test a New world is empty That's a reasonable test name So I can come in here and say give me a new world and then assert that my world's living cells and Let me count them is zero And we put the code in there return zero. We write a new one test a World with a living cell is no longer empty so we might go Here and let's say set living at Let's create a location object. I wish I had time I would talk about why I dislike that But we won't and then we go on when we implement it but if we when we talk about test names We talk about how our test names really should be describing the behavior of our system and and Less about the low-level implementation and I kind of did that here. I said, you know test a new world is empty Test a new world with a living cell is no longer empty That's really kind of talking about how our the higher level behavior aspect of it We don't come in here and say Def test the count of living cells of New world is zero Hopefully people wouldn't write that test name Instead you do this But look at the look at the code that's in there There's no symmetry here So we are saying that the world is empty, but we're actually Calculating world living cells dot count We're not letting the test name influence our API design One of the things we talk about with TDD is that it's a design methodology and one of the aspects of how you can do it Is by writing your test name putting the effort into the test name to make it good and make it really descriptive of your behavior And then we write our code to reflect that the first the writing of the test name is our first sort of thought around it and so One technique is to take your test name and actually use that to Reflected in the code itself. So we would want to maybe write is my world empty Our test is our first consumer of our components API So by being clear about our behavior and then letting the test name dictate what the API looks like We're letting the client of our API the client of our component dictate what that API is going to be and I would put forward that this I Would also put forward that I wrote this wrong a certain false That my world is empty and so by Really taking the test names which we tend to put a lot of effort into thinking about what are we describing and Having it directly reflect in the code that we're writing. We can build up nice API's As a side effect of this we tend to Also get sort of a bonus abiding by the law of Demeter where we're not reaching into the world Reaching into it grabbing out all of its living cells and then asking if those are zero That's a rough thing to do and worlds don't like it when you reach into them so it's really highlights that importance of taking and Spending the time on the names and then letting the names dictate down to where you are. I'm out of time That's just a couple examples of things that I wanted to share that I've seen over the years that a lot of people over and over again tend to do when they're coming up with a Situation I think that as I've looked at these I see these a lot in my own code base I see these a lot in other people's code bases. So You know as you go back and start writing code think about names and think about duplication not of code level but of behavior and See about reifying real concepts into your system All right with 26 seconds left. Thank you very much