 have tried to read this book. Yeah, that's about right. This book is just, it's insane to try to actually, it's insane to actually try to, try to read this book, but people say really great things about it. I'll let you read the slide for yourself if you're really curious, but the general gist is that it makes you think about code at a higher level and gives you like vocabulary to talk about what you're working on. And these are these are great benefits, but the problem is that there's the schism in our community. The schism essentially being that there are these people out there that hate design patterns with a passion. They despise them with every fiber of their being, and they have some pretty valid criticisms about it. That there, if you don't really understand the pattern you're using, it's very easy to have the have use it incorrectly. And using something incorrectly is worse than not using a pattern at all, just using something that makes sense for the scenario. And it's also really really difficult to read these. And like the book itself, my question from before illustrates that pretty well. It's, you start reading the book and I think when I first tried to read this book, I was reading it before I went to bed and it put me to sleep really well. I think several nights in a row, like a month of nights, I would just fall asleep and have to reread the same pattern over again, just to remember anything about it. And it's really hard to truly understand the implications. They work really hard to try to talk about different trade-offs and stuff, but it's really hard to understand them sort of at a visceral level. In your gut, you know that the observer pattern should only be used in these situations. So now I want to talk to you about Go. The game, not the language. I bet you didn't see that coming. Unless, of course, you read the description and then you did. So there's this thing in Go called Josaki. Josaki is essentially fixed patterns of play at the beginning of the game. And this is an example of a really common one that I have up on this slide. And there are some... And the idea behind Josaki is when you play these patterns, it's supposed to be equal... Both sides are supposed to have an equal benefit from playing that. And these are things that people have researched. There's a lot of books about Josaki out there. But there are a lot of criticisms about it. There's a schism in the Go world about Josaki. The schism being that, you know, if you try to use these without understanding why they are the way they are, then you actually play worse than if you didn't use Josaki at all. It's hard to read the books. You fall asleep for several nights in a row for several months trying to read these books about Josaki. I can attest to that one as well. And it's hard to really understand why, at a visceral level, these things are the way they are. So, fortunately, in the Go world, they've had a little longer to think about it. Go has been around a little longer than software development. And there's this book that was written called Lessons in the Fundamentals of Go. And in Lessons in the Fundamentals of Go, there is a chapter in it titled How to Study Josaki. Now, the reason I bring this book up, other than giving me the title for this talk, is when you think about, this is like one of the best English language books on Go available. It's the kind of book that you read every time you get a little better and you learn different things from it. And in it, he talks about studying Josaki. And he talks about how when you want to get better at playing Go, one of the places to start is actually to study Josaki. Why do you want to start there? Because these are idealized situations. These are the perfect way to play in this situation. If you understand why you play in this way, then you actually will understand the best way to play in that situation. And if you can truly understand this at a visceral level, you're a better player than you were if you didn't understand that. So he has like three bullet points in this chapter that I've put up here. They're a little hard to read. English is not his first language. But essentially, they say, don't just, wrote memorization is out. And that's true of design patterns too. Wrote memorization, completely a bad idea. If you're trying to actually get better as a software developer, it's not the way to learn. The next idea is to understand that this is the best solution to this problem. So in Josaki, it's the best moves, as I said before. In design patterns, it's the best way to solve the specific problem that they were outlining. Not saying that it's the best in every situation, but specifically for the problem that they're outlining. Design patterns are the best, the best way to solve that problem. And so if you're reading code, the best code to look at is code that is the best solution for a problem. The reason that I say it's the best over and over and over again, is because they did a lot of research when they were writing the book. They worked with a lot of groups, studied a lot of code to figure out how people solve these problems. And so it's not the best from my subjective perspective, although there might be some subjectiveness in it. It's the best because they studied a lot of different code and saw how these same problems were solved in a lot of different scenarios. And these are the solutions that they came up with. And then the other thing that's really important to think about, and this is just my changing of the wording to apply to design patterns, the last thing to think about is that even though a design pattern is awesome and solves a problem really well in the local scale, that is not necessarily true in a global sense. In fact, what might be the perfect solution locally might make zero sense given, taken in context with the rest of the system that you're working in. And that's important to understand, not just to understand that that's something to worry about, but understand the situations where that could happen. So when studying design patterns, what you want to do is you want to, and this is the approach I've taken on several of the design patterns, is you want to create a reference implementation of the design pattern, not like try to find somebody who's already implemented, make it yourself. Make it yourself from the guidance in the chapter. Work like, read the chapter, you're probably gonna have to read pieces of it a few times, but go through the chapter, understand the design pattern enough that you could implement sort of an idealized version of it. Then look, do a really thorough code review on your own design pattern. So on your own implementation. So take every line, every word in your, in your, in this piece of code. Think about how you could change it to make it to what what would what would it mean to change that word, change that line to something else. And if you change that word or that line, why is that worse in a local situation? What global situation could make that an okay thing to do? And when does it make sense to apply this pattern? When does it when is it a horrible idea to apply this pattern? You need to think about all of those things. You should ask yourself these questions, spend a lot of time. I I greatly encourage you to not rush through this book at all. Like take it one pattern at a time spend as long as you need to internalize it because the way we're going to become better programmers is not by memorizing a bunch of design patterns. It's not by knowing what a bunch of design patterns are so that you can look them up at a drop of hat. That was one of the recommendations that they had had in the intro to design patterns was like, Oh, well, you should just read the sort of the first couple sections of the of each design pattern. And then you'll know what the patterns are so that then you could look it up later. My experience with that approach was that I would I spent a lot of time reading the intro to each of the design patterns. Then when I saw situations that I thought sort of sounded like something that I had read about, I go and I try to read the whole section and I'd be like, Okay, that has nothing to do with the problem I'm trying to solve. And so so that that approach really, in my experience has not worked at all. What was worked much better is to spend so much time with a pattern. But instead of it being think instead of me thinking, Oh, I'm going to use the observer pattern. Now, I think I just write the observer pattern then afterwards them like, Oh, yeah, I use the observer pattern there. It's it becomes so so innate in your in your development process, it becomes part of what you do as opposed to being something that you're explicitly doing on the side. So what we're going to do now is we're going to go through a couple of design patterns. And in each of the design patterns, we're going to look at where I'm going to give you an intro to the design pattern as a whole. We're going to look at the look at a reference implementation that I made. And we're, we're not going to be looking at reference implementation all of them because some of them you can think about the implications without building the reference implementation. We'll talk about that in one of the patterns. And and we're going I'm going to show you the approach the the I take and I think is very useful for trying to understand how these patterns are how these patterns work. So the first thing I want to look at is this really confusing diagram that is useless as far as I could tell the first time I looked at it, then I realized when I was when I was going after the design patterns again, and trying to think, well, where do I start? There are there are so many of these and I have no idea which one to start with. And I realized that this is a dependency graph. This tells me which ones I can start with that are safe to start with, because they don't depend on anything else or they depend have very few dependencies on other design patterns. So so it's not perfect because the arrows are reversed on a couple of situations because they're not trying to communicate dependencies the same way that I want to view them. But this graph here allows me to understand that say the observer pattern is something that I want to I want to I want to study early on. And actually observer mediator is one where the arrow is a little is flipped but wills but it's better to study the observer pattern before the mediator pattern. So that's what we're going to start with is the observer pattern. Now, you may have seen this in some code, it's one of the more popular patterns that came out of this book, I think. The basic idea is if you have a a subject in your code base that a lot of other things have to respond to changes that happen in the subject. Commonly, like the really straightforward thing to do is to just take the subject and like push changes to all these different objects. And that's that's very so that becomes very unmanageable when you get to larger scale. And it makes the subject have to know a lot about all of these observers in order to work properly. So what the observer pattern does is it shifts this relationship. So that instead of instead of the subject having to know about different information in the observer, what the subject does is it has a list of observers that it works with. And those that list of observers when the subject changes, all it does is it loops through all those observers. And it tells each of the observers to that it updated. It calls this update method. So let's look at my let's look at my sample implementation of this the the sample implementation of this. I just I'll give you guys a GitHub link of all the all the design patterns, the implementations that I've done. As I said before, you should write ones yourself because that's part of the learning process. But if you want to compare to something that's already been written, you can look at this, you can look at the GitHub repo. This is the subject class that I wrote for that. And you notice that there's this notify method here. And it just loops through all the observers and calls update. The observers know about the subject and they're able to pull information off the subject that is relevant for them. So then we asked we have to ask the question, what if we pass something into the update method? See, I didn't even change a word. I put I put a new word in here. So so I'm even like being more anal about my study than I could have been because I didn't have to because I told you just to change words before. So what if I passed state into the update method? Well, there are different implications to that. One of them is that means that the the the observer doesn't need actually need to need to retrieve the retrieve method. It doesn't need to know about the subject as a whole. It just needs it can just respond to the state that's given to it. So it in some ways is less coupled. There's less coupling between the subject and the observer in that way. But another thing to think about is, what about larger context? What if what we're actually dealing with here is a micro service architecture? And when we call update, we're sending a request to a separate service. And if we're sending a request to a separate service, we have to shuttle all the state about this object across the wire. That's that's going to be really expensive. If all you need to know is how many rows are in this table. So so as as would be expected, broader context means that that this is either a really good idea or a really bad idea. And now that I've looked at this line, now that I've thought about how I can change this line, I know that I know the implications of that. So instead of instead of having to having to sort of blindly apply these patterns, and then later on discover some of the pit falls of trying to pass a whole bunch of state over over a service barrier, I suddenly have a better understanding of that. And I intuitively know when it's okay and when it's not okay to send state across when I'm calling update on observers. So let's look back at our dependency graph. Now that we understand how the observer works, there's enough we can look at the things that are related to the observer and have a context for understanding them. So now that now that I understand how the observer works, I can look at the mediator pattern and have be able to understand that more easily than I would before I had, I had studied the observer pattern. So what the mediator pattern is, is remember before we had a few we had a single subject, a whole bunch of observers floating around. Well, now we've got this really, really complex interdependencies between services, services, objects, whatever you want to think about. You have all of these interdependencies is really hard to think about them all because they're so interconnected. And the observer pattern starts to be more difficult because so for instance, this has to be a subject, but it also has to be an observer to this one. This, this has to be an observer to both of these, but is a subject to that one. It's really complex to try to be make all of these subjects and observers and all the appropriate context. So what the mediator pattern does is it takes logic that is, it takes logic that is generally in a bunch of the different colleagues and consolidates the logic about how these colleagues work together to how to put it into one place so that if you want to know how your pieces interoperate, the mediator, you know to go to this mediator to understand that logic. Now let's think about when this is a good idea and when it's a bad idea. So as I said before, we're not always going to have to look at a reference implementation. I have one and I can show it to you after this if you want. But in fact, we probably we might look and look at it a little bit, but but you don't always have to look at a reference implementation to think about the implications. The question is when is it appropriate to use a mediator pattern? These are these are the critical thinking questions that you have to be doing at all stages of design patterns. When is it appropriate? It's appropriate when you have a lot of pieces that it's unclear how they interact. And it's hard to figure out figure out chase down all the dependencies between them. But when is it not appropriate? What would happen if the interactions between colleagues were really, really complex? If if there's if the interactions were like they were chattering chatting back and forth a lot, they had to ask each other a lot of questions. What happens if you have to actually you have to actually go through a mediator for all that activity? That would make the mediator more and more complex. It would start looking like this monolithic class that every time you had to change a colleague you had to add something to the mediator and the mediator became a liability instead of a benefit. So now we've now now I've gotten even more meta. We haven't even looked at a line of code. We still think about the the the specific implications of this situation and how to address those implications, how to how to deal with those situations. Once again you look at the global context. The global context is everything for this. The mediator itself it's fairly straightforward. You the the concept of the mediator as you move code into the mediator and then the agencies are consolidated. But the global context of how much these colleagues have to talk to each other means everything for if it's an appropriate use of the so the so the takeaway from this, from these two examples are that we the that you should you should apply critical thinking to the design pattern and question every single little piece of it. It seems like it's nitpicking. If you were to do a code review like this it would really annoy the other person. It would seem like at least that's been my experience when I've tried to do code reviews like this. They hate me for for being so specific so so nitpicky about it. Some people appreciate it but most people don't. So so but you want to be more anal than you can possibly imagine being in a code review because your code review yourself you can't get annoyed at yourself can you? Maybe you can. So so that's the that's that's the general idea of how to study design patterns. We've got a few I've got a few more I don't have slides for them and I talked a little fast so we have extra time to look at more design patterns. So the let me so another good example one of my one of the ones I did early on was the was the factory pattern and the way the factory pattern works is when you have a when you have a I have a slide to illustrate the the dependency let me just let me just the factory method pattern. So the factory method pattern the idea is that you have this this method that constructs new types of objects but you you have a lot of you have these basically parallel class hierarchies where they're where they're working to I'm sorry you have these parallel class hierarchies and what's happening is when you want to create a new document for instance you have a lot of different kinds of documents a lot of different kinds of applications but what you don't have is a way to know how to glue the application to the document and the in the relationship between the application the document if you if you just leave it to each of the applications each of the application classes what happens is that the the application part of it ends up being what happens is like that you don't have like type hierarchies or anything like that to enforce the relationship between them so so you end up having problems with like oh well in order to create a document of my document from my application you have to call the new document method but if you if you want to create a your document from your application you have to call the really new document method and that and and you end up not being able to reuse parts because you have very specific ways of handling those situations and the the way to solve this is to basically have a parent class for application and document have a method on the parent the parent class for application that's able to construct a new document and then the subclass of document is controlled through that parent class now the reference implementation for this let's look at an application let's look at the yes okay so let's look at the new the the create document abstract method ah I'm sorry you're not seeing this at all are you let's look at the this is much easier to see so let's look at this implementation here so I've got so I've got this new document method down here that's calling create document when I want to create a new document this method here is associated with actually constructing the document but the but the abstract method of create document is what doc what the subclass has to define in order to be able to use use the the framework that's presented so then the question is what happens if I take away this word abstract what if I remove the word abstract is this still a valid pattern if is it actually solving the problem that I care about if I remove the word abstract so the way we answer that is we think about the implications so that means we actually have to have a default implementation of create document we can't just have a we can't just have a we can't have an implementation that that is we have we can't just leave it empty because leaving it empty means that you're just passing no around passing no around is his own problem and then you have no no handle exception no objects except exceptions all over the place and you can't figure out where they came from so you want to return an actual an actual document here that means the document can no longer be an abstract class you have to have a you have to have a concrete parent document in order to create documents the that don't know about the specific subclass or you have to have a specific subclass the you have to have a specific subclass that most of the applications that's what they're going to want anyway maybe that should be the parent class so maybe you shouldn't have maybe the implication of removing abstract from this method is that you have to make the parent class document also concrete that is one of the possible implications otherwise you the the abstract parent class knows too much about the other the knows too much about a specific application so that's that's one of the implications you probably you want to poke around with that idea a little more maybe you find such may maybe you can think of situations where you actually do want an abstract parent class that is the that's where it started a little more subjective because you're starting to venture more depart more from the original pattern but that's that's an avenue that is worth investigating that's an avenue that helps you learn more about software design it makes you a better programmer as a result of that specific investigation so that's another example where that's that's another example where the where just looking at changing one word removing one word was all we needed to have this whole other pursuit of investigation so this whole other avenue of investigation and then I have one more pattern we can look at if I actually go to the so now that we understand the factory method pattern we can look at the template method pattern and the way the template method pattern works is I'm sorry that's the wrong file so now that we have this this factory method that can create new documents let's say that let's say we oh I'm sorry I didn't blow it up again so the so let's say we have a bunch of actions that always happen whenever we create a document we're not just creating we're not just making a new document we're actually every time we're we're creating a document we always add it we always we always say that we're about to open the document and then we open the document and then we read it that's always what we do with the document well we can pull that particular behavior into a method in the parent class or the parent application class and by pulling the behavior into that class the open document behavior what we what we're able to do is we're able to create a framework for how the how the behavior actually works so for instance we so for instance in this case we check if we can open the document otherwise return null this was this was the actual example in the book I don't like returning null just to be clear there so we we check if we can open the I'm sorry it's not the we're trying no we just don't do anything and then we check for no down here this is where the no object came in in my mind so so we so we have all these steps none of these steps are actually concrete steps or some of them are like create document is because that's the factory method that we introduced in the last pattern but we we have all these abstract methods here and the contract becomes from from this from this class the contract contract becomes that if we inherit from application we're always we're always going to be able to open a document from that application so that contract that's one of the things that is required to be fulfilled some languages don't require enforce like abstract methods so that's a separate problem you can fix that at runtime by like throwing errors or not defining the method in the parent class but but the general idea is that you create this framework of abstract steps the the then you just have to fill in in the subclass so let's think about where this is a good pattern to use this is a good pattern when you have well-defined steps that always happen but when you have steps that sometimes happen what can sometimes happen with the application what can happen is that you you can't actually you have to so for instance let's say create an application that never cares about opening a document well then I still have to create definitions for can't open document about to open document all these things that I don't actually care about at all from a from the perspective of the from from the perspective of the subclass so that suggests the the if you run into situations like that this is maybe not the best pattern to use I think there I can't remember the name of the pattern off the top of my head but there's another pattern that has a separate class that defines the these these steps and in a better way so in a way that allows you to not have abstract methods it just knows how to talk to individual things I that's a poor description because I haven't studied that design pattern yet but but I read the intros of all the design patterns so I sort of know that that exists but that this is a situation so if you have something where you don't want to open it that's an example of a time that you do not want to use this pattern so that's the general idea of how to study design patterns so let's let me go back to my originally last plan slide and so if you want to see the source code for any of the design patterns I just showed you as well as the actual slides the GitHub repo I have up there is available as I said before you should probably write the implementation yourself you learn more that way and then if you look at my blog there's a link to my blog and Twitter okay well if there are no questions thanks for listening to me