Main

Observer Pattern Tutorial: I NEVER Knew Events Were THIS Powerful 🚀

This tutorial on the observer pattern is the fourth part of my series on how to write better Python code, I show you how to use events to write code that's really easy to change and extend. Events are a variant of the observer / listener design pattern. This video is inspired by a real-life example I recently encountered, where implementing an event-based approach provided a great solution to a design problem I had. Next to showing how to use events in your code, you'll also see what the effect is on the cohesion and coupling of the functions you write. All parts in this series: Part 1: Cohesion and coupling - https://youtu.be/eiDyK_ofPPM Part 2: Dependency inversion - https://youtu.be/Kv5jhbSkqLE Part 3: The strategy pattern - https://youtu.be/WQ8bNdxREHU Part 4: The observer pattern - https://youtu.be/oNalXg67XEE Part 5: Unit testing and code coverage - https://youtu.be/jmP3fp_BhmE Part 6: Template method and bridge - https://youtu.be/t0mCrXHsLbI Part 7: Exception handling - https://youtu.be/ZsvftkbbrR0 Part 7b: Monadic error handling - https://youtu.be/J-HWmoTKhC8 Part 8: Software architecture - https://youtu.be/ihtIcGkTFBU Part 9: SOLID principles - https://youtu.be/pTB30aXS77U Part 10: Object creation patterns - https://youtu.be/Rm4JP7JfsKY 💡Here's my FREE 7-step guide to help you consistently design great software: https://arjancodes.com/designguide. Relevant books: - Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides: https://amzn.to/3jllgyH - Principles of Package Design: Creating Reusable Software Components by Matthias Noback: https://amzn.to/2NETK3l - Clean Code: A Handbook of Agile Software Craftsmanship by Robert Martin: https://amzn.to/3qVZgNs - The original Design Principles and Design Patterns article by Robert Martin: https://fi.ort.edu.uy/innovaportal/file/2032/1/design_principles.pdf 🎓 Courses: The Software Designer Mindset: https://www.arjancodes.com/mindset The Software Designer Mindset Team Packages: https://www.arjancodes.com/sas The Software Architect Mindset: Pre-register now! https://www.arjancodes.com/architect Next Level Python: Become a Python Expert: https://www.arjancodes.com/next-level-python The 30-Day Design Challenge: https://www.arjancodes.com/30ddc 🛒 GEAR & RECOMMENDED BOOKS: https://kit.co/arjancodes. You can find the code I worked on in this episode in my GitHub repository: https://github.com/arjancodes/betterpython 🔖 Chapters: 0:00 Intro 1:24 Explaining the code example 3:16 Analysis 4:45 Creating a simple event handler 7:19 Moving to an event-based approach 10:40 The complete solution 12:44 The power of an event-based system 14:12 Final thoughts 👍 If you enjoyed this content, give this video a like. If you want to watch more of my upcoming videos, consider subscribing to my channel! 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!

ArjanCodes

3 years ago

