Why Use Design Patterns When Python Has Functions?
Key Takeaways
Compares design patterns from the Gang of Four book with functional approaches in Python
Full Transcript
I often hear people say that design patterns from the gang of four book are Obsolete and that in Python you don't need them at all because well you can just use functions now do think that in many cases you can use functions instead of classes that the design patterns book uses and you're going to achieve the same thing but with simpler code but I don't think design patterns are obsolete at all not even in Python and I'll show you why to illustrate this I'm going to look at a few common design patterns and show you an alternative approach using functions now the original design patterns book is still a good read even today but you may not want to use these patterns exactly as they were described in the book it's not because the book isn't good at the time it was published well basically everybody was talking about it just after the book was published I started studying computer science at the University that was actually before Java was popular so I was taught programming with modula 2 which is a procedural language it's quite similar to Pascal actually I was living at a student house at the time we had like 12 people in the same building and there was like a shared living room and we had a shared fridge also where we could get drinks so in order to keep track of all our expensive and who got which drink and who had to pay how much which by the way is a very Dutch thing way of dealing with it I created a full like system like an application using modula 2 uh to actually keep track of those things it was a text based system but it had windows so it was drawing Windows using uh text uh and it even had like window animations was like really cool it's a Pity I don't have to code anymore I could have shown that here on the channel it even had shortcuts so if I wanted to get a beer uh instead of going through the menu and opening the window I could just uh type Aram one beer or even have like a keyboard shortcut a1b so it was really fast to just book a drink that that you then got from the fridge and then of course as the evening progressed we uh started to get less precise with entering the actual uh thing that we got so then at the end of the month we always had like plenty of beers that were missing or people that uh apparently consumed way more drinks than was humanly possible uh so it was not ideal but still it worked pretty well and I think they even used that system that I built when I was studying for a couple of years after I left that house so that was uh I guess one of my first production software systems that I developed anyway back to design patterns I remember when design patterns was introduced in my study program it was actually a brand new course that was set up using C++ and that was I think for me one of the most important courses in my software development career I learned so much about how to use objectoriented programming and how it actually works and how to use use it right now today I'm not using design patterns in the traditional sense in that way anymore but for me it was really an eye opener at the time so let's take a look at a few of these design patterns and why I think they're still important the first pattern that I want to take a look at is the strategy design pattern it's a really a classic pattern I'm using that all the time in my code maybe not this version that I'm going to show you right now but I am using another version that I'll show you afterwards it's pretty simple you have a class which has a method it's in this case I'm using abstract based classes to Define that classes it's an example with sorting the aim of the strategy pattern is that allows you to replace one algorithm with something else without the system that uses the algorithm to know about it and here's an example where I do that with sorting now normally you won't develop your own sorting algorithms but it's just an example to show you how it works right so the basic idea is that you have some sort of abstraction an abstract class in this case a sort strategy that contains the method that represents the particular algorithm that you're using in this case that's a sorting algorithm and that gets data list of integers and then returns a sorted list so this is what the strategy looks like and then we have specific strategies for example we have a bubble sort strategy and we have a quick sort strategy and then in a classic object oriented piece of code you're going to have another class let's call that context that keeps track of a particular strategy and then uses it in some sort of context in this case it does some random things like multiplying elements in a list of data by two adding a random number and then running a particular strategy in this case sorting and then here we're using that context with different strategies so here I'm sorting and manipulating this list using bubble sort and here it uses quick sort so when you run this code then this is what you're going to get and here you see what the strategy allows us to do so we can simply call set strategy a method in context class to change the strategy is going to be used by this piece of code without this piece of code knowing anything about the specific strategy that's being used that's the idea of a strategy pattern very basic now instead of using classes and inheritance like I'm doing here especially in Python makes a lot of sense to just use functions instead and what does that look like well here you see another example the same context so we have a bubble sort function that gets a list of data and returns a sorted list and we also have a quick sort function and what I'm then doing is specifying a type called the sort function which is cable that gets a list and returns a list then instead of a context class I have a context function that gets another function the Sorting function as an argument and then that does exactly the same thing as we had in the original objectoriented version of the code except it's not in a class but it's in a simple function and then I have a main function where I simply call the context function twice and pass it the function that it needs to use for sorting and this gives you exactly the same result well not exactly the same because it's adding random numbers and things like that but uh Works in exactly the same way but the code is way simpler we just have about 50 lines of code whereas in the objectoriented version we have 66 65 lines of code so that makes a big difference in how much code you end up with and that's often what you see when you use functions versus classes is that with functions you typically end up with less code which most cases is a good thing but here you'll see a key technique that I'm using here to achieve this which is that I'm passing a function as an argument mment to another function so that's really One Core technique that's pretty common in functional programming we see it a bit less in objectoriented languages but you can definitely do that in Python and I find this extremely helpful so that's the first technique passing a function to another function and this is just one example of technique that's very handy for you to know because it's not just helpful for writing new code this is also helpful if you're refactoring existing code and in general if want to become better at identifying problems in existing code you might want to check out my code diagnosis Workshop which you can join for free by going to ion. Cod diagnosis this is a workshop that teaches a three Factor framework to help you understand problems in the design of your code faster I'm using existing libraries in that particular Workshop to show you some examples of what I mean you might even use some of these libraries in your own project anyway to check out the workshop just go to iron. go/ diagnosis to join for free the link is also in description of the video so strategy is a pretty basic design pattern so let's take a look at something that's a little bit more elaborate which is the Observer pattern and with the Observer pattern the idea is that you may have objects that change things in your application and they may want to notify other objects of that change so those other objects can then do something but you still want things to be decoupled so you don't want the thing that change ches things to be coupled directly to the things that listen to those changes um examples of where you would apply this is for example let's say you have a system that handles payments and orders and you want to send notifications like uh maybe uh to the user interface so that the user can see hey the payment succeeded or you might want to send an email or an SMS or things like that and that's typically something where the Observer pattern can be very helpful now what does this look like in terms of actual design in the code well we're going to have similar to with the strategy pattern we're going to have an abstract class in this case that's the Observer class I'm using abstract based classes here you can also use protocols and there's going to be an update method so an observer object is going to have an update method so things can update that Observer notify it of updates then we're going to have concrete observers so these are the actual objects that are being updated in this case there's one class concrete Observer you can have many different classes of course as long as they inherit from Observer this one just has a name and then it implements this update method uh simply by printing something it receives a value right then we're going to have a subject which is the thing that's being observed a subject has a list of observers and this is also where you see the decoupling happening because even though subject has a list of observers it doesn't know anything about specific observers doesn't know anything about concrete observers it just knows hey these are observers and the only thing it knows is they have an update method that's how the pattern works and then you have some helper methods to attach an observer and detach an observer and then let's say this is a method to uh notify The Observers of something and that simply walks through the list of observers and calls the update method on each of them and of course you wouldn't use a subject directly like this normally this is going to be part of a bigger piece of code that does something like handling a payment or processing an order or things like that the main function is then also pretty simple we have subject we create an observer we create another Observer we attach those things to the subject and then we call subject notify and then this is what we get so both observers received data again this is a very classic object-oriented approach of dealing with this and this is how it's described in the gang of four book but you don't have to do it this way you can also use functions uh here's an example of what that looks like so instead of having Observer objects we can have Observer functions like update Observer One update Observer two and I'm defining a type here to specify what the interface looks like of these update functions it's simply a function that receives a string and returns n and then I can have a notify function that gets a list of update function so that corresponds to the list of observers that we had here except here we're using classes and here we're simply using functions and then I have a for Loop that calls these functions with this particular data and then in the main function I create a list of functions Observer one Observer two and I call the notify function passing this list and some data this behaves in exactly the same way as the previous version so you see you get exactly the same thing but it's set up with functions you might use some combination of this for example you may have observ functions but that are called from a subject object or The Observers may be objects and the subject part of the pattern might be a function or you might go all in and it's all functions like in this particular example so the technique I use here is very similar to what I did with the strategy pattern so I'm passing an update function to another function but here I'm actually using a data structure a list in combination with the function function so I have a list of functions that I'm passing as an argument so that's another technique that you can use so don't just pass a function you can pass a list of functions but it's of course not limited to just using list I mean you could also have a dictionary that Maps event types to lists of event listeners or you know you can think of lots of complex ways in which data structures and functions are combined so that they do something useful I use this quite a lot actually in my code but the main point that I want to make is that this also shows why I think that design patterns are not obsolete the main thing that's in my opinion happens here is that it's not so important that you're using classes like in this example or that you're using functions right it's more a choice of Technology a choice of programming approach so to speak that you are picking and that might be your preference perhaps you like classes more than functions or the other way around it's so that's all totally fine the thing is that what you're doing with this particular design pattern is that you're detecting a particular class of problems namely I have something that happens in my system and I want to make sure that other parts of my code are aware of that and can handle it without things being horribly coupled and you can use class for that you can use functions for that you can maybe use other things for that sub routines if you're still coding in basic or something it doesn't matter it's about you being able to detect that this is the type of problem that was solved in and same with strategy it doesn't matter if you're using abstract based classes or protocols or functions or whatever it matters that you detect that the problem that you're trying to solve is an algorithm exchange issue we want to be able to exchange one algorithm with something else without affecting the original code too much and that means we need a strategy like pattern so in my opinion what really matters is that you as a developer are able to detect these problem categories and can handle them in your own preferred way whether this is with functions or with classes and in my opinion this is what design patterns are actually about it's about groups of problems and these are not obsolete at all we see them still all the time occurring in code if you want to be a great developer it's really important that you know these problem classes these problem groups because you're going to encounter a lot of them during your career how you implement them exactly functions classes something else doesn't matter so much as long as it gets the job done final pattern that I want to show you is the template method the idea of the template method is that you have a sort of standard operation standard algorithm standard way of doing things but you want to replace parts of that process you can see that right here so we have a template method method template method method and it calls a bunch of operations there's a simple if statement here that does something else um and this is the standard algorithm to do something of course this is kind of meaningless code but it's just to show you how the template method actually works and then in that same class here again I'm using abstract based class to kind of stick to the classic way that design patterns have been conceived there's some operations that already have an implementation for example there base operation one base operation 2 and base operation three then we're going to have a couple of operations that you need to implement in a subass so if you actually want to use this template class you're going to need to implement these two required operations and there are also let's call them hooks which are basically methods that you don't have to override or are default implementations of these things but you can replace them by something else if you want to and then we have a concrete class concrete template that implements the required operation and in this case it also overrides a hook and there's another concrete class that also of course has to implement the required operations and Implement another hook and then in the main function I create a bunch of objects and call the template method on them so when I on this then this is what we get so the first concrete class one if we look at the code you see that it implements hook two and not hook one uh so that means that this if statement condition will be true and will still run base operation three that's also what you see here uh that's being run here and then it calls hook two now the second example of this template method we have a concrete class two implements hook one and returns false and that means that in the template That Base operation three is not being executed and when we look at the output you also see this is indeed what is happening here so this is the idea of template method but again we don't have to use classes and inheritance for this so here's an example where I do exactly the same thing but I'm using functions so I have a template method function right here that has the exact same structure as the template method methods in the previous example but we've set it up using a more functional style of programming so I have my three base operations that are simply defined so in the objectoriented version they were part of this abstract class here they are these three methods and we have a template method function that's the actual template and now of course this has a bunch of arguments because we need to supply it with the required operations and potentially the hooks and that's what you see here and as you can see I've also defined some default values for the hook so they are optional this way you don't have to provide them and then I have some example where I have a couple of operations that I implemented simply print statements doesn't matter and I've also overwritten a hook that returns false similar to this objectoriented example that I just showed you and then in the main function here I'm using the default hooks right I just pass operation one and operation two and then finally I overwrite hook one in this particular example and then we get exactly the same output as we had before in that uh base operation three is run in the first version where uh I don't override the hook and it's not run in the second time I'm calling this template methods so again with functions you can achieve more or less the same thing as with classes but here we use 53 lines of code and here we use uh let me scroll down over 70 lines of code so that's again a big difference in the amount of code you have to write by the way if you like these types of discussions you might also be interested in joining my free Discord server it's a really helpful and awesome Community you can join for free using the link below what you're seeing in the functional version of the template method is that I'm relying a lot on passing functions as arguments to another function so that's basically the same technique as I used for the strategy pattern and the Observer pattern there's one more thing you can do to spice this up by using another technique which is returning a function as a result and that's what I'm doing here in this variety of the template method so what I've done here is I used the same template method function so that's basically this function I had right here but I defined the function in another function called base template method and base template method just gets the required operations and then it defines a function closure template method that has the hooks and then it returns that particular method and nice thing about this is if you look at the main function is what what you can do now is you Define once the template method with the specific operations that is needed and then template method is a function that simply gets two hooks and then you can call it several times here I'm calling it using default Hooks and here I'm overriding hook one so as opposed to the previous version where I had to pass every time I call the method also the operations which you know if you need to call it lots of times then this can become annoying so using the technique of return learning a function as a result which is also something you quite commonly see in functional programming you can add a bit more flexibility to your code although to be honest this does become a bit harder to read but here it's a bit easier to use I'm curious when you write code do you use functions in this way do you pass them as an arguments do you return them as a result do you have any tips suggestions for how to use functions to make your code easier to read let me know in the comments now little B tip you don't have to do it this way you can also do that in this version of the template method but by using something called partial function application and that's something really cool that's from fun tools so I'm going to import partial show you what I mean what partial does is that it constructs a new function it returns a function but it applies already some of the arguments which is exactly what we want to do here so what you can do is um applied template method is partial and then we Supply the template method and we Supply both the operations now we have a new function where these operations are already applied so I can take this method and simply call it like this without the operations and I can do the same thing here so I just remove the operations there we go and now if I run this code we're going to get exactly the same results so you see the first time we're calling base operation 3 and the second time hook one is overridden and base operation 3 is not called so this partial function application basically does the same thing as what we did here with the closure but it's a bit simpler to use so I've showed you three different design patterns as well as functional versions of those design patterns I've also talked about why I think design patterns are not obsolete because in the end it's about the problem classes that they solve they should know about and it's not so much about using a very specific type of inheritance or subroutines or functions ultim Ely those are tools that you as developer are using to achieve the decoupling that's intended with the particular pattern if you enjoyed this video give it a like because that helps YouTube spread the message you might also like this video which is video where I dive deeper into Fun tools and the things that you can do with it because the fun tools package is actually really cool thanks for watching and take care
Original Description
👷 Review code better and faster with my 3-Factor Framework: https://arjan.codes/diagnosis.
In this video, I'll demonstrate that functions don't make design patterns obsolete in Python. There's a lot of talk in the developer community on the topic, and to illustrate my point, I'll look at a few common design patterns and show you an alternative approach using functions.
GitHub repository ➡️ https://git.arjan.codes/2023/funcpatterns.
🎓 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
3:15 Strategy design pattern
8:04 Observer design pattern
15:06 Template Method
21:27 Bonus
22:39 Outro
#arjancodes #softwaredesign #python
DISCLAIMER - The links in this description might be affiliate links. If you purchase a product or service through one of those links, I may receive a small commission. There is no additional charge to you. Thanks for supporting my channel so I can continue to provide you with free content each week!
Watch on YouTube ↗
(saves to browser)
Sign in to unlock AI tutor explanation · ⚡30
Playlist
Uploads from ArjanCodes · ArjanCodes · 0 of 60
← Previous
Next →
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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: API Design
View skill →Related Reads
📰
📰
📰
📰
AI-Powered Change Logs: Automating Client Feedback for Small ArchViz Studios
Dev.to AI
Welcome to Day 6 of 100 Days of GenAI for DevOps!
Medium · DevOps
My AI Workflow for Turning Ideas Into Income (Templates Included)
Medium · AI
I Tested an AI Slop Detector — It Flagged My Own Writing
Dev.to AI
Chapters (6)
Intro
3:15
Strategy design pattern
8:04
Observer design pattern
15:06
Template Method
21:27
Bonus
22:39
Outro
🎓
Tutor Explanation
DeepCamp AI