Single Responsibility Principle Explained
54sClear, relatable example of a common coding mistake that developers instantly recognize, sparking engagement.
▶ Play Clip"Delivers a clear, practical explanation of SOLID principles, though it doesn't go beyond common knowledge."
This video provides a comprehensive overview of the SOLID principles of object-oriented design, explaining each principle with practical examples and discussing their benefits and potential pitfalls. The presenter emphasizes that these principles are guidelines, not strict rules, and encourages developers to keep code simple.
SOLID principles are well-known but often misunderstood. The video aims to clarify each principle, even for those who think they already know them.
A class should have only one reason to change. Example: a Student class that stores details, saves to DB, sends emails, and enrolls in courses violates SRP. Fix by extracting each responsibility into separate classes, improving reusability and reducing bugs.
Code should be open for extension but closed for modification. Avoid editing existing classes/methods to add functionality. Use the Decorator pattern or extension methods (C#, Kotlin) to add behavior without modifying existing code.
A child class should be able to do everything a parent class can. Example: a Child class inheriting from a Parent class that can 'go to work' breaks LSP. Fix by creating a Human base class with Adult and Child subclasses.
Interfaces should be small and specific. Bulky interfaces force classes to implement unused methods. Split into multiple interfaces (e.g., read, write, delete) and optionally use a main interface that extends them.
High-level modules should not depend on low-level modules; both should depend on abstractions. Example: inject a repository interface into a service via constructor, rather than instantiating a concrete repository directly.
SOLID principles are guidelines, not strict rules. Over-applying them can lead to over-engineering. The real benefit of interfaces is easier testing through mocking. The best advice is to keep code simple.
The SOLID principles provide a solid foundation for writing maintainable code, but they should be applied pragmatically. Always prioritize simplicity and understand the trade-offs.
What does the Single Responsibility Principle state?
A class should have only one reason to change.
00:14
What is the Open/Closed Principle?
Code should be open for extension but closed for modification.
01:48
What does the Liskov Substitution Principle state?
A child class should be able to do everything a parent class can.
03:31
What is the Interface Segregation Principle?
Interfaces should be small and specific, not bulky.
04:09
What does the Dependency Inversion Principle state?
High-level modules should not depend on low-level modules; both should depend on abstractions.
05:13
What is a downside of using extension methods compared to the Decorator pattern?
Extension methods cannot be switched at runtime.
03:17
Single Responsibility Principle
Provides a clear, relatable example of a class with multiple responsibilities and how to refactor it.
00:14Open/Closed Principle
Explains practical ways to extend code without modification, such as the Decorator pattern and extension methods.
01:48Liskov Substitution Principle
Uses a simple parent/child analogy to clarify a commonly misunderstood principle.
03:31SOLID Principles Are Not Rules
Cautions against over-engineering and emphasizes simplicity, a key insight for developers.
06:04[00:01] now solid principles are one of those things every developer has heard of but few fully understand if you use an object-oriented language then being you write better code principles such as a single responsibility principle were
[00:14] fairly self-explanatory whereas the list of substitution principle requires a bit more mental effort to get your head around even those of you who think you probably do with a refresher hopefully by the end of this video you will have a
[00:27] principles even if you struggle to understand them before the first is the single responsibility principle this is one of the more simpler principles of should have a single responsibility giving a class multiple responsibilities
[00:41] change you're more likely to introduce bugs a class should only really have one reason to change so what does that look like in real life now let's say we're creating a teaching application where we're going to have a student class we
[00:55] student into a class like this this however quite clearly breaks a single responsibility principle our student class is responsible for storing student details saving them to the database sending them an email as well as
[01:08] enrolling them in courses so here we have multiple different reasons why we therefore multiple ways that we could introduce bugs on top of that if we have for a student then they'd all end up
[01:21] whole load of merge conflicts when they finish their work so to fix this we need to extract all those responsibilities into their own separate classes this then has the added benefit of letting us reuse functionality without having to
[01:35] repeat the code in several places in our application even though this all seems quite simple it is very easy to take this too far single responsibility only one thing it just means that everything it does should be very
[01:48] closely related so you don't end up with bloated classes the second principle is the open close principle now this principle states that your code should modification if you need to add some
[02:00] application then you shouldn't be editing the existing classes or methods to do that after all you have spent ages writing unit tests for all of those make now would cause them to break on top of that adding in additional
[02:14] functionality to existing methods may cause unexpected consequences wherever you end up calling that method from so how do you go about adding additional functionality without changing the existing methods or classes for these
[02:26] need to check with your language documentation to see which ones were available to you one way to achieve this is to use The Decorator pattern if you functionality either before or after your existing code then this is one way
[02:40] to do that instead of modifying the code we create a new class that implements the same interface we can then call this new method without affecting the other this approach is that you can use dependency injection at runtime to be
[02:53] able to control when this new class is used however you can only use this approach if the method you want to extend is both public and included in the interface another great option is to use extension methods now extension
[03:05] methods can be used in both c-sharp and kotlin as well as a few other languages an extension method allows you to add a method to an existing class without actually having to change that file provided that you have the namespace for
[03:17] the method in the same way you would do if that method was part of the original class the only downside of using extension methods is that unlike The Decorator pattern you can't switch at runtime when this code is used there are
[03:31] the functionality of your application without having to change the existing code such as using inheritance or attributes the next principle is the list called substitution principle now this principle is a little harder to
[03:44] understand it states that a child class should be able to do everything that a parent class can so let's say we have an actual parent class and it might be able to do things such as eat sleep go to work and make dinner then we have a
[03:57] child class that is inherited from that parent class now obviously as a child there's some things they can't do such as make dinner and go to work this would therefore break the list of substitution principle because we can't use the child
[04:09] wherever we've used the parent in our code to fix this we'd have to create a human class and then have an adult and child class that would inherit from that instead the next principle is the interface segregation principle now
[04:21] interfaces provide a contract that your classes need to implement if you have particularly bulky interfaces then your classes are forced to implement methods ever used the repository pattern you
[04:33] this pattern you end up writing an interface that looks a bit like this now interface you need to write an implementation for each of those methods even if you don't plan on using them if you didn't want to implement any of
[04:46] these methods you could of course throw a not implemented exception but that substitution Principle as well to overcome this you can split the methods into different interfaces you might have one for writing one for reading and one
[04:58] of the different methods you could always create a main interface that you only need to implement the methods that you're actually going to use and some code that hasn't been implemented yet the last principle of solid is
[05:13] dependency inversion which states that high level modules shouldn't depend on low level modules they should both depend on an abstraction for example if you had a service class and you wanted to save something to a database you
[05:25] repository class directly inside your service but now your service is dependent on a lower level component to overcome this we create an interface for our repository and then we inject an instance of the repository into that
[05:38] Class via the Constructor now both the high level and low level modules depend on an abstraction which in this case is the interface the service doesn't need to know which repository it's using or how it works it just cares that it meets
[05:51] interface with all software principles it's important to understand that they're not rules that you have to obey they're just there to help you write code for example you can take interface segregation too far and end up having
[06:04] just one method per interface even if you need to use all of them all the requirements could change and instead of modifying the old code you extend it leaving the old code behind that just never gets used depends the inversion is
[06:16] cases you're just going to have one class implementing an interface being able to swap out one database with another one using the same interface is a nice idea but how often have you actually needed to do that the real
[06:29] benefit of using interfaces is it makes everything a lot easier to test because you can just inject a mock whenever you're doing your testing to be honest the solid principles are in some ways too vague to be useful you can follow
[06:41] the solid principles to the letter and still end up writing bad code as always the best advice when you're writing your code is to keep it simple there is which tries to overcome some of the shortfalls of solid and I'll try and
[06:53] cover that in a future video thank you for watching and I'll hopefully see you in the next video [Music]
⚡ Saved you 0h 07m reading this? Transcribe any YouTube video for free — no signup needed.