SOLID Principles with Steve Smith
Episode #8 Published Wednesday, August 12, 2020
This week, I talk with Steve Smith about SOLID principles. We talk about the importance of design patterns and we go through the SOLID principles in detail.
Steve Smith (@ardalis) is an entrepreneur and software developer with a passion for building quality software as effectively as possible. He provides mentoring and training workshops for teams with the desire to improve, and has published many courses on Pluralsight. Steve has been recognized as a Microsoft MVP for over 15 consecutive years, and is a frequent speaker at software developer conferences and events. He enjoys helping others write maintainable, testable applications using Microsoft's developer tools. Connect with Steve at https://ardalis.com/.
Follow Steve on Twitter
- Steve's Pluralsight courses
- Steve's personal website
- Weekly Dev Tips podcast
- Accelerate your career with devBetter
Barry Luijbregts 0:25
Welcome to another episode of developer weekly. This week, I'm talking with Steve Smith, also known as our Dallas about solid principles. Steve is an entrepreneur and software developer with the passion for building quality software as effectively as possible. And he also has published many courses on Pluralsight thanks for being here. Steve. How are you?
I'm doing great. How are you doing?
Yeah, I'm doing I'm doing all right. You know, the, we don't really have a hard lockdown here in the Netherlands. So it's like an intelligent to go fit lockdown. But we might be ramping up with countermeasures. Again, as we see the cases coming up, you know, people are going on holiday.
Steve Smith 1:08
Yeah, yeah, as we're recording this, it's late July of 2020. And in the United States, at least we're seeing like 60 or 70,000 new cases a day. So we're probably not as lucked out as we should be. But I'm doing my best to stay home as much as I can.
Barry Luijbregts 1:23
Yeah, most people here are pretty cautious as well. Although now that it's summer, you see lots of people just, you know, they want to go out and do stuff. They also want to go on holiday. So you see people stress spreading out over Europe, they're going on holiday to France or whatever. So I'm very curious to see what's going to happen when everybody comes back from all those places.
Steve Smith 1:44
Who knows, you know, we're having same things happen here, I think. And it's it's difficult because some states in the United States are trying to implement things like a quarantine for people coming from outside the state. But there's there's no borders for it. There's no there's no checkpoints at the At the state borders, there's no way to implement such a thing except voluntarily and, you know, if people are gonna take the pandemic seriously and do it voluntarily, I think they would at least be wearing masks and things. I don't think you can expect people to voluntarily self quarantine for 14 days.
Barry Luijbregts 2:16
No, definitely not going to do that, please. Most people probably aren't. Yeah, that's difficult times weird times. But hey, at least we can do our thing. Online as as as most of our work, so that's a good thing. Yeah. We're very forthcoming in disguise. Yeah, absolutely. So I follow you on Twitter. And I also sometimes read things on your site weekly, Dev tips.com. I enjoy that. And I always just learn something about design patterns and code quality stuff like that C sharp. So how did you get into code quality and design patterns?
Steve Smith 2:52
It's been something I've been interested in since I discovered them. So as a, as a human, a junior developer, I was always interested in trying to write Better code and just trying to get better at what I'm doing. And so I would read books that had titles that sounded like, you know, that sort of thing. So, you know, in the early days, it was design patterns and refactoring, you know, those classic hardcover books from the 90s. And then more recently, there were books like clean code, and, you know, classic books like code complete. Also from the news. But Stephen candles, get a more recent version. So all of those books just sort of try and describe ways that we can write code in a more consistent, more maintainable way. And I do my best to, to try and write code that that I can be happy with later. And of course, I always fail because I always find better ways to write my code. And if you're not, I think you're not improving. But I think the, the striving toward getting better is the important part.
Barry Luijbregts 3:56
Yeah, definitely agree. It is very difficult to you know, Basically, sometimes when I create something new, it's just, it's a big, messy ball of stuff, right? And then I try to make it pretty and beautiful. But it's sometimes difficult to just know how to go about that. So it's good to learn principles and and more rigid and solid principles to do that, right?
Steve Smith 4:20
Yeah, and a lot of it has just been an evolving of my understanding of object oriented design. Most of the design patterns and things that I talked about are mainly object oriented principles. And when I first was learning about object oriented design, and jointed principles, I was very much thinking of them as literal objects, like in the space of the problem that we were working with, right? So if you're, if you're working on a shopping cart, you know, application, then you might have objects like customer and carts and product or something like that. And until I started getting into design patterns, I didn't really think More abstractly than that, right? That was something that really opened my eyes to the idea that you could use objects to be these abstract things within your solution in ways that you never would have thought to do if you were strictly thinking about them as, as nouns within the requirements that you were trying to build, right?
Barry Luijbregts 5:18
Yeah, I think they're very interesting things. I've also dove into the cloud design patterns, as well as I'm totally into Microsoft, Azure and other cloud providers, which are things like retry pattern and stuff like that. It's a bit different, obviously, then, things that you might do in C sharp, the classic design patterns. They're very interesting things.
Steve Smith 5:41
Yeah, once you know that design patterns exist, you can apply them in any field it seems or in different subfields within software development. So I mean, the point that the the authors of the Gang of Four book make is that they borrowed heavily from a book that was on architecture and town planning. Yeah, that's where they took the their structure of how they described the different patterns from. So it's clearly not something strictly limited to software or even just one type of software modeling.
Barry Luijbregts 6:12
No, absolutely not. No, I don't think so. So, and then one way of applying those patterns, I think and making better and higher quality code is then using the solid principles. Can you tell me what those are and what what those are meant for?
Steve Smith 6:29
Sure. So I suspect many of your listeners probably have already heard of solid but solid is a is a convenient acronym of acronyms for some object oriented design principles. And so real quickly, they stand for the single responsibility principle, the open closed principle, the liskov substitution principle, interface segregation principle, and then the dependency inversion principle. And these have been around some of them since the 80s. That's Two of them were first coined by professors and researchers in the 1980s. And the other three, I think were in the 90s. So they're they're not anything terribly new, although the acronym itself wasn't turned into solid until, you know, I don't know, probably 15 years ago. The first time I read about them, they were described in a book that didn't put them in that order. And so if you were going to make a word out of it, it wouldn't have been solid. It would have been like, oils or something. But yeah, so having having him as a name that you can actually say and pronounce. I think it certainly helps them from a marketing perspective.
Barry Luijbregts 7:40
Yeah, definitely. So these are 10 principles, is that the same as patterns as in design patterns.
Steve Smith 7:48
They're not that the idea is that you have principles that you can use when you're evaluating a design. And then you can use a pattern to try and change the design. implement a particular kind of design in a certain way. And then the nice thing about design patterns is that they're reusable. And so if you are faced with the same problem later on, you might be able to apply a pattern that's that's known to work on that problem. Either because you've used it before, just because other people in the industry know that this is a well known solution to this class of problem. Right? And so you want to use both you want to have principles are more abstract, they're, they're not something that's going to directly tell you exactly what to do. They don't have like a UML diagram that says, This is what this principle looks like. Right? Whereas a pattern is more specific, still broad still, like not something you could just copy paste into your code. But it's, it's like a recipe. It's like, okay, here are the basic things that you need to use this pattern, and then to apply it correctly, and so they're related and so you can use a pattern to To implement a principle or to fix a violation of a principle, if you will, but but they're, they're different. And then the other p that often goes along with those two, principle and pattern is practices, right? And so there's a bunch of books out there that talk about patterns and practices and principles. And I think they're, they're all related, right? And practices are things you actually do in the course of writing software that can be helpful.
Barry Luijbregts 9:27
That's, that's a good distinction to keep in mind. And then principles are more guiding things that tell you the direction in which you might might go, and in which you then look for solutions that you might implement with the patterns. Right. So let's get into these the solid principles, like they're not new, of course, it's always good to repeat and maybe some of our listeners haven't heard of some of the principles.
Steve Smith 9:55
Sure. And, and I've taken to saying recently that if you're a senior developer Upper right even whatever that means to you, you know that maybe that means you've got five years of experience or, you know, you you have people that you're mentoring. If you're at the level that you consider to be a senior developer using an object oriented language, like C sharp or Java, you should be able to teach people the solid principles. So, you know, if you're not at the point where you just know them and can teach them to someone else, you probably want to, to get to know them a little better, I would say. So, the first one is the S is the single responsibility principle. And that one basically says that your classes should be focused on doing one thing and doing it well. They should have one responsibility that they are all about doing and they should be cohesive meaning the things that are in that class, the state and the behavior that are married together within that, that classes encapsulation boundary should all be focused on the same thing. If you look at a class and you can easily see that you know, Half of the properties and methods work together and the other half work together. But separately, maybe that's two classes, right. And you could refactor that, to split it up into two classes that each did their own thing, and didn't have to worry about the other parts that the other one was doing.
Barry Luijbregts 11:16
And does this only apply to the class level or also to the methods because in a class that has a certain responsibility, you could have a method that tries to do two three things, maybe that are slightly different as well.
Steve Smith 11:29
Sure. And obviously, if you're following it at the class level, you want your methods to be focused. And there's other principles that apply and code smells, which is another whole topic that apply at the method level. But generally, these principles apply at the class level. Although it's certainly true that you know, if you if you have a class that follows single responsibility, its methods should be fairly small and focused on things within the realm of that responsibility.
Barry Luijbregts 11:57
Yeah, I've seen people try to get away from It weird stuff, you know, that's 2000 lines of code class, Red Hat a certain responsibility, but then the methods to do all sorts of weird stuff.
Steve Smith 12:11
Yeah, well, and I don't know that it's clear what a responsibility is. So when I teach these principles, I try and lay out like, what are some examples of responsibilities, because it's all too easy for someone to say if I if I go back to the, you know, the simple shopping cart example I mentioned, it's very easy for someone to say that, you know, I've got a class called shopping cart manager. And it's only responsibilities to do anything and everything related to the shopping cart. And that includes checking out adding items, removing items, validating, checking all the prices, verifying all the sales, making sure you know, that the customer follows whatever discounts they have taken care of handling and calculating all the shipping and on and on none, right. So it's not, it's not correct to say that the responsibility is you know, everything to do with Some broad topic or some broad object within the system. Like that's, that's probably too big, you know. So things like validation or responsibility, persistence as a responsibility. interacting with other collaborators is a responsibility. deciding who your collaborators are is a responsibility. If you're if you're inside of the class and all of the things you're working with, you're newing up or calling statically. That class is deciding specifically what other things it's going to work with. And that's a separate responsibility. Right. That's something that could be done somewhere else.
Barry Luijbregts 13:34
Yeah, definitely. It's it's probably difficult to find the scope of the responsibility for yourself. It's it's a bit of common sense, of course.
Steve Smith 13:43
Yeah, it takes it takes experience, I think and it takes Yeah, I mean, some of you could say it's common sense, but that's common sense. Isn't that common? And a lot of what I think of is common sense is, is really just experienced, but you have a hard time. You know, saying what it is exactly right. Yeah. So it's it can be hard, right? But at the end of the day, if you are following the single responsibility principle, what you'll find if you if you compare two projects, or two designs that do or don't follow it, is that you will tend to have more classes, and those classes will tend to be smaller. Right. So when we think about how that affects our practices, and maybe our tools, that means that we should get better at finding files in classes within our solution, and organizing them in such a way that it's easy for us to work with more files that are smaller. If you're only comfortable scrolling through 2000 line long classes, and you don't really have the the muscle memory or the experience of working with lots of small classes, then it's gonna feel unfamiliar to you. It's gonna, it's gonna there's gonna be friction, right? And so, moving toward following this principle sort of requires that you skill up In in working with smaller files, which isn't necessarily what, what a lot of developers are used to.
Barry Luijbregts 15:05
no, no, I see a lot of them do it. Well. So this is very good. Good principle. All right. So that's the single responsibility principle. And the second one is the open closed principle. Right? Can you tell me about it?
Steve Smith 15:21
So the open closed principle is sometimes confusing, because it says that your classes should be open to extension, but closed for modification. And what that means is that you should be able to change how your class works, what it does its behavior without actually changing its source code, without having to recompile it and redeploy the code to run it. And at first, oftentimes, if you've just hearing about this principle for the first time, you might scratch your head and be like, well, how the heck does that work? How am I going to change my code? Does without changing my code. But if you think about it, we do this all the time, right? The simplest way to take some code and change what it does without actually changing the code is to provide a parameter to it some kind of input that when you change that input, it changes what the code does just a parameter. And so a lot of how you implement the open closed principle is just about how we specify behavior by passing it in, in the form of parameters either at the method level, or as a constructor parameter or a property.
Barry Luijbregts 16:33
So this could mean that if you have a constructor in a class that has a certain parameter that takes, let's say, a logging mechanism or something that you might be able to inject a completely different logging system in there, then they would originally have and therefore, change the behavior of the class to lock to a different system or different output for instance.
Steve Smith 16:57
Sure, imagine that you wrote some code and you literally just hard coded all of your logging. And you said, I'm going to log everything to C colon backslash log dot txt. And you do and you write that code and you and it works great and you ship it. But then somebody wants to run this code, and they want to log it somewhere else, or they want to run it on Linux that you know, doesn't necessarily have a C, colon, backslash, right, or a Mac. And so now you're stuck, like you've hard coded too much into a particular implementation. And the only way to change it now is to recompile it because you've compiled all that stuff right into that routine that class. So like you said, If you instead passed in some type of a logger, class, or abstraction, or interface, and then you can implement it in such a way that maybe for you, it's fine for it to just log to a local file on your C drive. But someone else could implement that in a different way. And instead, it could be logging in any way you can imagine, right? It could go to a database, it could go to a different location, it could go to something some debug viewer, right? Yeah. And and so Now your code is open to extension and closed to modification, meaning you don't need to modify it. You don't have to change the source code now in order to get that that extended behavior.
Barry Luijbregts 18:11
Yeah. Which is a great principle. And I think you shouldn't take this too far. Obviously, as in, if you have a database layer or data access layer that uses SQL server or something, you shouldn't always make it so that it can also use all sorts of other databases, for instance, right?
Steve Smith 18:30
Now, yeah, not necessarily, right, every every way in which you allow your system to be extended, makes it more abstract, makes it generally more difficult to quickly understand what it's doing. So when you look at the code itself, and you try and see what like, what does this code actually doing, if it's very abstract, and there are a lot of ways that it's hooking into other things that are being passed in through parameters or constructors or dependencies, it can start to become difficult to figure out where the actual work is being done. And that's a common criticism that gets laid against, you know, overly abstract, overly designed object oriented systems. And so there's a balance here, right. And so you don't want to try and make your system extensible in every possible way up front. Instead, you want to wait and see where the changes are going to occur and where the pain is coming from. So I like to tell developers to follow PDD pain driven development. And if it's causing you pain, then use these principles or these patterns to find a way to alleviate that pain. If you if it's not causing any pain, right? If just logging straight to a sequel and text file is fine, and nobody's asking for anything else, then leave it alone. It's working. But But after the second or third time that somebody is asking for a new way to do something, you should recognize that this is an axis of change in your system. that's likely to continue to be an axis of change. And so consider making it extensible
Barry Luijbregts 19:58
Yeah. Oh, that's a great That's a great principle. Pain driven development. I love that. Yeah, but it's definitely true. Especially even for things like performance optimizations, you know, I love to do performance optimizations myself, and I can just spend weeks on it. If you just let me. It's just it's usually really not necessary. Because it's fast enough, probably by default, and nobody asks for it as well. Right? So only if it's a problem, then you should really focus on it.
Steve Smith 20:28
Yep, exactly. It's a it's a premature optimization. Yeah.
Barry Luijbregts 20:32
All right. So that is the open closed principle. And then the next one is liskov substitution principle. Can you tell me about that one?
Steve Smith 20:40
Sure. So this is the only principle that's actually named for a real person, which is Barbara liskov, who's a professor at MIT. And she coined this back in the late 80s. And the idea is that your objects should not just be oh sorry if your objects that inherit from another object or type should not just be that thing, right, they shouldn't just have an is a relationship, like we hear so often when we first learned object oriented programming, instead, they should be substitutable for that base type, anywhere and everywhere that they might be used. And so where you commonly see violations of this principle is where you might have a fairly large class or interface that you're implementing. And you, you only need some of it right now. And so you you leave some of the bits either undone, or maybe they're throwing and not implemented exception. And so you ship your code like that. And later on, somebody comes along, and they need some, some some instance of this, this interface, this type, and they see that there's already one that's been made. There's there's a provider or an adapter or whatever you want to call it that you've created for them. And so they they inject that into their system and they expect it's just going to work. And at runtime, it blows up and it says not implemented. exception. Right. And so it wasn't fully substitutable for the parent. And that's that's the best case scenario. That's where it's, you know, obviously broken, right? Because it's giving you that exception. What's worse is when it's not really easily detectable that it's doing the wrong thing, or it's not doing what it should. And that's, that's a much tougher bug to find. One of the ways you'll see this manifest in your code, is if you're doing something that should be polymorphic. Like you have a for each over a bunch of types, but they might be not actually that type. There might be a subtype. And then inside your for each loop, or inside your method that takes an instance of this base class, you're checking to see which specific subclass they might have. Right? So you like, Hey, I'm going to print out all the employees. So I say for each employee in this collection of employees, and then inside your loop, you say, Well, if employee is manager type, then I want to do something different. Like right there. Your brain Making liskov substitution because now you're checking to see what kind of type this thing is it shouldn't matter, right? That's what polymorphism is all about is you should be able to treat it exactly like its base type. And if you can't, if you have to know what its actual type is, then you're breaking that principle of object oriented programming.
Barry Luijbregts 23:18
That's it. That's a great principle. I see that a lot actually, in production API's still, yeah, that you hit something and then it's not implemented yet exception. Terrible, right?
Steve Smith 23:29
And where that's really a problem is because of the duplication that it entails. So if if there's one place where you need to know that subtypes specific type, because you want to do something different, okay, that's not terrible, right? That's fine. But it tends to spread. So you know, in your application, it's not going to be just one place probably where you're checking that it's going to be everywhere, you're dealing with a set of that base type, right? There's going to be some exception for some certain type that's implemented a different way. And so now when whenever some new features comes along or some change needs to be made, you've got to remember to go to all those different places, and, you know, tweak them to make sure they work just right now. Or maybe you add another subtype, and it behaves even different still from the other ones, right? So again, you've got to go to all those places where you're not using polymorphism correctly, and make sure you've got enough checks in all the right places for that new behavior. And that's where that's where you end up missing some in bugs creeping?
Barry Luijbregts 24:25
Yeah, that's definitely where the bugs creep in. Yeah. And those are difficult to find as well. Certainly. Alright. So that is a liskov substitution principle. And then the next one is interface segregation principle. What is that?
Steve Smith 24:40
So really briefly, the interface segregation principle says that classes should not depend on methods that they don't use or functionality that they don't use. So if you have a class, and it depends on an interface, let's go back to that logger example. Right you you've got this method that will log a line of text But then it also has some method for, I don't know, copying the log file to a backup store, right? Well, your class doesn't care about that it only cares about logging stuff. But But now there's this other method that that's all about copying things to a different store. And if that method changes, then you're going to have to recompile your code because you depend on that, even though you're not using it. And so you end up having larger ripple effects from your changes. When you have larger interfaces. And you have classes depending on pieces of those interfaces. They don't use, they don't need. So the the general way to follow the interface segregation principle is to do two things. One is to have very small interfaces that are basically following the single responsibility principle doing just one thing well, and then to having clients control their interfaces. So instead of shipping interfaces with a framework or with some set of base classes that you know, the company Many architects put together when you're writing the actual service that needs the thing. You write the interface that exposes exactly what your service needs. And then you implement it with whatever you need to write.
Barry Luijbregts 26:14
Yeah, and it's very specific.
Steve Smith 26:16
Yeah. And this this way, it leads into the next principle, the dependency inversion. Because, you know, normally what, what developers, especially junior developers expect, is that someone's going to give them the the framework in which to work, right? They're gonna be like, okay, here's, here's the, the, the high level structure, you just fill in the details, including stuff like base interfaces and base objects and things like that. Yeah, interface segregation, kind of says, Hey, actually, as you're creating this service that you're writing, if there are certain things you need from other dependencies or other things, you know, create an interface that is specifically for your service, or at least specifically for services like yours. And so you may not end up with an interface for every single class that needs something that would probably be overkill. But you should have some very small, very cohesive interfaces that work with your set of services that all need sort of the same thing. The dependency inversion principle, I don't want to I don't want to skip over because I actually think it's probably the most important of these principles. And what it states is that you don't want to have your high level modules depending on low level modules. Instead, you want low level stuff to depend on high level. And that kind of presupposes that we know what high and low level means. So let's let's define that real quick. Low Level means closer to an input output, you know, closer to writing bits on disk or taking input from the user, right the user interface or the data access layer, talking to the file system. That's all low level stuff. High Level is more abstract and you know the the concepts of the overall software like, you know this, this customer wants to add this item to their cart, right? It doesn't know anything about specific operating systems or file formats or anything like that those are all low level details. All right. And then related to that the high level and low level modules shouldn't depend on specifics, they should depend on abstractions instead of the other way around. So it's what's commonly the case, if you don't follow this principle is that you write code that just depends directly on its infrastructure. So if we go back to that logging example that we've been using, you know, you write some simple console app, you want to log some stuff out. So inside of there, you just new up a file using the file system API's that are in the framework, and then start writing lines directly to that file. Right. There's no abstraction there at all. You're working directly with a low level file protocol. And you probably don't have any interface You wouldn't need any interfaces in that example, because it's just a, you know, program.cs console app. But as a result, it's it's not very testable. So very extensible. It doesn't really follow object oriented principles at all. And to get it closer to being able to do those things, which needs to do is introduce some abstractions, and then depend on those instead of the details. And where this plays in the biggest benefits. And what I've seen is when you switch from having a classic interior architecture, where you have a UI that depends on a business layer that depends on the data layer that depends on a database. That's the classic model that that folks have done for decades. That's what I cut my teeth on as a junior developer was building things like that in the late 90s, early 2000s. You if you switch that and you flip it on its head and you say, No, we're going to have the the low level, the data access layer, the file providers, all those low level two Things, instead of having the business layer depend on those, we're going to have those depend on the business layer. And if you start thinking about domain driven design, which which also have a course on Pluralsight about now that that domain model is your business layer, that's sort of the core of your application. And the infrastructure, the data access layer, depends on that core instead of the other way around. And that's, that's what the inversion is talking about the dependency inversion principle, is inverting the dependency. So instead of having your high level code depend on low level code, you flip that and it's the other way around,
Barry Luijbregts 30:37
And because of that, you can also switch things out way more easy, the low level bits, or you can use another implementation or something like that writes to disk or writes to another database or whatever.
Steve Smith 30:48
Right now your code is incredibly modular, and there are many seams in it that make it much easier to test.
Barry Luijbregts 30:54
Alright. So those are the solid principles, which are great principles. To follow, but how do you embed those in the development process of a team? And make sure that everybody's following them?
Steve Smith 31:09
I think the the best thing is to have everyone sort of know what they are, right? So have some sort of level setting, you know, some lunch and learn or everybody watch this Pluralsight course or some training or whatever, if necessary, right? If there isn't already that that understanding. But once people at least know what they are, then in whatever passes for code review on your team, whether that's pair programming, or formal code reviews, or looking at pull requests, be be very clear about which principles you're citing when you offer feedback related to those. So if you're working with someone, and you're pairing on a class, and you adding some functionality, and so you add another method to this class, and the class is getting bigger, and this new thing isn't really related to what we were doing before. You know, it would be perfectly reasonable to say, Hey, aren't we sort of breaking single responsibility principle here, maybe we should put this in a new class. Like that would be, you know, one way that you would implement it. And I think just that's, that's really the best way is for team members to keep these principles in mind when they're looking at code when they're designing code, either as they're writing it or as they're reviewing what others have written. And then use the principles as a way to evaluate the quality of the code.
Barry Luijbregts 32:25
And then constantly try to identify them as well, if you see them or as you try to design your codes.
Steve Smith 32:33
Yeah. I mean, if you see that they're being egregiously broken, right, then the principles are something that you can cite, right? It's not just you saying that, hey, I think that this is too big. You can say, well, this principle that's been around for decades that many people in the industry feel is a good thing suggests that maybe we should try and keep this smaller or keep this, you know, dependency at arm's length or whatever it might be.
Barry Luijbregts 32:56
Exactly. That is, that is a great practice. I think lots of people already do that. Hopefully I've seen it a lot, especially during code reviews as well. I've had a lot of reviews where we also talked about the solid principles. So that's very good. And if you're not doing this yet, then please dive into these principles and to try to embed them in your, in your process. I do any additional resources that listeners might be able to visit to learn more about these principles.
Steve Smith 33:31
Sure. So I've got a couple of Pluralsight courses that are relevant. I've got two different courses on solid principles. One of them has been archived, but you can still get to it from my author page on Pluralsight. If you don't have a Pluralsight subscription, you can use a trial from their homepage and you'll get like a 10 day period when you could watch whatever you want. I also have a podcast of my own, where sometimes I talk about these principles. I have some some episodes in the past. I've covered them Which is at https://weeklydevtips.com/ or on https://www.youtube.com/weeklydevtips channel. And you can also follow me if you like, I'm frequently talking about these things at conferences or on Twitter. So everywhere online, you'll find me as ardalis, which I'm sure will have a link to in the show notes.
Barry Luijbregts 34:17
Absolutely. Yes, I will link to all of this in the show notes. This was delightful. Thank you very much for teaching me about the solid principles. And we'll see you next week on another episode of developer weekly.
Steve Smith 34:31
Barry Luijbregts 34:35
Thank you for listening to another episode of developer weekly. Please help me to spread the word by reviewing the show on iTunes or your favorite podcast player. Also visit https://developerweeklypodcast.com/ for show notes and the full transcript. And if you'd like to support me in making the show, please visit my Pluralsight courses to learn something new.