 Hi, welcome to Visual Studio Toolbox. I'm your host Robert Green, and joining me today is Phil Jepixi. Hey, Phil. Hey, Robert. How are you? Good. Welcome back to the show. Thanks. Thanks for having me again. Phil is an MVP, a trainer, speaker at conferences, an author, and a consultant. And a consultant. I still sling code. Great. So we were at a show recently. We've been at a couple shows recently, actually. We were sitting around talking about what types of things that we should be telling people how to do. We spent a lot of time on all the new stuff, bot frameworks and stuff like Azure and DevOps and Xamarin. There's a whole bunch of stuff going on. But one of the things that we sometimes gloss over is the standards. How would you, no matter what you're doing, be a better developer? And so you suggested that we should spend more time doing that kind of stuff. Yeah. Because one of the things that people want to do is greenfield projects, right? File a new project, build something from scratch, latest technology, play with all the toys. Reality is most of us are janitors. We spend our time cleaning up either our own code or somebody else's code. With adding features, bug fixes, or whatever. The average life cycle of a project is usually about 10 years. So how do you make that life less miserable? And one of the ways is really focusing on the quality of your code. Okay. I mean, you can obviously upgrade to the latest version of the tool because Visual Studio has new tools and whatnot. But this is more about the code you're writing, not the IDE. Yeah. So just because there's new search capabilities in Visual Studio, it's not going to fix bad code. Right? And what I mean by bad code is, is every code you write, you look back, even if you wrote it yesterday, you go, I could have done that better. Right? So what we want to talk about, and we've talked about for a long time, is solid, right? The solid principles, single responsibility, open, closed, and we're going to go through those. Okay. But it's just some foundational principles that if you think about these as you're writing code, and the other thing is to sum it up, I like to look at it this way. Pretend the next person looking at your code is an ex-wielding psychopath. Right? And if you write bad code that they have to maintain, they're going to get a little cranky with you. Now, in reality, who's looking at your code next? It's probably you. Right? Six months down the road, you pull some code down, you have to work on it, you're looking at this code going, oh, this is terrible. Who wrote this? When you look at the commit log and you realize you wrote it. Right. And you're like, no, no, it's fine. I love this code. Let me clean it up. Right? Okay. So what I want to do is just go over a few guiding principles I try and follow. And this is, again, this is whether you are starting a new project or neck deep in an existing project that you're going to be on for the next several years. Right. Yeah. And we've talked about that also with the Boy Scout principle, we'll get to that. You know, there's certain things that you can do to clean up technical debt. Okay. And we'll talk about, it's a balancing act. Define technical debt. So technical debt is code spells, right? Code that could have been written better, but wasn't necessarily. Not all technical debt is bad. Okay. And you don't always have to pay it back. I mean, if something works, it's in production. I've got code written in VB6 that's still in production and people are still finding it useful. And I look back at that code every now and then and go, ooh, I don't want my name attached to it. Can I please rewrite it, right? But it works. Right. And they're not having performance issues. There is a cost to rewriting. There is a cost to rewriting. So you have to really decide, is it worth paying that debt back? And it's a balancing act, right? We all want to go back and fix it, but it's not always the best thing for the customer. Right. Right? So when we talk about solid, Robert Martin, Uncle Bob, wrote this paper. Principles of Object Oriented Design was the official title. And everybody just refers to them as the solid principles. Okay. And it's single responsibility, open, closed. It's called substitution, interface segregation, dependency inversion. Right. So I wanted to do just a few slides. I know we're going to get the code, but a picture is worth a thousand words. And I'm sure you probably had a knife, something like that when you're in Boy Scouts, right? I had one of those. And you could do anything you wanted to, except cut anything, because you could never get the little knife out. Right. Right? And the problem that we run into as developers is I call it the kitchen sink mentality. Right? We've got a class out there called something utilities. And we just start dumping stuff in there. Right? Or we've got a method. If I just add five lines into here, then I don't have to create a whole new method or a new class. Right. And when we talk about single responsibility, you really want to have your methods, your classes, focus on one job and do it well. It's like driving. Can you text and drive in Washington State? I think that's illegal, right? It's illegal. It also gets you in trouble. Yes. Right? So if you're texting and driving, you aren't going to do one of them very well. Right. Right? And hopefully it's a texting you're not doing well, you don't cause an accident. Yeah. Same thing with code. If you're trying to do 40 different things or even two different things in a method, you're not going to do them optimally. And plus, if you go to change the one thing, you don't know what kind of side effects you're going to get from the other. Right? So just have one thing being done in each method. You can have lots of really small methods. And then you're going to have lots of really small classes. Okay. And people will say things like, well, then that's a lot of files. And I say, so what? Right? With Visual Studio these days, you can find anything, right? All the refactoring tools. Yeah. The next one is the open close principle. What we want to do is we want to extend our classes instead of modifying them. And what I like is to picture the house, right? If you're going to put an extra bedroom, a patio room, a deck, that's pretty easy to do, right? If you want to put a new basement on your house, that's significant. And you run the risk of breaking your entire house. Right. Well, if you've got code it's in production. It's working. People are using it. Why would you go change that? Right? So we want to make sure that we extend code instead of just changing things at the base level because again, we risk those side effects. There's unintended consequences. Everybody likes to cold beer or at least some sort of cold beverage? Yeah. And what I like about this slide is we really want derived classes to be able to stand in for any other call. And what I mean by that is program to an interface. So if I have an I repository that I'm programming to, I can program in or instantiate anything that holds that interface. It's like a beer tap. If you go into a bar and they want to switch over from a winter shanty to a spring, I don't know, something, I'm not a beer expert, they don't have to rip out the taps, the lines, the whole infrastructure. No, they just flush the line, put a new half borough in and they're pouring the new beer. Okay. Think of, and this happened to me in the late 2000s. We were writing an application. It was an e-commerce site. We had a certain credit card provider we were using. The CFO calls and says, we have to switch. And this is like six weeks before release. And he said, okay, why do we have to switch credit card providers? He said, well, we just have to, right? You have to use this other one. Well, it turns out he was playing golf with the sales rep for the new one, lost around the golf and we had to switch. If we had programmed everything to be directly tied into that additional credit card provider, we would have had to rip out a whole bunch of code that had already been tested. Or even through user reviews and QA and everything else. Instead, we actually had an interface that we could program to. We swapped out the old one, put in the new one, had to tweak it some, but basically we were up and running in about a day. Okay, right? The next one is interface segregation. You probably don't know what that is. That is the control panel on the USS Missouri, the Mighty Mo. I was fortunate enough to go to Pearl Harbor one time and they had imagined a room about the size of the studio covered in dials. To shoot the big guns, they had an entire room full of people, mainly turning knobs. And these guys knew how to do it. They could hit a target 100 yards in diameter, right? Miles and miles away. When they went to bring it out of retirement for the first golf war, the Pentagon went, huh, nobody knows how to shoot the guns. They had to bring a whole bunch of service men out of retirement to teach the new guys how to fire the guns. Well, that interface is way too complicated, right? So anytime you have an interface, intelligence is great, right? But if you hit dot in Visual Studio and there's a scroll bar in the intelligence window, your developer is gonna be stuck in analysis paralysis and go, I don't know which one to use. A lot of times they're very similar. So we wanna make very fine-grained interfaces specific to the job at hand. Even if that means making your own interface to wrap up an existing framework class, you want it to be as quick as possible for your devs to be productive. The last one's the Penny Sim version. I think it's the most important and probably equal a single responsibility. Did you drive to get here today? Yes, I did. Did you build the engine before you could drive here? No, I did not. The engine was already there, right? Yes. Yeah. So think of software. How often do people build the engine before they drive the car? If you're newing something up in your method and then using it, you're building an engine every time you wanna drive the car. You were locked into that specific instance and you can't use anything else. What we wanna do instead is subscribe to the iCar interface. You have more than one car. You can drive either of them. You've had rental cars before. As long as they subscribe to the iCar interface, you can drive it, right? Which is usually during wheel and accelerator and de-accelerator. Some states, they have turn signals. Not all states use them, evidently. But you wanna do it in software. So we're gonna inject those things in like the engine, like the data access layer, like the repository. When we get to that point, you'll have to explain why. Like I understand, I've always understood the principle, but sometimes explaining why you need to do that. I want to be able to plug different things in, but in my app, I'm only using one of them in the first place. Why do I need dependency? Well, you're not always using one of them. You ever use log for net? No. Okay, so log for net's a logging framework. And based on settings in the web config or the app config, you can change the logging level. And you can have it be very verbose or very, very light. Right? Right? And what we're doing is we're setting those properties in the config file, which is then being set at runtime. Now that's not really the dependency injection, but that is an instance where we're changing the functionality of something without having to change code. So let's say that I'm using a credit card provider for my e-commerce site, and I say foo equals new credit card provider, and foo dot check credit card, foo dot check address, foo dot charge credit card. Okay? So now I have to switch credit card providers. And now I have bar. And I say bar equals new credit card provider. Yeah. And it's not bar dot check address, it's bar dot address verification. So now I have to change all that code. Mm-hmm, okay. Whereas if I just had injected in an i credit card provider, and then we'll talk about it with some of the patterns so we can put an adapter around that so that it subscribes to a common interface, then I can change out the credit card provider. So how is that different than creating a service class that has a fixed set of methods and then your service class just calls check address or verify address or whatever, so that your front end never has to change. Okay, so how are you getting that service class into the method that you're calling? You dim it up. Okay, you're a VV guy. He said dim. Knew it up. You dim it up, you knew it up. Either one, they both work. I know, I do that too. So that's true. But what if that service class has to change? What if I'm going against a... But the service class, and maybe we're going down a tangent here, but the service class has a method called check address. And it's always gonna be check address. I don't care what the thing I'm calling calls it. Check address, verify address, address, verify. It doesn't matter. You would have to change the code in the service class, but the thing that calls the service class always calls check address, passes in something, and gets back a yes or no. So that'll be coding to an abstraction. And so you've solved the problem in one part of your code and you've kicked the can down the road to another part of your code. So now you need to change something in that service class. Yes. Right, do you want to change the code or do you always want to pass in a new object? Here's a better example, that might make more sense. But then aren't you just kicking it down the road to the interface? Let me say this. So EF Core now has an in-memory provider, right? And it's great for unit testing. So I'm using SQL Server in my real app. I don't want to write unit tests that are actually touching the database because that's really an integration test and that's a different type of test. So I can inject into my ASP.NET Core application a context that's using the in-memory database as opposed to SQL Server and not changing any of my code. Okay. So I'm just injecting in a different database provider because it all holds in the same way. We're digressing. We are. That's what, that's what- You and I are having fun here but the viewers have not turned us on. But you know what? That's what post-production is for. So this could be a really short segment if you need it to. I doubt it. I think we'll probably just leave it in. So let's move on. Let's move on. So everything is dry, right? It's not one of Uncle Bob's solid principles but it's don't repeat yourself. Anytime you have repeated code, you run the risk of introducing side effect bugs. Okay. Right? So I've always said if you write something you want to think about making it a function, if you write something twice, please, please, please make it a function. If you write something three times, you might want to stop being a developer. Okay. Because if I've got, you see this all the time with case statements. I've got a case statement over here. I'm going to clipboard inherited over here which is an anti-pattern, right? Yep, clipboard. And I change it over here because I'm working in this code and I totally forgot I wrote it over here. So now I can make five different types of pizzas if I'm in this part of the code but only four types of pizzas if I'm in this part of the code, right? So we really don't want to repeat ourselves. The Boy Scout principle is what we're talking about when we got to legacy code. So I've got this humongous app. I've inherited other things in it. There's, you know, 5,000 line methods called execute with 36 parameters. And if you want to eliminate all that technical debt, you're going to spend who knows how much time just rewriting code. Right. And there's not, there's some value in that but not really value that can get translated to return on investment. So what you want to do is if you have to go into that code, leave it just a little bit cleaner than you found it. So add some unit tests, right? Maybe extract some methods. It's really easy in Visual Studio to pull out a method, right? And then write some more unit tests. Don't fix it all at once. Just chip away at that debt. It's like if you've got a mortgage, you know, pay an extra payment a year, you cut the life of your mortgage down by five years typically, right? So just, you know, and the Boy Scouts always leave something cleaner than they found it, right? Right, hence the Boy Scout principle. Last is separation of concerns, right? So I'm a Star Trek fan. Bones would always say, you know, damn it, Jim, I'm a doctor. I'm not an engineer or a weapons specialist, fill in the blank. Right. Here's what we want to make sure that our code is doing what it's supposed to and nothing else. And this is very similar to single responsibility but it's kind of more of a macro vision of it. When we talk about separation of concerns, let's have a data access layer that's isolated so that if we don't want to use and hibernate and we want to switch to NAD framework, all this code doesn't change, right? We're passing in, we're injecting in an I repository that now calls in hibernate or at NAD framework, right? And if you've got UI concerns, NBC is a great example of that, right? We really have a good separation concerns in that. Okay. Last thing I want to show is just a quote, Phil Hack had this on an alt.net news group that I used to subscribe to years ago but it's such a great quote and it's so powerful. When we talk about design patterns, so we've moved away from solid, let's talk about actually how you code in a solid manner and design patterns really help us to do that. The problem that I see so often and why I came up with this talk initially is people treat design patterns like dogma. Like this is the only way you do it, right? I have a hammer, now everything's a nail. And the best part of this quote and your viewers can read it but I love the fact that he says the goal is not to bend developers to the will of some specific pattern but to get them to think about their work and what they are doing. And if you just look at that second part of his statement to get them to think about their work and what they are doing. That's what we really want people to do is stop and think, right? Program is not a typing exercise. It's a thinking exercise. Okay. So how can we apply critical thought? How can we learn from others and write cleaner code? Okay. All right. So let's dive into some code and talk about some, actually not all of them we would be here for days if we wanted to talk about every pattern there was. This code's all available on GitHub. It'll be in the show notes. And I have unit tests around them and the reason I do that for a couple of reasons, I'm pretty fanatical about testing code. But the other reason is if people want to download the code and play with it and tinker with it, if they break the unit test, they broke the pattern. Okay. All right, so you're building a website and you're going to use any framework and firing up a context is the most expensive part. The context it creates a connection, it checks the database, make sure everything's in order. So it's kind of an expensive operation and for most people not that bad, right? But it's something that you want to do on every single database call. So that's something where you might want to create a singleton and the singleton by definition means there will only ever be one of these things in existence per app domain. And for most of us, we just deal with app domains. I mean, if you're doing some multi-threaded stuff, it gets a little more hairy. But the way you implement a singleton, the way you recognize a singleton is here I've got two different variables. They're both set to the singleton instance and we'll talk about that shortly. And I'm just running a test. I say assert that they are the same. Now our same in unit testing means that they are pointing to the exact same item on the heap. Okay. Change a value on one of them and I make sure that they're equal on both. So that's the symptoms. That's the result of having a singleton. Let's look at how we build this. And like I said, it's a very simple pattern. We create a private static instance of the class we're building and you'll see in all my demos, the names are terrible and really bad at naming things but the three hardest things in software development are naming conventions enough by one errors. We also have this sync log object. Now I will say there are several different ways to implement singleton, this is just one, right? A dead giveaway is a static property called instance. That's just a convention, not required for the pattern. And then what I'm doing is I'm checking if the instance is private static instance variable is not null, then I've already created one and I can just return it to the calling code. If it's not already been created, I put a lock. Okay, so this makes my code single threaded if you're not familiar, I know you're familiar with locks, if some of your viewers aren't familiar with locks. And then we do another check to see if it's null. The reason we do this is we've got multiple threads coming in potentially, get gated by the lock. One gets through, followed by another one. So now there's single file in line. If this one creates a new instance and we're not checking again to see if it exists, this one could create a new instance as well. So we just throw another lock and then we simply make the instance a new instance of the class and we're off to the races and that's all there is. So this helps with cutting down and repeated code and making sure that if you have to have state across different calls, this will do it for you. So like I said, a very simple pattern. The next thing I wanna talk about, and I use this a lot, is a simple factory. And a simple factory is usually used to instantiate different options. So for example, let's say we're creating a pizza factory and I have to give a shout out to Headfirst Design Patterns. It's a book, it's a very, very good book and we'll put it in show notes as well. Some of their examples I leveraged for this talk. And one of them is a pizza store. So let's say we wanna make a different type of pizza. We could put an if then or a case statement everywhere where we're creating a new pizza in code, but then we'd be repeating ourselves. So we can encapsulate that in a simple factory and it's called a simple factory because it really is very, very simple. A lot of times it'll be just a case statement. Okay. All right, and we call into this. Now, in real code, I wouldn't just statically create these things, I'd be calling into a database or whatever I'm doing, right? But let's say for example that I run an e-commerce site and we're going to try and get different shipping methods, right? If you're going to Amazon and you buy a book, they're gonna pack it in a box. If you buy a steak, they're gonna pack it in dry ice. If you buy something fragile, they're gonna pack it completely different, right? So I can get a new instance of that packing class just by using a simple factory. Now, according to the Gang of Four, it's not an official pattern. So I just have to call that out. Me, I'm more pragmatic than academic. So it doesn't matter to me that it's not an official pattern. We're gonna jump ahead to combining the factory method and the abstract factory. Oh wait, go back. Oh yeah, certainly. Make sure everybody understands why you're creating the factory. What's the difference between those methods? Oh yeah, certainly. So here in the simple factory, all I want is one place where I can create things. So it's sort of like your service class, right? You were talking about earlier with dependency injection. If we're creating something, we want to have one place to create it. So it's a single responsibility. The factory's job is just to create things. It doesn't use them, it doesn't do anything other than say, hey, I need one of these and throws it back to the code. Okay, so the I-Pizza is a pizza. So every pizza is similar in some regards. Every pizza, yes. And they're represented by an I-Pizza, which looks like what? Oh, certainly, yep, sorry. And then we're on a little bit of a time frame, so I was, hey, not hitting that button. We're on a little bit of a time frame, and so I just want to say here's an I-Pizza. Okay. It's got some toppings, it's got a dough type, seasonings, sauce type, and then it's got some methods it exposes. All right, got it. And those methods will come into play. So although they're depending on the type of pizza you want, you go through a different path, but you always return an instance of I-Pizza. Yes. And that's why you created a factory like that. Yep. Instead of having four different classes, potentially, for the different pizzas or four different methods and different places. Yeah, and this is just the, the scope substitution principle, right? I want to be able to program two and I-Pizza. Pizza's going to have toppings, it's going to have a dough type, it's going to, you have to cook it, cut it, those types of things, right? If I had a cheese pizza and a pepperoni pizza class, well, that's easy, but now let's say you got 36 different toppings. Right. Let's say you work at Starbucks, right? And it's on pizza, but think of all the different combinations and variations of coffees you can order. Right. And you get right down to it, it's all the same thing, it's liquid in a cup. Yep, absolutely. Okay. All right. Thank you for- Delicious liquid in a cup, of course. Absolutely. It's not, you know, doubt play, the awesomeness of- I've got my Starbucks up, I'm on band. All right, so let's, there's two other factory patterns that I typically combine into one. And it's the abstract factory and the factory method. Okay. And it's easier just to explain holistically how it all works together than to go into the minor details between it. So, let's say we have this different types of pizza stores. Mm-hmm. And we've got a New York pizza store and we want to order a localized pizza. Now, New York style pizza is very different than Chicago. Yes, it is. Right? And we want a pepperoni and then we're just going to assert that it's a thin dough, it's a red sauce, and it's spicy. Mm-hmm. So, let's say we have a Chicago pizza store. You forgot greasy. That's being nice. I am being nice, it's good. So, Chicago pizza store and we want a sausage and it's going to be deep dish and tomato basil and mild seasonings, right? Which can all be changed, but this is just a default. Now, here's the important thing. Let's think about, I have a pizza franchise, right? All right, I'm a UNO, right? I'm a pizza UNO and I want to franchise or have people franchise my store. Yeah. We want to control certain things. For example, the order of execution. So, we want them to make the pizza, cook the pizza, cut the pizza. Well, actually, there you go. I just messed up the order. Put it in a box, then cut it, right? And then deliver it. Right. If you get that order wrong, bad things can happen, right? You can put all the dough and all the toppings in a box and put it in the oven and light your store on fire. Right. So, there's certain things we want to control, but certain things we want to give them flexibility to. Yep. And this is also... Chicago pizzas are typically not cut first. They just put them in the box. It depends, right? So, the franchise by me cuts it. Okay. So, not first, but they put it in anyway. We're getting totally squirreled here. So, let's look... Well, you're bringing up pizza. What do you want? Oh, I know. I like pizza. But that's why I talk about things that people can relate to, right? So, I used to give demos on more business-type things. Yeah. And so, like if I was talking about banking here or expense reports, somebody used to say, well, that's not how expense reports work and we get totally lost in the domain as opposed to just looking at the code. So, we've got a pizza store. And if we look at the pizza store base class itself, it's got an ingredient factory and the base ingredients just, you know, it's very simple. We'll talk about those. But here's what I want to talk about. The order localized pizza. So, this combines a factory pattern with the command patterns. We're gonna get to a little later. Where we say, create your localized pizza and I don't care what type it is, right? So, the inherited store, we'll make a more New York style, West Coast, you know, California pizzas style or Chicago. And then we want to control the order. Okay. And then we're gonna return it. Now, where this really comes into play, let me go back to that whole e-commerce site. Right, you order something and you put your money in and then a couple of days later, it shows up on your door. Right. So, if you order a book, they're gonna, first of all, make sure that it's in stock. Pack it, well, pick it, pack it, chip it. Right. Right? Same thing with no matter what you order. Those exact commands happen. But how those commands get executed, very, very different based on what you're ordering. Okay. So, we want to control the order, but not necessarily the exact functionality. But we also want to make sure that the store, the base store, doesn't care whether you bake it at 350 degrees for 30 minutes or at 400 degrees for 12 minutes. It just says bake. Okay. All right. There's a lot more we could talk about that, but let's get to some other patterns. Okay. Let's talk about the adapter. We're now moving into structural patterns. So, what we're talking about, we're creationals. Three main types, I'm probably sure to say that. Structural, behavioral, and creational. Okay. So, this is structural. So, the adapter pattern is also hugely helpful. So, if you're old enough to remember two prong outlets in your house, I don't think they build them anymore. But invariably, my dad would come home with something that had a third prong. And I have a two prong outlet. So, we did what everybody did, broke off the third prong and plugged it in, right? Well, what we were supposed to do. We just plugged it into a three to two. Plug it into an adapter, take the little wire. Yeah, it's just the ground. Attach it to the, yeah. In software, we do the same thing with an adapter. We make something appear to be something else to make it easier to code, right? Let's go back to that whole e-commerce thing when they're switching out. We just wanted to check a credit card to see if it was valid. And then we want to charge it and we want to check the address. So, we didn't necessarily care how all that happened. We just want to be able to call that and not fight the different names. Right. So, let's say we've got three types of cartoon characters. We've got a moose. Yeah. And we've got a flying squirrel. Yeah, moose and squirrel. And we've got a bad guy. Okay. Now, the problem with the bad guys and the squirrels and the moose, moose. Moose. Mises. Mises. We'll call it mises. So, a bad guy can only do two things. Can drive and it can shoot, right? If we look at the flying squirrel, it can only do two things. Fly and drop acorns. And if we look at a moose, it can run and it can charge. Okay. Right? But now we want to operate. It can do magic tricks. It can do magic tricks too. I should add that in. That's not part of the interface. So that'd be an extension as opposed to a modification. So, if we look at these, we can certainly work on them in a list. So if we've got one squirrel, one moose, and two bad guys, we can put them in an array list, which is not strongly typed. And then if we want to act on them, we would say, okay, if object is of type, then call this method. But then every time we want to act on those, we have to remember to translate those methods into something that makes more sense holistically. So what we want to do is we want to make them all look like an eye character. Okay. And an eye character has three methods, chase, fleeing, attack. So we want to map those. So the way we do that is by making adapters. Now I will say, from a single responsibility standpoint, I've broken things here, because I have multiple interfaces and multiple classes in one file. Really not a good idea for supportability, maintainability. It's demo code. It makes it quicker to get from one to another. So I do want to point that out. So, the way we turn a moose into an eye character is we have this moose adapter class. So we inject in an eye moose. We're always coding to an interface. So we don't care which moose it is. It could be something that derives from eye moose. It could be a baby moose. It could be Bullwinkle. It could be Bullwinkle's wife. Okay, so right here. Yes. In this application, you have a moose. So you could pass in moose. I could. Now, the benefit to passing in eye moose is that you are pre, you're getting ready for if in the future you would ever have different types of Mises. Mises. Or mooses. Mises or mises, the plural of mice? I don't know. Mooses. Right? Bullwinkle. Bullwinkle. So in this instance right here, it's not 100% necessary immediately, right? Because it's, instead of dealing with a moose, you're dealing with a moose and an eye moose, it can seem like you're over-complicating given that there is a moose. Is that correct? Well, so. So what would you say to somebody who says that to you? So. Because that's extra work. What am I gaining? Well, it's not a whole lot of extra work. I'm really just saying eye moose instead of moose. I know. There is the yagney, right? You ain't gonna need it, right? So there are times when you want to just back off a little bit. What I have found with things like programming to an interface is it never hurts. And quite often comes in handy. So there are things that I would consider overkill, like using an IOC container, an inversion of control container, which when your viewers download a code, I use Unity, not the game engine, but the IOC container that Microsoft wrote to do some of this in the longer version of this talk. Right. Another classic example is MVVM, where even though the standard is that you name your view model after the page, and then in the page you instantiate a version of the view model, right? You don't do that, you use a view model locator, which, you know, you're in the customer page. You're going to call the customer view model. That's the convention, right? And then there it is, under view models, customer view model. Why, you know, so you might ask yourself, why am I going through adding all this complexity of a view model locator, which I now have to learn how to use. It's not a problem getting one, there's plenty out there, but now I gotta learn how to use it when I'm in the Moose page and I'm gonna call the Moose view model, let's move on. Right. So there's a couple of things to that and I totally agree that a lot of times using those locators is overkill. If you're moving to .NET Core. Right, so somebody could argue that this is overkill. Oh, they could argue, right? And in this particular code example, I couldn't really refute that, right? I could easily change this to that. Right. And it wouldn't break the code, it'll work just as well. Right, so the question is, what's to be gained by switching into the habit of calling the interface and these simple type of examples? If you get in the habit of always coding to an interface, then when you have to start paying back that technical debt, then you can start injecting different things. You can use mocks to unit test, right? So I can write a unit test throughout this about this entire adapter and not have a Moose class. Right, okay. I can create a mock representation of an I Moose, put it in here and make sure this code works. And I actually have unit test with mocks in here to show how to do that. So that's interesting. So in an application where you're calling data, it would make it a heck of a lot easier to use fake data while you're developing. Oh, absolutely, yeah. Because you're bringing in an I Moose and your real Moose, which calls a Moose factory, which then goes out to the database and brings stuff in, or you're passing in the mock Moose, which is just hard coded data, sample data so that you can. Yeah, and my unit test wants to make sure that if I call Chase, it's really calling the run method on the Moose, on the I Moose, right? And not actually executing it. What if the run method was charge credit card? And I had to pass in a real credit card number and it would charge it, right? But I could bring in a fake credit card processor and just assert that that method was actually called through the mock framework. Okay, cool. But from a strict coding standpoint, in this example, you could argue that you don't have to code to an interface. But if you do get in the habit of coding to interface, it's very little overhead, if any, and it's just a good habit. Well, I've seen these types of talks quite a bit and I think they sometimes tend to just focus on the mechanics of what you're doing without stopping to remember that you do it this way, there are potential benefits. Which you may or may not realize in this particular example, but if you understand now, oh, I see, this will make it easier in the future for me to do something like this. And it's one more letter, I Moose versus Moose. It's worth setting yourself up for being able to take advantage of it if you then understand what the benefit is down the road. Right, absolutely. And actually, there's several books have been put out by some of the software luminaries that say you shouldn't use the iMOOS name, you just call it Moose, because everything should be an interface. And it should just be assumed that everything you're talking to is an interface. We're not there yet as an industry. Speaking of mocking and testing, look at this, right? So I have my iMOOS and I'm creating a mock which is just a proxy around the iMOOS. And I'm saying the behavior is strict and I'm using the free version of just mock for this. And what behavior strict says is that if I'm calling something that doesn't exist, like if there's a method that I try and call, it's gonna throw an exception. So I arrange that when I call a charge, it actually is going to return 10 and it must be called. So this says if anywhere in this test, charge is called return 10 and I'm saying it has to be called, right? So this is an expectation. So I can go then assert that these things were called appropriately. So I'm testing my adapter without having to have a real Moose. Right. All right. So I have the different adapters here. Flying squirrels maps it to one thing to another. And the other reason I like adapters is not just we don't normally program around Bullwinkle and Rocky and Natasha and Boris. But a lot of times we have legacy code we have to call into or we have something in the framework that's difficult to use or we're using a third party app that is confusing but it's mission critical. I can write an adapter around that to simplify it. So if you're, and I'm gonna show, actually, you know what? Let's just go onto the facade because the facade is very similar to an adapter. But the difference between the facade and the adapter, essentially, is an adapter is I'm taking one thing and shaping it to look like something else. And a facade, I can take many different things and make it look like one thing. Okay. Right? So let's say that I've got this class that implements I Confusing and I Overdone. So I Overdone, again, just made up names, but we've got this business critical assembly that we have to call into. Okay. And we've got these wonderfully meaningful names, do something, do something else, and do something again with X, Y, and Z, and oops, I ran out of letters, I have to start over at A. Okay. Right? Not very maintainable code. This would be significant technical debt, in my mind. Then we've got this other one that's I Confusing and it's, yeah, that's a great feature. So we've got Execute, always a great name for a method. Method one, method two, this is somebody learning how to use Visual Studio to add a new method and then another method two with an overload. Okay. Well, I'm calling into this all the time, right? I have to because that's the way my workflow goes. But now what I have to do is if I want to remember which one of these methods I should call, I either have a bunch of post-its on my desk, or I have to use Reflection or Reflector or some tool to go look at the source to see what it is. So what we want to do is we want to build a facade. So somebody has to bite the bullet and take the time to learn which of these methods we need and call them something better, right? And wire them up. So we really need these two methods and their overload. So add three numbers, add and multiply with some different items. So when we build this class, we're just going to call into the methods on the bad classes, right? So that as I'm coding and I need to add three numbers, I just say foo equals new better API, foo dot add three numbers. So the facade is just the middleman basically. Yeah, just cleans it up. Makes it nice and easier to use, right? All right. Decorator is absolutely awesome. I wish I would have known this a long, long time ago. I wrote an application, it's still in production and it's a configurator for high-end bicycles. And it's all written in JavaScript, long before we had all these great JavaScript frameworks. So it's plain old JS and it's easily, I don't want to say it out loud, 5,000 lines of JavaScript. If you pick this frame, then I go through and say, well, these are the tire rims that are available, these are the brakes that are available and just imagine a tree configuring a bicycle from the ground up. And it's, I actually volunteered to rewrite it for the guy for free, just to get my name off of it, right? Cause it's in JavaScript, so anybody can look at the source. There's so much better ways to do it and this design pattern is phenomenal. It's called a decorator and what we do is we take a base something and we decorate it. Let's go back to Starbucks, right? You start with some coffee and you're gonna add some syrup, you're gonna add cream, whip cream, change the temperature, all these different things that can affect the price. So instead of having one class for every single combination, let's just have an iCoffee interface or in this case an iCar interface and let's decorate the car. So let's say I was watching, sometimes I write demo code. Let's play with what that means. I will, but I also have to just say that I was watching the remake of Speed Racer when I was watching this, so hence the cars. So I have a base car and it has a drive, attack, and defend basically hit point value, okay? Let's say I wanna have an armored car. The armored car drives a little slower, attacks the same, doesn't change from the base car, but it defends much better, right? Let's go down and look at the race car. Obviously it's faster, doesn't attack as well, it's lighter, doesn't defend as well. And then an attack car, right? So we go through. So if I'm building the classes to support making the movie Speed Racer, this is very simple. We could all do this, we got different styles of cars. But halfway through the movie, Speed Racer says, well, I got a double armorer, I'm gonna soup up the engine and I'm gonna put better guns on it. Well, is this another class? Think about all the combinations that you would have to come up with. So instead of creating a class for each of these options, we decorate it, the way we decorate it is let's look at the armored car. Is we, all of them implement iCar, right? Which has drive attack and defend. And we pass in an iCar into the constructor and we're gonna armor this car, we're gonna put some more plating on it. Well, because we're adding additional plating, the drive speed decreases. But the defense power increases and we're not modifying the attack vector. If I look at the attack car, we do the same thing, we pass in an iCar and it doesn't drive quite as fast but it attacks much better and it defences lower. So I can take my base car, factory standard and I'm going to pass it into an armored car decorator, put some armor on it. I'm gonna do it again, put it back into an armored car decorator, put some armor on it. So what I'm doing is I'm creating these circles around it. So I'm using with an iCar. This doesn't know, this attack car decorator has no idea what the iCar already has. The trick here is that we're not setting values, we're decorating the values, right? Taking a little decoration off, adding a little decoration, taking the Thanksgiving decorations down, putting the Audiva decorations up, right? Just changing, you're not changing your house, right? You're just decorating it. Okay. So that's a phenomenal pattern, I think. Especially because it would have saved me so much time writing the configurator. And if you didn't do that, then you'd have to create a car and then you'd have to manually set all the properties. And remember what the rules were for setting the properties. And now you've got just all those properties all in one place. At the same point you created the car. So you're not getting separation of concerns, you're not getting much reusability. Right, you're not getting any reusability. And let's say I want to- And it's really easy to mess up. Right. And let's say I want to armor it three times. Well, now I have to create yet another class. And remember that when I armor it, well, this is the attack. Let's say, okay, so when I attack I increase it by 30. Well, what if I forget and then I increase it by 40? Right. Right? Yeah. So it just, it creates all kinds of- Or you got to, next time you want to create a double armored car in a different part of your code, you got to copy that code, create the car again, and then copy all of those properties. Yep. Or extract that into a method, but now you've got multiple different methods for every time you wanted to do it differently. Yeah, it's a mess. Yeah, and that's about the time that you update your resume and look for a new job. Or you learn how to do this. Or you learn how to do this. There's only a couple more patterns. Okay. The command pattern, really, really simple. And I demonstrate how simple it is. The command pattern always has a controller that calls the commands. Think of a remote control, right? You've got a remote control, and it probably says cable, TV, DVD, or VCR if it's an older one. And you push that button, push the VCR button, and the VCR turns on. Push it again and it turns off. The remote control has no idea how to turn on that VCR, right? It sends a command. The VCR recognizes a command is, oh, I need to do something with this. So I'll turn it on. So here I have a very simple controller. I should point, this doesn't help your viewers. So I'll point to this very simple controller. I've got a light and I've got a light command. The light command is very, very simple. It just, if the light is on and I execute it, turns the light off, right? Right first, so you can also do undo, but then with undo you have to track the commands that were executed. So this is just a very simple example. And then the controller literally is just, right, it looks to these controls. Now, remember when we talked about the factory pattern, we had some commands, bake, cut, box, right? When we talked about e-commerce, pick, pack, ship, charge a credit card. Those are just commands. So if your controlling code doesn't have to know anything about that, and says, by the way, they ordered this item, go pick it, right? And that gets sent to some other system and it says, oh, here's the SKU, it's a book. I can pick it manually, or I've automated with a robot arm, oh, it's a thousand-year-old vase. I'm gonna send a human to go grab this very carefully and pull it over. Your calling code has no idea what's going on, right? So now you've got separation and concerns. You've got single responsibility. I am responsible for picking this. I'm responsible for packing this. I'm responsible for shipping, right? So when you start combining these patterns together, you get much cleaner code and much more sensible. So now we're gonna start selling boats on Amazon.com, which is a whole different style of delivery. But your UI, the code that controls the commands and the workflow, doesn't care, right? Now I extend it, I create this new set of commands and I can keep building onto my site. Very good. All right, the last one, strategy. So the strategy allows us to change the functionality of something at runtime. I mentioned log for net earlier and we were talking about DI and really it's a better example of the strategy pattern. So the strategy pattern says, I'm doing something. I'm gonna get some sort of input and I'm gonna do something different, right? Log for net, no logging. Now there's a problem on your production server. I'm gonna crank logging up to 11, which hits performance, but it gives me all this data then I can turn logging back off. Now I go analyze the data, right? Because one of the problems that we always have is well it works on my machine, I can't reproduce the problem. So what we're gonna do here is we've got some superheroes. They all have different powers. So Spider-Man, we all know we've webs. Superman flies, Batman fights. And if I could do a talax, right? Cause Batman would fight. Go in old school a little bit. And they've all got these powers, right? And that's fine. But let's go and look at Peter Pan, not Peter Pan, Peter Parker. And so Spider-Man is going out to meet the bad guys and he's shooting his webs. And what happens as soon as he sees Mary Jane? It's web slinger jams, right? So he has to get a new superpower. He can't go, time out, I'm gonna go back to my aunt's house and change my superpower, come back. Well, the bad guys are gonna be gone, right? So in the middle of the fight, he has to switch what he's doing, right? And so whether it's, so now he has the new fight superpower and he doesn't really fly but he can jump off buildings and then if his web slinger's working, right? He can go. So this is, this is awesome. So to-dos are a code smell. This to-dos probably been in here for about four years and every time I get to this point, I'm like, I need to fix that and then I forget. Let's look about it, so that's great, right? Again, we're not writing software about Rocky and Bullwinkle or Superman or Spider-Man. But let's say we've got, go back to his e-commerce site, right? And there's a power outage on the East Coast and our cheese factory's on the East Coast and the cheese is gonna melt. Not melt. Go bad, right? And so we want to change the price of cheese without deploying a whole new release. So through the strategy pattern and the commands, right? So pricing is one of those things. So I'd say get me your price. Again, your front end knows nothing about how to calculate prices, but cheese knows how to price itself. You change that capability at one time and we can do that through dependency injection. So we can just create a new assembly or a new configuration. Really, what do we do in real life? We change the database value. But what are we doing when we change the database value? We're changing the way something operates at runtime, right? So that's an example of using this pattern, right? And we only want this sale to go on until the power comes back on. And when the power comes back on, we want to immediately go back to our normal pricing. Okay. And we don't want to, again, to deploy a whole new site to do this. We want to be able to do configuration through dependency inversion IOC containers, be able to change things at runtime. Okay. So that's the last one I have for you to show today. Cool. So do you have for each of these examples of the old way of doing it and then how you would do it once you adopt these patterns? Do you do that? You know, that's a great idea. I don't, I don't have that. Excuse me. I should think about that. What I recommend people do is get a book like the Headfirst Design Patterns book and read them and go out to something like Project Euler, E-U-Y-L-E-R which is just a bunch of math problems and program them and just do CODIS, code CODIS, right? Practice writing the code, delete it. Practice writing the code, delete it. Because what we want you to get to is the point of where to borrow a matrix reference, you won't be able to see the lady in the red dress. One thing that I use design patterns for when I'm running teams is when we're talking about how to design a system, I don't let people use our whiteboard. Because as soon as you give an engineer a dry erase marker and a whiteboard, they're off, drawing shapes and figures and naming things, right? And you get totally down a rabbit hole. But if we can just sit back and talk about, well, how would you build this? It's a configurator. Well, should we consider a decorator? Well, yeah, okay, move on. What's the next thing that we have to design, right? And so it becomes a language, a way of communicating without going into all these great details. So just practice. I don't have, you know what? I'll probably add some examples of the bad way of doing things. I won't say the bad. The not is optimal way of doing things. Okay, I'll go back and look at a couple of apps that I've built and see if we can come up with some examples. Maybe we'll do a follow up show. Where we actually show. Refactoring them into the patterns. Yeah, refactoring, right, and then why. Yeah, okay. That'd be great. Cool. Well, thanks for having me on the show again. Thanks for coming on. All right, hope you find that very useful and let's make this the beginning of the conversation. Sounds good. We will see you next time on Visual Studio Toolbox. All right, take care.