Uncle Bobโs SOLID Principles Made Easy ๐ - In Python!
Key Takeaways
The video discusses Uncle Bob's SOLID design principles using practical examples in Python, covering Single Responsibility Principle, Open-Closed principle, Liskov Substitution Principle, Interface Segregation Principle, and Dependency Inversion Principle.
Full Transcript
the solid design principles help you write great code that's easy to reuse and extend and that's going to save you a lot of time today i'm going to show you exactly how they work using practical examples in python let's dive right into it if you're new here you want to become a better software developer and gain a deeper understanding of programming in general start now by subscribing and hitting the bell so you don't miss anything the solid design principles were first mentioned in a paper written in 2000 by the software engineer robert martin also called uncle bob what's going on with all these weird naming schemes in computer science gang of four uncle bob what what kind of vibe are we going for i'm uncle arjun and have i got something solid for you [Music] solid stands for five principles single responsibility open closed list of substitution interface segregation and dependency inversion i've talked about some of these principles before but in today's video i'm going to take you through a code example of a sales system with order and payment handling in python to illustrate each of these five principles in a practical setting the example i'm going to talk about today is a sales system there's a class order that has items quantities and prices and the payment status and there are functions for adding items computing the total price and paying the order in this example i create an order i add a couple of items then i print the total price and finally i pay the order and this what happens when i run the program so very straightforward we create an order of 210 dollars we're processing a debit payment type and we're verifying that with the security code and the pay method that you see here is basically responsible for dealing with the payments the first of the five principles installed i'm going to talk about is single responsibility we want classes and methods to have a single responsibility another way to say it is that we want classes and methods to have high cohesion be responsible for only a single thing and that ensures that you can reuse them much easier later on in this case the order class does way too many things i mean adding items you can understand it's part of an order because you want to be able to add items to an order computing the total price could also still be part of the order but handling the payment definitely shouldn't be part of the order so the order class has way too many responsibilities and we need to fix that now the way we can do it is for example by extracting this pay method and putting it into a separate class that has another advantage because if later we want to add other payment types like bitcoin or apple pay or whatever we don't have to change the order class anymore we can do it in the payment processing side of things so let's do that so i'm going to create a class here called payment processor and inside that class we want to have the different payment methods now at the moment the pay method is not ideal because there's like an if else statement in here that checks for the various different payment types and i think we want to do something different so let's redesign this method and split it into two methods pay debit and pay credit so i'm going to copy over all this code and then i'm going to refactor it so that it fits with our new design so instead of a pay method we now have a pay credit method and a debit method i'm just copying over everything and then remove what i don't need anymore we no longer need to know the payment type because that's encoded in the method name so i'm removing that here and then i'm going to remove these if statements because we don't need that either so now we have to pay debit and pay credit methods inside a payment processor class the only issue is that we want to set the order status to paid so this means that the payment processor actually needs the order in order to process the payment so we're going to pass that as a parameter now we need to do is not call order.pay anymore but create a payment processor and then use that so now we have a separate pavement processor and we can remove this bay method from the order class so much shorter classes we've made sure that order and both payment processor have their own single responsibility which is handling adding stuff to the order and processing the payment and when we run this code we are going to get exactly the same result as before except that of course i need to add the order object to the payment processor there you go that's the single responsibility principle if you look at what we did we increased the cohesion order has one responsibility payment processor has one responsibility but we also introduced some coupling we'll deal with that later on the second principle the o in solid stands for open closed and that means we want to write code that's open for extension so we should be able to extend the existing code with new functionality but closed for modification we shouldn't need to modify the original code in order to do that let's take a look at what this means in the order example so we have our order we have our payment processor and we have creating the order and processing the payment here in the example now the issue is if we want to add an extra payment method like bitcoin or apple pay or paypal or whatever we have to modify the payment processor class so that violates the open closed principle optimally what we'd like to do is create a structure of classes and subclasses so that we can just define a new subclass for each new payment type in order to do that we need to refactor this payment processor class so let's turn it into an abstract class and create sub-classes for each of the different payment types so i'm going to import the abc module here and let's create an abstract payment processor class that code we're going to need later and we're going to add a single method abstract method that's called pay so now what we can do is for each payment type create a subclass for example let's create a debit payment processor and that's a subclass of payment processor and similarly let's create a credit payment processor we don't need this code anymore and now what we do here is create one of these instances of the subclass and then simply call the pay method there we go let's run this yeah still works fortunately but now we do not violate this open close principle anymore because if we want to add another payment type like paypal for example we don't have to change the payment processor or the order anymore let's try and do that so now i've created a new paypal payment processor and we can use it here without having to change anything about the order class or anything related to that the third principle is lisk of substitution and that means that if you have objects in a program you should be able to replace those objects with instances of their subtypes or subclasses without altering the correctness of the program let's take a look again at this paypal payment processor now the thing is that paypal payments don't work with security code but with email addresses so if i wanted to fix that without changing anything in the code what i probably should do is make sure that this is actually an email address and not a security code so i'd do it like this but then here i would provide some kind of email address the issue is that this is not supposed to be security code but an email address so we're kind of abusing this type to do something different than we're supposed to and that means we're violating the liskov substitution principle one way to solve this is by removing this dependency from the pay method and actually setting it in the initializer so that we can do different things in initializer depending on the type of class we create so let's remove security code here and that means we also have to remove it here here and here and then let's add an initializer and we can add the same initializer to the credit payment processor and the paypal payment processor then gets an email address and we should add self because now it's an attribute of the class instead of a method parameter so there we go now if we create the paypal payment process so we don't pass the email address here anymore but as a parameter to the initializer and now let's run the code again and we get again the same result but now we're properly using the pay method instead of changing what parameters mean in order to fit our specific use case by the way if you're enjoying this content so far give this video a like the fourth principle in solid is interface segregation interface segregation means that overall it's better if you have several specific interfaces as opposed to one general purpose interface i've extended this example to now include a two-factor authentication inside the payment processor class so there's an off sms that gets a code and that authorizes the payment in the debit payment processor i've implemented this in a very simple way just putting a verified variable to true whenever we retrieve an sms code normally you would do all kinds of checks here i'm not implementing that for the sake of simplicity the issue is that a credit payment processor doesn't have two-factor authentication so what we do here is i raise an exception that credit card payments don't support this and paypal payment processor does support it so i have a similar kind of implementation here and the only thing i added to the pay method is checking that the payment has been verified and i'm only doing that in the debit and in the paypal payment process because for credit payments it's not allowed here you see an issue with defining a generic interface like the payment processor to do multiple things that are not always applicable to subclasses in this case not all subclasses support two-factor authentication so it's better to create separate interfaces for this and what you could do for example is add a second subclass of payment processor that adds sms two-factor authentication capabilities so let's add that class here and this is a subclass of payment processor payment processor no longer contains this sms authentication method but we put it in the payment processor sms class and this one is no longer needed because it's already in the superclass and now we can use this class and only inherit from that class if we support sms authentication so that's the debit payment processor and that's the paypal payment processor and then the credit payment processor we don't need to put in this weird sms authentication method that always raises an exception so that's much cleaner this way so that's interface segregation so instead of one general purpose interface we split it so that subclasses can have more meaningful behavior instead of doing this with classes and subclasses you can also use composition which arguably makes more sense in this example what do i mean by that so we have the authentication method here but what we could also do is create a separate class called sms authorizer that handles the authentication let's add that class and that class has two methods one for verifying an authorization code and second for checking that it's authorized for now let's assume that all codes are always valid obviously normally you would add checks here to verify that the code is actually found then we have an is authorized method that returns a bool you could directly access the property but this is a bit cleaner a payment processor still only has a pay method but we don't have this class anymore but now our specific subclasses receive an sms authorizer if they are using that functionality so the debit payment processor doesn't only get a security code it also gets an authorizer and i'm adding a type in here to just make sure that we know what type of object we're getting also now we don't store the verified status anymore inside the payment processor because our authorizer is responsible for that the offs mess function is no longer there and inside the payment method we call the is authorized method from our authorizer and let's do something similar for the paypal payment processor there you go now we need to change the code here to create this authorizer for us and instead of calling off sms on the processor we're calling it on the authorizer and now we should get a similar result as before oh i think i forgot to change this class here let's try that again yes there we go so now what happened is that we used composition instead of more subclasses to create a similar effect myself i tend to use composition more than inheritance because most cases i noticed i don't really need a big inheritance tree i just need to separate the different kinds of behavior in my application and composition works very well for that the final principle in solid is dependency inversion i talked about that one before in another video if you want to check that out click here or here somewhere dependency inversion means i want our classes to depend on abstractions and not on concrete subclasses and in this code this is currently an issue because the payment processes are depending on specific authorizers in this case an sms authorizer so to solve that is create another abstract authorizer class that you pass to the payment processors let's create that class the authorizer class only contains an is authorized method and sms authorizer is now a subclass of that class there we go instead of passing an object of this type to a payment processor we're going to pass an object of this type so let's change that here in the code let's run that now nothing really changed in terms of behavior by doing this but now we can add other things that make this easier to use for example let's say i want to create another authorization method like checking that you're not a robot so let's add another class to deal with that just gonna copy over part of this code but not a robot doesn't have a verify code method it has a not a robot method and now we can do is create another authorizer here and call the not a robot method instead so that's dependency inversion and that works because we made sure that the authorizer is of type authorizer and not of type as a mess off i hope these examples clarify what the solid design principles mean and how they translate to practical applications if you've been using these principles already in your code let me know in the comments below though it is important to know about these principles as a software developer i do notice that as you get more comfortable in applying these they kind of get ingrained into the way you work in my case for example i don't think about these specific principles anymore when i write code i just automatically gravitate towards solutions that incorporate them i have a lot more python videos in the pipeline so make sure to subscribe and come on over to discord to hang out and talk about software design thanks for watching take care and stay tuned for another video of uncle arjun posse of one son why don't you come on over and sit on uncle arjun's lap i love talking in third person [Music] we don't want classes to have low cohesion and be responsible for too many different things first we're going to explain the code example darn and there are a few functions that help me create different orders i hope these examples clarify these these i hope these examples clarify what the solid design principles mean and better better i just automatically go
Original Description
๐ก Learn how to design great software in 7 steps: https://arjan.codes/designguide.
In this video, I discuss the SOLID design principles by Robert Martin (Uncle Bob) using practical examples in Python. Though the SOLID principles are one of several sets of software design philosophies, and arguably quite specific for Object-Oriented programming, they are the most well-known and easy to apply to your own code.
You can find the code I worked on in this episode in my GitHub repository: https://github.com/arjancodes/betterpython
๐ ArjanCodes Courses: https://www.arjancodes.com/courses.
๐ฌ Join my Discord server: https://discord.arjan.codes.
โจ๏ธ Keyboard Iโm using: https://amzn.to/49YM97v.
๐ Chapters:
0:00 Intro
1:08 Example explanation
1:45 Single responsibility principle
5:01 Open/closed principle
7:36 Liskov substitution principle
9:48 Interface segregation principle
12:12 Interface segregation variety using composition
15:25 Dependency inversion
17:29 Final thoughts
18:15 Gag reel
#arjancodes #softwaredesign #solidprinciples
Watch on YouTube โ
(saves to browser)
Sign in to unlock AI tutor explanation ยท โก30
Playlist
Uploads from ArjanCodes ยท ArjanCodes ยท 14 of 60
1
2
3
4
5
6
7
8
9
10
11
12
13
โถ
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
Full stack WEB DEVELOPMENT in 2021 - the ULTIMATE tech stack for FAST web app development
ArjanCodes
FROM PRODUCT IDEA TO SOFTWARE - turn your idea into reality in a few steps
ArjanCodes
Cohesion and Coupling: Write BETTER PYTHON CODE Part 1
ArjanCodes
Build a GLASSMORPHISM React Component - Typescript & Material-UI
ArjanCodes
Observer Pattern Tutorial: I NEVER Knew Events Were THIS Powerful ๐
ArjanCodes
100% CODE COVERAGE - Think You're Done? Think AGAIN.โ
ArjanCodes
Two UNDERRATED Design Patterns ๐ก Write BETTER PYTHON CODE Part 6
ArjanCodes
1000 Subscribers! ๐ WHY I Started this Channel and WHAT'S NEXT
ArjanCodes
Channel Trailer ArjanCodes - March 2021
ArjanCodes
Exception Handling Tips in Python โ Write Better Python Code Part 7
ArjanCodes
Monadic Error Handling in Python โ Write Better Python Code Part 7B
ArjanCodes
GW BASIC Games I Wrote When I Was a Kid ๐ฎ Running 30 Year Old Code
ArjanCodes
Why You Should Think About SOFTWARE ARCHITECTURE in Python ๐ก
ArjanCodes
Uncle Bobโs SOLID Principles Made Easy ๐ - In Python!
ArjanCodes
QUESTIONABLE Object Creation Patterns in Python ๐ค
ArjanCodes
If Youโre Not Using Python DATA CLASSES Yet, You Should ๐
ArjanCodes
CODE ROAST: Yahtzee - New Python Code Refactoring Series!
ArjanCodes
7 UX Design Tips for Developers
ArjanCodes
Going All-in on Software Design in Python + an ANNOUNCEMENT ๐
ArjanCodes
๐ Interview with Sybren Stรผvel, Developer @ Blender 3D
ArjanCodes
Do We Still Need Dataclasses? // PYDANTIC Tutorial
ArjanCodes
7 Python Mistakes That Instantly Expose Junior Developers
ArjanCodes
Answering Your Most Frequently Asked Python Questions // Q&A 07-2021
ArjanCodes
GitHub Copilot ๐ค The Future of Software Development?
ArjanCodes
More Python Code Smells: Avoid These 7 Smelly Snags
ArjanCodes
Test-Driven Development In Python // The Power of Red-Green-Refactor
ArjanCodes
5 Tips To Keep Technical Debt Under Control
ArjanCodes
Refactoring A Tower Defense Game In Python // CODE ROAST
ArjanCodes
The Factory Design Pattern is Obsolete in Python
ArjanCodes
Why the Plugin Architecture Gives You CRAZY Flexibility
ArjanCodes
Refactoring A Data Science Project Part 1 - Abstraction and Composition
ArjanCodes
Refactoring A Data Science Project Part 2 - The Information Expert
ArjanCodes
Refactoring A Data Science Project Part 3 - Configuration Cleanup
ArjanCodes
Purge These 7 Code Smells From Your Python Code
ArjanCodes
Running A Software Development YouTube Channel
ArjanCodes
Refactoring A PDF And Web Scraper Part 1 // CODE ROAST
ArjanCodes
Refactoring A PDF And Web Scraper Part 2 // CODE ROAST
ArjanCodes
How To Easily Do Asynchronous Programming With Asyncio In Python
ArjanCodes
The Software Designer Mindset
ArjanCodes
NEVER Worry About Data Science Projects Configs Again
ArjanCodes
Powerful VSCode Tips And Tricks For Python Development And Design
ArjanCodes
8 Python Coding Tips - From The Google Python Style Guide
ArjanCodes
What Is Encapsulation And Information Hiding?
ArjanCodes
8 Tips For Becoming A Senior Developer
ArjanCodes
Building A Custom Context Manager In Python: A Closer Look
ArjanCodes
GraphQL vs REST: What's The Difference And When To Use Which?
ArjanCodes
You Can Do Really Cool Things With Functions In Python
ArjanCodes
Announcing The Black VS Code Theme (Launching April 1st)
ArjanCodes
7 DevOps Best Practices For Launching A SaaS Platform
ArjanCodes
Refactoring a Rock Paper Scissors Lizard Spock Game // Code Roast Part 1
ArjanCodes
Refactoring a Rock Paper Scissors Lizard Spock Game // Part 2
ArjanCodes
Things Are Going To Change Around Here
ArjanCodes
Dependency Injection Explained In One Minute // Python Tips
ArjanCodes
How To Setup A MacBook Pro M1 For Software Development
ArjanCodes
A Simple & Effective Way To Improve Python Class Performance
ArjanCodes
How To Write Unit Tests For Existing Python Code // Part 1 of 2
ArjanCodes
How To Write Unit Tests For Existing Python Code // Part 2 of 2
ArjanCodes
Make Sure You Choose The Right Data Structure // Python Tips
ArjanCodes
5 Tips For Object-Oriented Programming Done Well - In Python
ArjanCodes
Next-Level Concurrent Programming In Python With Asyncio
ArjanCodes
More on: LLM Foundations
View skill โRelated AI Lessons
โก
โก
โก
โก
A Young Designerโs Question: What Are Companies Actually Hiring For?
Medium ยท UX Design
Why Clear Calls-to-Action Are Essential for Business Websites
Medium ยท UX Design
AI in Design: The Skill That Gets Scarce When Making Gets Cheap.
Medium ยท AI
Sheba Manager Mobile Apps: Retail OS in the Palm of a Merchantโs Hand
Medium ยท UX Design
Chapters (10)
Intro
1:08
Example explanation
1:45
Single responsibility principle
5:01
Open/closed principle
7:36
Liskov substitution principle
9:48
Interface segregation principle
12:12
Interface segregation variety using composition
15:25
Dependency inversion
17:29
Final thoughts
18:15
Gag reel
๐
Tutor Explanation
DeepCamp AI