in this video i'm going to show you how to use  the observer pattern to create better separation between various modules in your code this pattern  allows you to do some really cool things i'm going to show you an example the observer pattern  also called the listener sometimes is actually a classic from the gang of four book on design  patterns here's a class diagram the important thing to note is that there are two roles the  subject and the observer the subject does things and changes things
and notifies observers of any  changes that happened there's several variations of this pattern in this video i'm actually  not going to implement exactly the classical object-oriented version of it but you commonly  see it in event management systems and this is also the way that most developers use this pattern  handle user interface or general system events this is a pity because the pattern can be very  powerful and work for you and i'm going to show you how to use that to your advantage in
a real  world example suppose you write a back-end api and you work on a register user function next to  the database operations this function also sends a message to slack to the sales team it sends  a welcome email to the user and it writes a log to a server somewhere now it's possible that you  write a function that looks something like this that's not good let's write something better let's first go over the structure of this example  the example is a little bit more involved than the previo
us ones because i wanted to show something  that kind of approaches the situation like you would encounter in real life the example that  i have here imports a few functions from an api folder and it does a few things it registers  a user it sends a password reset message and upgrades the plan of the user now normally these  things would be api calls i just put them right here in the code just for testing purposes if you  look at the api folder we have a user file and a plan found these actually
contain the methods that  i was calling just there so in user for example we have to register new user which takes a name  password and email address and we have a password forgotten function that takes an email address so  if you look at the body there's one part which is the actual job that it needs to do like creating a  user and then it posts a few messages like here it posts a slack message so the sales department  can spam the person it sends a welcome mail it writes something to the serv
er log etc etc and  these things are all imported from a lib folder at the moment this doesn't really do anything  like for example this send email message doesn't actually send an email but it simply prints the  message to the console similar for log and for slack in a real application obviously this would  be integrated with the actual services that you'd be using the database is the most complicated of  all these things in the sense that it's also not a real database but it creates an array o
f users it  has a class user that has name password email and a few other things and then it has a few functions  so you can create a user and you can find the user so these are things that you'd normally have  in a database driver but here in this example obviously we're just doing that locally now the  problem with this code is that if you look at for example register new user you see it's doing a lot  of different things it's overall a method that has pretty weak cohesion not only does it nee
d to know  about database stuff it also needs to know about slack email logs etc now because register new user  needs to know about all these particular functions it means you also have a lot of different imports  here and similar for password forgotten so it also does the actual job it needs to do which is find  the user and generate a password reset code and then it sends a message it writes something to the  server etc etc and for the part of the application dealing with upgrading the user's
plan it actually  looks pretty similar part of this job is doing the changes in the database which is finding the user  and then upgrading the plan in the database but then it also posts a slack message sends an email  writes something to the log and you see also here there's a lot of different imports that means that  upgrade plan just like register new user also has pretty weak cohesion and is directly coupled  with all these very particular implementations so that sounds very nice and we want
to change  that and this is where the observer pattern or specifically an event system can really help you  separate these things so let's try to rewrite this application so that it uses events instead of  these direct couplings between the code and the messaging python has several event libraries  but just to show how it works i'm going to write my own it's it's actually pretty simple  so let's add an event file here event dot pi and basically the event system is very simple  you have a number
of subscribers that subscribe to different types of events and whenever you  post an event you need to notify the subscribers so let's create first a dictionary containing  the subscribers now we have a dictionary and then each item in the dictionary is going  to be for that particular type of event the list of subscribers that need to  be notified when that event happens so let's add a subscribe  method that does that for us so we're giving it an event type which is  basically just a string an
d a function that needs to be called i'm not going to use  type hints here for the function because frankly in python type hints for functions are  a complete mess the only thing we have to do when we subscribe to a particular event type  is first check that there is already a list of that event type in the dictionary if not we  need to create one and then add it to the list so if not already in the  subscriber list then let's create a list of subscribers for this particular event and we're dire
ctly appending the  function that needs to be called to the subscriber list now again there are already  event library so probably you won't have to write this yourself i'm just adding it so it shows  you how the pattern actually works and then next to subscribing we also need to be able to post  events so let's add a function for that as well and normally when you post an event you  generally want to pass along some data with it so if there are no subscribers if the  event type doesn't exist in
dictionary subscribers then we don't have to do anything otherwise we're going to  go over the entire list of subscriber functions and call each  of those functions with the data so there you have it this is actually a complete  well almost complete event system and this actually works just fine so now what we can do  we can go back to for example the user functions like registering new user and then replace all  this stuff with simply a posting an event goal and as the data i'm going to pass 
along the user and same thing here then of course i also need to up update my imports  and now i can remove parts of the imports that are no longer needed here and i forgot to  add the user there so much shorter this way and now what i can do is that i can kind  of group these different event handlers together in the way that makes sense so for  example i could add here a slack event handler so create a file slack listener  then what i'm going to do is import this post slack message that  i'm ma
inly going to use to do that and of course i need the event library and then first thing is let's add a function that handles a user registered event and there  we're going to put the slack message to sales and of course don't forget to spam this  person there you go so there we have our handle user registered event now i've got  an import here and i'm also going to add a function that sets up the event  handling system for slack messages and it's going to call the subscribe method  that subscri
bes us to a particular type of event and then user registered event should be  mapped to the handle user register event function and now i can add more functions here  like when the user upgrades the plan etc etc now in a similar way i can do that for for example  the system logs so add the log listener file i'll just copy this over because i  need to do a lot of things the same and now i'm not posting a slack message  but i'm sending a system log event and i can do the same let's say i want  to
have a password forgotten event like this and they add a  subscribe method goal here so i created these two collections of  listeners and in the observer i then should import those and call this function so  that the event system is set up correctly so i'm not going to show how this works for  all the functions and all the methods in this particular example but i made a kind of complete  version of this example where i rewrote this api so that it now uses this event system that's also  in the s
ame repository so if you check it out on github you can look at it and play with it  yourself so you see we have here this event system that i just added and we have a log listener with  a couple of different event handlers and we have slack listener that looks the same and we have  an email listener that actually sends the emails and the user and plan api access points now simply  post an event instead of using directly sending emails posting logs or posting slack messages and  something really
interesting happened here if you look at the way that it's now structured and the  way that the imports are organized is that here you see that the only dependency is on the event  system there's no longer any dependency on the type of specific type of message or specific  type of things you want to do depending on the event that occurs and the same is for the plan  so there is there's just the database stuff and the event stuff that's it and the methods are also  becoming much shorter so we ju
st have the database operation and then we post the event if you look  at the listeners themselves you also see that the number of imports is actually pretty low  it just imports event stuff that it needs and since this is a slack listener it  needs the post slack message import and the same for the log and for the email so  using the event system in this way has allowed us to really separate the code much better if you  look at what we do in the actual test program so we're simply initializing
the event structure  by calling up these event handler setup functions and then when i run this you see that it generates  a bunch of emails slack messages log messages etc when i call these functions here and now it's  really nice that not only are the imports much better structure that has less coupling because of  that some things are now much easier to change so for example if i want to temporarily disable slack  messaging i could simply put this into comments and if i run the code again the
re are no more  slack messages i didn't have to change anything in my actual api functions because these simply  post an event and don't know anything about what happens after that now similarly if let's say i  wanted to change from slack to a different message provider like microsoft teams or whatever you use  in your company then also that would be a pretty easy change i would simply disable this and then  add a new listener for my new messaging service and enable event handling and i'm basica
lly done i  don't need to change anything else in the code in the previous version i would have to sift through  each of the functions in my back-end servers and change the slack specific part to a teams specific  part so there you see a very clear example of how reducing coupling helps you write code that's much  easier to change later on and this event mechanism i said before it's really really useful for these  kind of things and a lot of people only use events for ui stuff like handling a bu
tton click or  stuff like that but just keep in mind that if you encounter this kind of structure or this kind  of thing in your code that events can really help to clean it up you know on this channel i like  to talk a lot about writing code and designing software i don't like to just provide recipes like  how to do x but i'd like to think a bit more about why we're doing things the way that we do  them i've been teaching computer science for over 20 years and i've started several  software bus
inesses and simply following recipes never really led to good results for me i  really needed the understanding that's behind it on the other hand there are lots of tutorials out  there about design patterns and design principles but often the examples are not very practical  what i discussed today was a solution to a problem that i literally had a few weeks ago i hope this  video helps you think differently about how you write code let me know in the comments below what  your thoughts are about
this you can find a link to github repository containing the code that i  worked on in this video in description below if you're enjoying this series consider subscribing  thanks for watching take care and see you soon you

Comments

@ArjanCodes

Event systems are a good example of a design that results in code with low coupling and strong cohesion. This video delves into coupling and cohesion in more detail: https://youtu.be/eiDyK_ofPPM.

@MatheusAugustodaSilva

I love the sense of humour all over the place. Your tutorials are the first ones that actually managed to get me interested in design patterns. Please never stop making videos!

@RoamingAdhocrat

Arjan: "I'm going to show you how to use the Observer pattern…" Me: <watches>

@willemvdk4886

These kinds of tutorials are incredibly refreshing! Thanks, Arjan! Most programming tutorials are about either learning a language, a framework or building some kind of bogus app. These topics are usefull of course, but at a point they will either be too basic or too specific. Your video's are both advanced/expert level AND generic enough to be interesting/educational for a lot of programmers. Kudo's, vriend!

@fat_pigeon

Clear and useful explanation! Using an observer can be extended to abstract over the event transport. Then you can do things like retry failures or even plug in a distributed pub/sub system. Constructive feedback: I would like if you spent a little time to also cover limitations/drawbacks of the pattern you're discussing in each video, and the circumstances when it would be inappropriate or overkill. Design patterns are tools for architecting software, and it's important to know when each tool is the best for the job, and also when one should look for a different tool.

@TheWarmestWaffle

Arjan if you keep up these videos, this channel is going to explode. As an amateur python user who has gone through some Kaggle courses, freeCodeCamp courses, and primarily written code as a hobby and as a necessity when needs have arisen, these videos are phenomenal and engaging content. I took the time to like and comment, and am subscribing and look forward to future content!

@rishanriyal

Never commented on a Programming video before, the way u presented the whole idea made me to comment on. Kudos, and keep up the good work.

@bilbo1337

Just want to complement the production quality of this tutorial, both the editing and content are great!

@jeanhadrien

This is insane quality content, keep it up !

@CodingEntrepreneurs

Great video! Keep up the great work. Looking forward to watching more.

@Omnifarious0

I would not have decoupled logging in that way. That feels integral to what the function is supposed to do. And I like logs to be very obviously and simply related to code that's doing the logging. But yes, this pattern is powerful and useful, and the example you chose was (aside from the logging bit) compelling.

@grantwilliams630

This is my favorite pattern. Event-based programming works amazingly well with micro services and allows you to super easily scale asymmetrically i.e. the ML portion of your architecture vs the I/O portion.

@eatcheese5486

Great overview! There are tons of use-cases for this, I'm glad to have now seen a concrete example of how to use it. And fun fact, this would have helped me in an interview with Amazon about a year ago!

@lordGaruda

Your attention to details, all the way down to the volume of the background music, is immaculate.

@thatguy6664

Thank you. I'm looking forward to the rest of the series. This type of content is rare, much needed and much appreciated!

@richardbrown1300

I love that you showed the UML and explained the concept really well before hand. Event handlers are used in so many places but it is not always clear what is going on when you look at existing usages.

@JohnMauneyIV

I really appreciate that you built the event system to show its internal workings instead of using an existing library, thanks!

@SuperSlugger94

These videos provide so much help for me! As you said, there are a lot of tutorials out there on design pattern recepies but no one really explains when it might be a good idea to use them and their advantages when it comes to get a better cohesion and decoupling your code. This channel is a real treasure trove! Cheers from Sweden

@guillermokeller1985

This channel became my favorite python channel. Thanks for your work, I'm learning a lot!!!!

@orie239

Is it a coincidence that I started reading the same book about Design Patterns and I suddenly come across your channel? Brilliant.