I've worked in crazy spaghetti codebases, and architecture astronaut code mazes. After those experiences, I love this practical, real-world advice. Thank you.
Really nice video, thanks a lot! Got a project at work with a lot of inherent complexity about a year back and would be completely lost without all the stuff I learned from your videos. The great thing is that every time I watch a new video I get new ideas on how to improve things!
I moved from C++ to Java in 96. OO was the bible. Things changed when Dungeon Siege released and ECS came to the forefront in my world. Had to go back to OO when DI tools like Hibernate and Spring became popular. I am retired from software development now and have come to Python late. Love your explanations. Most especially when it comes to inheritance and when to choose 'has a' over 'is a'.
I find that because these OO principles are abstract, they take quite a bit of repeated exposure to "see" in day to day coding. Especially when starting a feature from scratch. Thanks for making such a variety of videos about them (including the course). It's really helped keep the reinforcement learning/repetition fun and interesting.
I've found myself incorporating many of these naturally over time as well. My use of inheritance is still something I should work on - I often just slap it on hastily because its easier (at the time), but it definitely makes for some readability issues down the line. Another fantastic video, thanks!
Inheritance is good if you have some base data that all similar classes should share. I don't believe methods should be inherited. In that case it should be abstract methods which need implementations, but work under the premise that "these are required to work". That is in my opinion the most sane way of using inheritance. At my job, there are some massive inheritance issues, where one class might have three ancestors through inheritance. It's honestly awful, but it's basically something that people who knew how to write code but not structure code made, and now we're suffering from the consequences much later. We're working on modernizing the code base and improving it, but we'll still be left with a lot of legacy code.
Good stuff. Separating data and behavior concerns is forward thinking. Not being worried about strictly adhering to a design paradigm is so refreshing to hear; let's be practical! This is your best video, yet!
The python community has no concept of OOP. Your channel is honestly the first I’ve ever found that actually utilises OOP and is good at it. Keep it up my friend!
I love your style of writing code it makes sense and it's clean and organized. Keep them coming. I am actually trying to adapt my code style to be more like yours as I like it so much.
The best strategy in life, not only in programming, has been expressed once in an interview with Bruce Lee. He said one should study martial arts (not just one) and from each of them take what works for one. Take it and from then on develop it. This is by far the best advice one can give in any walk of life: Take the best out of it and develop from now on. Therefore mixing different styles of programming should be standard, not something frowned upon. After all, a hammer is not the answer to all questions, so to speak.
the understanding of separating the data classes and the behavioral classes in such a clear way is really amazing and an awesome idea which I will most certainly implement and take into consideration with every OOP step I take. thank you so much!
Thanks, I used the dictionary as a collection of functions/objects a lot but until this video, I did not realize that enums as keys can work really nice.
code MUST be readable by humans first, has been my motto for years. And what you're saying is along those lines. The more I watch of your videos ,the more I like. I'm trying to "bing" watch your videos but my head feels like it may explode. 🙂 Keep up the good work.
This is seriously thoughtful stuff, I especially loved the part about not being locked into an OOP or functional style. It's always better to use the right tool for the job. What I didn't agree with as much was about classes being data or behavioral orientated. I always thought it was the other way around - that classes make more sense when you have data and behavior that are tightly coupled (say, a 2 year old dog playing fetch.) What do you think?
Yeah, I agree with that. One of the main purposes of creating a class is being able to share the same common data across a lot of different methods. Splitting behaviour and data its kinda pointless for me
I'd say splitting data and behavior is useful in some circumstances. It can be a lot easier to have a class which manages such objects instead of the objects themselves doing all of the work. I'd say one of the primary reasons why you'd want to have methods in a data class is when it has data you don't want to expose publically. In which case I'd prefer if that method had an accompanying interface.
Oh this was the catalyst, it finally clicked. Thank you for such curated, intentional explanations. I aspire to be as engaging and well-informed one day.
I did all your tips in my last refactoring and it's working wonders 😂 A sane combination of functional and oop is actually great for writing well-structured code without crazy side-effects! 😄 One thing about turning behavior-oriented classes into raw functions: If you wanna do dependency injection and duck typing via protocols, it's really essential to represent your set of functions as a class because it's way more cohesive than passing each function separately (really helps readabity). And moreover something like attributes is necessary to store the handle to each dependency instance. But for the rest of the video, I totally agree 😁
I implemented this payment processor class behaviour in production recently and it was from this particular video i learnt about ABCs and Protocol. Thank you so much for the knowledge you share
I wish some of the library writers would watch your videos. I have run across libraries that try to be a complete application and have such convoluted object structures that I sometimes end up writing my own library. Yuk! Keep up the great work.
Great video Arjan thanks! I really appreciate your insights and the quality of your videos. I'm a developer with 20+ years of xp and I'll work with python for the first time soon and your videos are helping a lot on my preparation to be more pythonic.
You have the best videos on python and coding on youtube. You put in a lot of work into your videos and they are to the point and amazing every time. Thank you!!!
I can't believe your channel hit 100K+ subs. I have learned a lot from you Arjan, thanks for all the quality videos (and free knowledge). You deserve more.
this is quality content for senior devs; you're talking about abstract topics that matters on the big picture/decision making of big projects; I loved it, subscribed!
About inheritance: One more usage of it is for making C/C++ classes integrate better in a Python program. Depending on how the C/C++ side is implemented, inheriting from these, or creating a class to wrap around them, might actually benefit the simplicity and readability of your code.
Data classes have brought way more OOP to my code. A series of transformations on an object with predefined values is way easier to track compared to a dictionary
I can see how Java gets a lot of heat for how things are done. When I started studying computer science in 1999, no surprise, Java was all the rage. Fortunately I had worked with Delphi before (a natural step up from my Turbo Pascal days in DOS), so I was able to tell apart what disadvantages are specific to Java and what to OOP in general. I have moved away to mostly working in C nowadays since I work as an embedded developer (never done C++), but I use Python for tools that make my life easier. That's why I watch your videos. When appropriate, I sometimes follow a semi-OOP approach in C, where I define a struct holding all data of that "object" and pass this (well, a pointer to it) to various functions that work on this data, much like the self parameter in an object's method in Python. I even call the parameter "self" most of the time. 😅
This is a really good video. Only thing I'd say I disagreed with is separating classes by data vs behavior. In theory this sounds nice, but when I get into a larger project I almost always need some of my data focused classes to be able to do some various behaviors. I think separating those out too much from each other could pose other problems. All about balance though
Its better to consider OOP exactly bad exactly per sé, just to oppose inertia. Only when all developers will agree its not THE way of structuring code, we can talk how it can not suck.
This guy does create a lot of object oriented code, sometimes importing a couple of functions in a python script is all you need
2 ปีที่แล้ว
I'm kinda new to python, and tbh I see a lot of code that people say it's "more pythonic" that for me is just more complicated to read. I've seen some list comprehensions that look like RegEx and took me a second to understand. And a lot of what you talked here reminded me of how Django works, using classes (models) for data and mixing it with functional programming for views (even though you can use classes for views also).
Awesome, as usual. In my opinion the audio quality changed with respect to previous videos (and it was not an improving for me; previous ones were better).
Consistently good videos covering topics in a sensical way with examples reasonable enough to be relatable but not overly complex for explaining the subject matter. Great job. Would love to see you make some more "difficult" testing-related videos dealing with concepts like async sqlalchemy sessions and the many other difficulties that arise with testing asynchronous code. It's one of the areas where I feel least confident and most "Google a lot of stuff until things begin working" and I'd like to get away from that feeling, but it seems resources surrounding these topics aren't great currently.
Functional programming in not about using functions, it's more about stateless, function composition, memorizing, recursion and closures =) FP not easy to read and python is not great for FP. This video in more about procedure programming. When choosing between classes and functions keep in mind that under the hood python functions are just class instances with only (practically) call method :) I don't think it's a great idea to convert methods to functions, it could work, but you loosing internal state of class. And if your functions changes your classes state, or you have some global states - that's not FP at all =)
I wouldn't call data classes OOP and I wouldn't call any functions FP. Functional programming would be more about not mutating data class objects, not avoiding the usage of them. Functional programming would be writing functions that promise not to mutate their inputs if passed by reference, and don't have side effects that get consumed by external logic. I'm not advocating for a certain style, just want to make it clear that class != OOP and function != FP, the styles are more about the constraints you put on yourself and the patterns that emerge from doing so. They are not about using or not using certain constructs, though certain styles do tend to lean more heavily on certain constructs like a preference for tuples over lists (to give a Python example) in FP because they enforce certain principles.
No, he used a function, therefore its functional programming. /s This has been the play of OOP for years. OOP used to be about so many things(encapsulation, inheritance, etc.). But now that all of those things have been shown to be terrible, its now just 'using classes/objects'.
@@Mr7Shane In my personal humble and very inexperienced opinion, Classes are the best single thing that allows you to store complex hierarchical data. Because you can have a very clear and defined level of control of what is stored in the class. And you can have the information you need not just as primitive types but as custom objects that enforce certain things about the data that simplifies managing them later. However behaviour oriented classes are so cumbersome and often feel unnecessary when you don't have variations of the methods (writing unnecessary preambles to each functions and such). So unless you need to define custom behaviour for each different object I would avoid classes all together in favour of funcions. Whst I like about Python is that it allows the user to do multiple paradigms without too much effort. Exploiting the advantages of different approaches and such
How do you feel about Dependency Injection increasing the number of inputs? On Clean Code it is mentioned that we should minimize params because we are just creating complexity by having to test multiple inputs generating multiple outputs. Wdyt?
Great video! I'm not exactly sure what you meant by an abstract base class you use for inheritance, but I like to use certain modules, from pypi or from Python to manipulate those objects and localize my own objects. For example, creating a Paddle Class in a pong game that inherits from Python's Turtle. This way all of the code for those objects is in one class instead of riddled around the code. Inherit a turtle from Turtle and create your own custom turtles sort of thing. But maybe you said that in your video talking about inheriting from the Charge Class. I really like the idea of separating behavior from data in more complex programs. I like to see similar code in the same spots.
The beard is growing. Arjan slowly turns into our spirital leader. Leading us through the deadly valley that snakes itself across the land of Guidotopia.
My opinion's become that OOP isn't bad, there's just a lot of bad OOP code out there. A lot of the principles of OOP are sound, but they fall apart when you mindlessly apply them, and the same is true for FP. Someone who writes an AbstractSingletonFactoryFactory would also write some pretty heinous functional code, because the problem isn't the paradigm, but the person who applies the paradigm without thinking about their design first.
Lovely video! Could you do a video on Method Chaining? I've been told that it is not considered very pythonic. I've never found any good explanations as to why, though. It obviously works, and it is in plenty of libraries, so.. is it bad? Personally, I love it.
What I tend to do is when functional programming makes more sense I put all the functions into a class that kindof describes what the group of functions does and make them all static methods or class methods
wow I loved every bit of this videofrom the introduction to the end, as a self taught software developer in the making vidoes like this helps a lot, I did not only like but i subscibed.Thank you
Arjan, I'd love to hear your feedback about a principle that I've used: That is, don't make a class unless you're going to need multiple instances of that class. I can think of one exception--a dataclass which has lots of instance variables. Otherwise, it seems like just using functions would be simpler. What to you tihnk? P.S. I love your videos. Your explanations are very clear and well thought out. Thanks!!
Thank you for another interesting video. It think is filmed really nice also. Visually pleasing, calm, colourful and still focussed on the code. Thanks again :)
I would add: Use immutable data structures where-ever possible. e.g. dataclass(frozen=True) or tuple[Thing, ...] instead of list[Thing]. Do, if possible, not use a lot of getter/setter methods, but prefer to create new instances with the altered attributes. Immutability, delegation instead of inheritance, functional methods (no side-effects), and classmethod-factories that make the code easy to read and understand. Changeable class attributes are particularly a pain to test, because the control paths quickly factorize and become insurmountable.
Separating classes to either mostly contain data but little behaviour (like structs) or to contain behaviour but little data (like functions), but preferably not both; and try not to use inheritance. Those must be some of the most unOOPish OOP-tips I have ever heard... 😃
Thank You, From the Functools to DataClassess and now blending (F and OOP). I feel this could have been your 7 steps pdf for download, lol I had a question about assigning a index in lieu of self generated indexing. There are (Cluster, Multilevel, Sparse, Hash etc.) I have a establisd mathematical function I would like to use to assign a index to the database instead of building out table relationships. I believe your depth of understanding of how to remain scalable and dynamic in your approach to coding gives me a bit of confidence that I can do something along these lines. Thank you for your valued insight in this field. My question is how can we have a discussion ? My bread just came out of the toaster, and butter must be applied for the best Bread in the WORLD, lol P.S. also my thumbs are cramping from this texting. I need to use VOIP more often.
With all due respect, the first example is not a combination of FP and OOP. Here's an exemplification: "2" is an object in Python, and print() is a function. But when we write "print(2 + 2)" we don't "combine FP and OOP". It is just old good imperative code. When we put imperative code into a function, we don't do "functional programming" just because of that. Functional programming is a quite special thing: it's a programming via function composition. Likewise, when we put our code into a method, this doesn't make our code object-oriented. OOP assumes certain specific principles (encapsulation, inheritance, polymorphism), without them it's all just using classes as C-like data structures.
What really distinguishes OOP versus functional programming is that the former makes use of objects with *mutable* state, whereas in FP we make use of pure functions without side effects ie we avoid mutable state. Just because it has the keyword "class" in it doesn't mean it's OOP! Data classes are often used a bit like tuples, but with named slots, and you can make them(almost) immutable using frozen=True argument. When used like this they are a bit like Scala's case classes, which are used in FP. When you pass immutable data classs into pure functions, this is absolutely FP, and *nothing* to do with OO.
Would have been nice to also mention the terms "pure core" and "side effects". Especially the way the code should be organised. Haskel is probably one of the best examples. It allows I/O operations only in the "main" context. Hence all that unpredictability that I/O has is located in a "thin top layer" (easier to debug). The core must be immutable - the input gets transformed and returned at the output without any side effects. Same input generates same output no matter how many times that function is called. For dynamic programming languages there is also the PFAAO design pattern which is quite helpful. Writing tests for "pure" code is always a joy because it is really straight forward. Personally, I'm coming from more of a RoR background. Wouldn't say that Python is that great with FP. I think that Ruby does a much better job at FP but it has its own downsides (i.e: there are no native immutable data structures). After learning a bit of Scala, I was able to understand that 95% of the Ruby projects I've ever seen were done in a classical imperative way that mixes the stateful with the stateless and then gets really messy over time. PS: FP is a style. Can be very well achieved in any OOP language if FP principles are well understood and followed (ofc if we ignore the type system altogether which to me is probably Scala's best selling point).
1. 7:07 you mention PaymentProcessor could be a module. When would you write a class as a module? Would the api_key then be a module scoped global variable? 2. 12:00 sounds like a reason to do dependency injection is so it's easier to test, are there other reasons? 3. It looks like we are polluting the function argument list when dependency injection pulls things from within order_food into it's argument list. What if we wanted to test more items, the argument list is going to grow to contain other business entities, as many as we want to test.
Great video, I am not sure if what you call Dependency Injection is not just "composition", I think of DI as a more implicit/automated process, just like Pytest does with fixtures and FastAPI does with depends
@dataclasses are not OOP in my opinion, it is an implementation of Product Types/records. A behavior focus class isn't much of a class either, it would be better described as a module. OOP starts with inheritance, IMHO.
Arjan, I love all your videos. You are a great teacher. I know it's not the focus of your video, but can you tell us how you have your line numbering setup in VSCode?
Love this video and all the videos on your channel. Super helpful❗️😃 I would love to see an equivalent video on # Tips for Functional Programming in Python 👍😃
The point of classes is to group up related behavior and data together. If you create a class just to store data, there are dictionaries for that. If you want to group up functions, that's why we have imports and functions in single files.
@@clauseclause6640 you can, but is messy. As @Jorge Escobar said, it is more clear tu know that a python class is delivering - processing data, rather than only declaring data. I have seen a lot of programmers using Enum for this. As I said, so messy. Just persist your data in a db or create readable key value file, that later on, can easily be migrated to a db. Easier and good practice -> global or local constants.
Accessing data as object's property is less error-prone than a dict's key. When u refactor the property name, IDEs support that in a click, doing that for key string is quickly becoming a mess. You cannot also hint the data type in case of dictionary.
@@TrungNguyen-mj2idThat's not necessarily true. You can use type hinting in the dictionary definition to get auto completion. e.g. my_dict: dict[str, dict[str, MyObject]] = {'foo': {'bar': }} Would allow you to get completion on a call like: attribute = my_dict['foo']['bar'] attribute.method() As for maintainability you're right, using string keys in a dictionary is really only useful if you're driving those indexes programatically to read a data stream that's given to you that way. Or if you have to say pair up arbitrary keys with values (like writing code that processes ang given datatable agnostic of headers/row names). When you're building a data structure in code though, it's good practice to start with a dictionary and if you start running into overuse of magic string keys then migrate that structure into a more maintainable/documentable structure like a data class. And python classes should primarily be used as a way to re-use functions and prevent pollution of the root level namespace with generic function names For a really simple and dumb example: instead of 2 functions like get_number_as_float and get_number_as_int, youd have a Number class that has two subclasses called FloatNumber and IntNumber then call FloatNumber.get_number or IntNumber.get_number. Being able to link data and functions is also a good way to make sure that users are feeding the correct data types to the class methods. If the object initialization fails (putting type checks in the __init__()) then you can immediately raise an error instead of letting them continue to misuse functions or hope they have their data formatted properly.
I enjoyed your video. In your tip #2, it would be useful to add an explicit "Why you create separate data and behaviour classes". It sounds like you are transitioning to FP when you say that often the behaviour classes could be replaced by a module of functions. Are you trying out any pure -FP languages?
I'm not sure about the section where seperate method and data-classes are promoted. As allready said in video, if you use data this should be in same class. As long as it is not about GUI programming nearly all of my functions process a bunch of data. Therefore I often have classes with data and functions/methods. I don't see anything bad about this. Regarding the question if I would also put functions in my code (mix FP and OOP): Yes, but I would only write functions if it don't use class data, I don't want to store results and I do this only in one instance. Regarding the credit-card programming example: If I write code for a singe payment machine, I would stick to a function for this check-card-method, but if I programm a payment system with many payment machines, I would prefer to store the card-data in the same class and maybe also stroe the result of the check in this class to not call this too often.... so I would put it in a class.
Awesome tips man. For me coming from non object oriented background I have always used a functional and object oriented mix. It just feels easier for some reason.
One thing I don't understand is why you see so rarely these tips applied, even in the python standard libary. One recent exemple is the pathlib library. It does everything you advise against like multiple inherentences and even the use of the fency __new__ to create an os dependant path instance. So is it worth using this style of coding when not many people seem to use it ?
I noticed you sometimes use the UML class diagrams to explain some OOP patterns (e.g. adapter pattern). I would love, if you would explain how to read those diagrams on some examples. I can't follow them in other videos.
Can someone elaborate on separation of behaviour and data? I sort of see some places where that could useful, but that's not everywhere or maybe I just lack experience to notice. I think it is a design decision important enough to have a separate video dedicated to it.
💡 Get my FREE 7-step guide to help you consistently design great software: arjancodes.com/designguide.
Mid level engineer here. Binge watching your videos like its netflix. Hands down some of the best programming content on youtube. Thank you!
Glad you like them!
This is a great topic! I'd like more like this, a general list of hard-earned tips that have marinated in an experts mind for a long time
I've worked in crazy spaghetti codebases, and architecture astronaut code mazes. After those experiences, I love this practical, real-world advice. Thank you.
You're welcome - glad you liked the video!
Love ur tips. The helped me a lot. Please make a full course for us
Thanks Augustus! There actually is a full course: www.arjancodes.com/mindset ;).
Really nice video, thanks a lot!
Got a project at work with a lot of inherent complexity about a year back and would be completely lost without all the stuff I learned from your videos. The great thing is that every time I watch a new video I get new ideas on how to improve things!
I moved from C++ to Java in 96. OO was the bible. Things changed when Dungeon Siege released and ECS came to the forefront in my world. Had to go back to OO when DI tools like Hibernate and Spring became popular. I am retired from software development now and have come to Python late. Love your explanations. Most especially when it comes to inheritance and when to choose 'has a' over 'is a'.
I find that because these OO principles are abstract, they take quite a bit of repeated exposure to "see" in day to day coding. Especially when starting a feature from scratch. Thanks for making such a variety of videos about them (including the course). It's really helped keep the reinforcement learning/repetition fun and interesting.
as someone who uses python for over 2 years now . This is a huge added value for a 16 mins video.
I've found myself incorporating many of these naturally over time as well.
My use of inheritance is still something I should work on - I often just slap it on hastily because its easier (at the time), but it definitely makes for some readability issues down the line.
Another fantastic video, thanks!
Inheritance is good if you have some base data that all similar classes should share. I don't believe methods should be inherited. In that case it should be abstract methods which need implementations, but work under the premise that "these are required to work". That is in my opinion the most sane way of using inheritance.
At my job, there are some massive inheritance issues, where one class might have three ancestors through inheritance. It's honestly awful, but it's basically something that people who knew how to write code but not structure code made, and now we're suffering from the consequences much later. We're working on modernizing the code base and improving it, but we'll still be left with a lot of legacy code.
Good stuff. Separating data and behavior concerns is forward thinking. Not being worried about strictly adhering to a design paradigm is so refreshing to hear; let's be practical! This is your best video, yet!
The python community has no concept of OOP. Your channel is honestly the first I’ve ever found that actually utilises OOP and is good at it. Keep it up my friend!
I love your style of writing code it makes sense and it's clean and organized. Keep them coming. I am actually trying to adapt my code style to be more like yours as I like it so much.
The best strategy in life, not only in programming, has been expressed once in an interview with Bruce Lee. He said one should study martial arts (not just one) and from each of them take what works for one. Take it and from then on develop it. This is by far the best advice one can give in any walk of life: Take the best out of it and develop from now on. Therefore mixing different styles of programming should be standard, not something frowned upon. After all, a hammer is not the answer to all questions, so to speak.
the understanding of separating the data classes and the behavioral classes in such a clear way is really amazing and an awesome idea which I will most certainly implement and take into consideration with every OOP step I take. thank you so much!
One of the best videos I've ever seen on OOP, so simple but with all the necessary insight for future development!!!!
Thanks, I used the dictionary as a collection of functions/objects a lot but until this video, I did not realize that enums as keys can work really nice.
code MUST be readable by humans first, has been my motto for years. And what you're saying is along those lines. The more I watch of your videos ,the more I like. I'm trying to "bing" watch your videos but my head feels like it may explode. 🙂 Keep up the good work.
This is seriously thoughtful stuff, I especially loved the part about not being locked into an OOP or functional style. It's always better to use the right tool for the job.
What I didn't agree with as much was about classes being data or behavioral orientated. I always thought it was the other way around - that classes make more sense when you have data and behavior that are tightly coupled (say, a 2 year old dog playing fetch.) What do you think?
Yeah, I agree with that. One of the main purposes of creating a class is being able to share the same common data across a lot of different methods. Splitting behaviour and data its kinda pointless for me
I'd say splitting data and behavior is useful in some circumstances. It can be a lot easier to have a class which manages such objects instead of the objects themselves doing all of the work. I'd say one of the primary reasons why you'd want to have methods in a data class is when it has data you don't want to expose publically. In which case I'd prefer if that method had an accompanying interface.
Oh this was the catalyst, it finally clicked. Thank you for such curated, intentional explanations. I aspire to be as engaging and well-informed one day.
I did all your tips in my last refactoring and it's working wonders 😂 A sane combination of functional and oop is actually great for writing well-structured code without crazy side-effects! 😄
One thing about turning behavior-oriented classes into raw functions: If you wanna do dependency injection and duck typing via protocols, it's really essential to represent your set of functions as a class because it's way more cohesive than passing each function separately (really helps readabity). And moreover something like attributes is necessary to store the handle to each dependency instance. But for the rest of the video, I totally agree 😁
I implemented this payment processor class behaviour in production recently and it was from this particular video i learnt about ABCs and Protocol. Thank you so much for the knowledge you share
I'm making my way to senior and I would dare say you helped me a lot with getting to a whole different level of app design. Thanks
I wish some of the library writers would watch your videos. I have run across libraries that try to be a complete application and have such convoluted object structures that I sometimes end up writing my own library. Yuk! Keep up the great work.
Great video Arjan thanks! I really appreciate your insights and the quality of your videos. I'm a developer with 20+ years of xp and I'll work with python for the first time soon and your videos are helping a lot on my preparation to be more pythonic.
Hi Rodrigo, thank you and glad to hear you enjoy the videos and that they're helpful to you!
As a c# oop dev, i think your points are good and the way I approach engineering with my python.
You have the best videos on python and coding on youtube. You put in a lot of work into your videos and they are to the point and amazing every time. Thank you!!!
Thank you, Nathan! I'm really happy to hear you enjoy the content.
I can't believe your channel hit 100K+ subs. I have learned a lot from you Arjan, thanks for all the quality videos (and free knowledge). You deserve more.
The dependency injection topic was something new to me, so thank you!
You must have access to my yt search history because this is exactly the video I need right now.
Watched this with the team at work today. Good stuff
Thanks, glad you liked it!
Tip #2 is one of the most helpful pieces of advice i've come across. Applying that thinking to my classes has made my projects way more organized.
this is quality content for senior devs; you're talking about abstract topics that matters on the big picture/decision making of big projects; I loved it, subscribed!
Thanks Alberto, and welcome on board 😉.
About inheritance: One more usage of it is for making C/C++ classes integrate better in a Python program. Depending on how the C/C++ side is implemented, inheriting from these, or creating a class to wrap around them, might actually benefit the simplicity and readability of your code.
Data classes have brought way more OOP to my code. A series of transformations on an object with predefined values is way easier to track compared to a dictionary
I can see how Java gets a lot of heat for how things are done. When I started studying computer science in 1999, no surprise, Java was all the rage. Fortunately I had worked with Delphi before (a natural step up from my Turbo Pascal days in DOS), so I was able to tell apart what disadvantages are specific to Java and what to OOP in general.
I have moved away to mostly working in C nowadays since I work as an embedded developer (never done C++), but I use Python for tools that make my life easier. That's why I watch your videos. When appropriate, I sometimes follow a semi-OOP approach in C, where I define a struct holding all data of that "object" and pass this (well, a pointer to it) to various functions that work on this data, much like the self parameter in an object's method in Python. I even call the parameter "self" most of the time. 😅
This is a really good video. Only thing I'd say I disagreed with is separating classes by data vs behavior. In theory this sounds nice, but when I get into a larger project I almost always need some of my data focused classes to be able to do some various behaviors. I think separating those out too much from each other could pose other problems. All about balance though
Its better to consider OOP exactly bad exactly per sé, just to oppose inertia.
Only when all developers will agree its not THE way of structuring code, we can talk how it can not suck.
This guy does create a lot of object oriented code, sometimes importing a couple of functions in a python script is all you need
I'm kinda new to python, and tbh I see a lot of code that people say it's "more pythonic" that for me is just more complicated to read. I've seen some list comprehensions that look like RegEx and took me a second to understand.
And a lot of what you talked here reminded me of how Django works, using classes (models) for data and mixing it with functional programming for views (even though you can use classes for views also).
Awesome, as usual. In my opinion the audio quality changed with respect to previous videos (and it was not an improving for me; previous ones were better).
I loved the video, but the constant rustling sound is quite distracting
Consistently good videos covering topics in a sensical way with examples reasonable enough to be relatable but not overly complex for explaining the subject matter. Great job. Would love to see you make some more "difficult" testing-related videos dealing with concepts like async sqlalchemy sessions and the many other difficulties that arise with testing asynchronous code. It's one of the areas where I feel least confident and most "Google a lot of stuff until things begin working" and I'd like to get away from that feeling, but it seems resources surrounding these topics aren't great currently.
Functional programming in not about using functions, it's more about stateless, function composition, memorizing, recursion and closures =) FP not easy to read and python is not great for FP. This video in more about procedure programming. When choosing between classes and functions keep in mind that under the hood python functions are just class instances with only (practically) call method :) I don't think it's a great idea to convert methods to functions, it could work, but you loosing internal state of class. And if your functions changes your classes state, or you have some global states - that's not FP at all =)
Correct it's a mixed style programming, with procedural and oo styles.
you are completely right.
I wouldn't call data classes OOP and I wouldn't call any functions FP. Functional programming would be more about not mutating data class objects, not avoiding the usage of them. Functional programming would be writing functions that promise not to mutate their inputs if passed by reference, and don't have side effects that get consumed by external logic. I'm not advocating for a certain style, just want to make it clear that class != OOP and function != FP, the styles are more about the constraints you put on yourself and the patterns that emerge from doing so. They are not about using or not using certain constructs, though certain styles do tend to lean more heavily on certain constructs like a preference for tuples over lists (to give a Python example) in FP because they enforce certain principles.
No, he used a function, therefore its functional programming. /s
This has been the play of OOP for years. OOP used to be about so many things(encapsulation, inheritance, etc.).
But now that all of those things have been shown to be terrible, its now just 'using classes/objects'.
@@Mr7Shane In my personal humble and very inexperienced opinion, Classes are the best single thing that allows you to store complex hierarchical data. Because you can have a very clear and defined level of control of what is stored in the class. And you can have the information you need not just as primitive types but as custom objects that enforce certain things about the data that simplifies managing them later.
However behaviour oriented classes are so cumbersome and often feel unnecessary when you don't have variations of the methods (writing unnecessary preambles to each functions and such). So unless you need to define custom behaviour for each different object I would avoid classes all together in favour of funcions. Whst I like about Python is that it allows the user to do multiple paradigms without too much effort. Exploiting the advantages of different approaches and such
Wow 🤩 luckily I landed on this channel and loving it . Gonna go through each of the videos , amazing way of teaching
Hi Priye, I'm glad you're enjoying the content - welcome here!
How do you feel about Dependency Injection increasing the number of inputs? On Clean Code it is mentioned that we should minimize params because we are just creating complexity by having to test multiple inputs generating multiple outputs. Wdyt?
Writing object oriented code well is basically a process of mostly avoiding object oriented programming
Great video! I'm not exactly sure what you meant by an abstract base class you use for inheritance, but I like to use certain modules, from pypi or from Python to manipulate those objects and localize my own objects. For example, creating a Paddle Class in a pong game that inherits from Python's Turtle. This way all of the code for those objects is in one class instead of riddled around the code. Inherit a turtle from Turtle and create your own custom turtles sort of thing. But maybe you said that in your video talking about inheriting from the Charge Class. I really like the idea of separating behavior from data in more complex programs. I like to see similar code in the same spots.
The beard is growing. Arjan slowly turns into our spirital leader. Leading us through the deadly valley that snakes itself across the land of Guidotopia.
Excellent video about how to make the code cleaner and neat. Thanks a lot!
Thanks so much Viktor, glad you liked it!
Amazing video Sir! Thank you very much for sharing your expertise with us! I always learn a lot from you!
My opinion's become that OOP isn't bad, there's just a lot of bad OOP code out there. A lot of the principles of OOP are sound, but they fall apart when you mindlessly apply them, and the same is true for FP. Someone who writes an AbstractSingletonFactoryFactory would also write some pretty heinous functional code, because the problem isn't the paradigm, but the person who applies the paradigm without thinking about their design first.
Lovely video!
Could you do a video on Method Chaining?
I've been told that it is not considered very pythonic. I've never found any good explanations as to why, though. It obviously works, and it is in plenty of libraries, so.. is it bad?
Personally, I love it.
Just discovered your video and it is very good! Looking forward to watching the next one :)
Glad you enjoyed it!
What I tend to do is when functional programming makes more sense I put all the functions into a class that kindof describes what the group of functions does and make them all static methods or class methods
wow I loved every bit of this videofrom the introduction to the end, as a self taught software developer in the making vidoes like this helps a lot, I did not only like but i subscibed.Thank you
Thank you so much, glad to hear you liked the content!
Arjan, I'd love to hear your feedback about a principle that I've used: That is, don't make a class unless you're going to need multiple instances of that class. I can think of one exception--a dataclass which has lots of instance variables. Otherwise, it seems like just using functions would be simpler. What to you tihnk?
P.S. I love your videos. Your explanations are very clear and well thought out. Thanks!!
RRs7@2eaww
I love static classes because they make the code more readable and I hate not grouping my code
@@paulblart4551 You can also use a module. That's what modules are specifically designed for
There’s a pattern called singleton which contradicts this principle. Most configs/settings you know in frameworks are singletons.
Thank you for another interesting video. It think is filmed really nice also. Visually pleasing, calm, colourful and still focussed on the code. Thanks again :)
I'm glad I found this channel
I would add: Use immutable data structures where-ever possible. e.g. dataclass(frozen=True) or tuple[Thing, ...] instead of list[Thing]. Do, if possible, not use a lot of getter/setter methods, but prefer to create new instances with the altered attributes. Immutability, delegation instead of inheritance, functional methods (no side-effects), and classmethod-factories that make the code easy to read and understand. Changeable class attributes are particularly a pain to test, because the control paths quickly factorize and become insurmountable.
Rocking that shirt! And as always concise and wonderful video
Learned a lot about fundamentals from your videos. Grateful 😊
Thank you! 😊
Separating classes to either mostly contain data but little behaviour (like structs) or to contain behaviour but little data (like functions), but preferably not both; and try not to use inheritance. Those must be some of the most unOOPish OOP-tips I have ever heard...
😃
Thank You,
From the Functools to DataClassess and now blending (F and OOP).
I feel this could have been your 7 steps pdf for download, lol
I had a question about assigning a index in lieu of self generated indexing.
There are (Cluster, Multilevel, Sparse, Hash etc.)
I have a establisd mathematical function I would like to use to assign a index to the database instead of building out table relationships.
I believe your depth of understanding of how to remain scalable and dynamic in your approach to coding gives me a bit of confidence that I can do something along these lines.
Thank you for your valued insight in this field.
My question is how can we have a discussion ?
My bread just came out of the toaster, and butter must be applied for the best Bread in the WORLD, lol
P.S. also my thumbs are cramping from this texting. I need to use VOIP more often.
my new favorite channel for python programming
Thank you so much for the kind words! Glad you've been enjoying the videos :)
you can use ide to navigate embedded classes, interfaces or abstract classes...
With all due respect, the first example is not a combination of FP and OOP. Here's an exemplification: "2" is an object in Python, and print() is a function. But when we write "print(2 + 2)" we don't "combine FP and OOP". It is just old good imperative code.
When we put imperative code into a function, we don't do "functional programming" just because of that. Functional programming is a quite special thing: it's a programming via function composition. Likewise, when we put our code into a method, this doesn't make our code object-oriented. OOP assumes certain specific principles (encapsulation, inheritance, polymorphism), without them it's all just using classes as C-like data structures.
Really good video, learned lots! Now I need to find out if you have a video on Protocols?
Thanks for giving this great advice for free
What really distinguishes OOP versus functional programming is that the former makes use of objects with *mutable* state, whereas in FP we make use of pure functions without side effects ie we avoid mutable state. Just because it has the keyword "class" in it doesn't mean it's OOP! Data classes are often used a bit like tuples, but with named slots, and you can make them(almost) immutable using frozen=True argument. When used like this they are a bit like Scala's case classes, which are used in FP. When you pass immutable data classs into pure functions, this is absolutely FP, and *nothing* to do with OO.
Would have been nice to also mention the terms "pure core" and "side effects". Especially the way the code should be organised. Haskel is probably one of the best examples. It allows I/O operations only in the "main" context. Hence all that unpredictability that I/O has is located in a "thin top layer" (easier to debug). The core must be immutable - the input gets transformed and returned at the output without any side effects. Same input generates same output no matter how many times that function is called. For dynamic programming languages there is also the PFAAO design pattern which is quite helpful. Writing tests for "pure" code is always a joy because it is really straight forward.
Personally, I'm coming from more of a RoR background. Wouldn't say that Python is that great with FP. I think that Ruby does a much better job at FP but it has its own downsides (i.e: there are no native immutable data structures). After learning a bit of Scala, I was able to understand that 95% of the Ruby projects I've ever seen were done in a classical imperative way that mixes the stateful with the stateless and then gets really messy over time.
PS: FP is a style. Can be very well achieved in any OOP language if FP principles are well understood and followed (ofc if we ignore the type system altogether which to me is probably Scala's best selling point).
1. 7:07 you mention PaymentProcessor could be a module. When would you write a class as a module? Would the api_key then be a module scoped global variable?
2. 12:00 sounds like a reason to do dependency injection is so it's easier to test, are there other reasons?
3. It looks like we are polluting the function argument list when dependency injection pulls things from within order_food into it's argument list. What if we wanted to test more items, the argument list is going to grow to contain other business entities, as many as we want to test.
Great video, I am not sure if what you call Dependency Injection is not just "composition", I think of DI as a more implicit/automated process, just like Pytest does with fixtures and FastAPI does with depends
@dataclasses are not OOP in my opinion, it is an implementation of Product Types/records. A behavior focus class isn't much of a class either, it would be better described as a module.
OOP starts with inheritance, IMHO.
Arjan, I love all your videos. You are a great teacher. I know it's not the focus of your video, but can you tell us how you have your line numbering setup in VSCode?
Modula-2!!! Kudos from a Pascal lover!
Thanks so much, glad you liked it!
I like you content on Python. You really know how to synthesize complex concepts into easy to understand bits. Do you have any material on react?
Thanks!
Thank you so much, Anthony!
Best channel of advanced python OOP. thanks!
Thank you, glad you like the content!
This sounded so familiar I did my (Sun)java certificates J2EE about 20 year ago. Retired now 🙂 yea i am old. Thanks for your insights.
algo boost comment. thanks for all your help!
Great topic indeed and looking forward for many such
Thank you, glad you liked it!
I love your teaching style. It's great
Glad you’re enjoying the videos!
Love this video and all the videos on your channel. Super helpful❗️😃
I would love to see an equivalent video on # Tips for Functional Programming in Python 👍😃
The point of classes is to group up related behavior and data together. If you create a class just to store data, there are dictionaries for that. If you want to group up functions, that's why we have imports and functions in single files.
Not agree) You can use classes to create yours datatypes, under the hood all python data types made same way.
@@clauseclause6640 you can, but is messy. As @Jorge Escobar said, it is more clear tu know that a python class is delivering - processing data, rather than only declaring data. I have seen a lot of programmers using Enum for this. As I said, so messy. Just persist your data in a db or create readable key value file, that later on, can easily be migrated to a db.
Easier and good practice -> global or local constants.
@@david85o primitive obsession
Accessing data as object's property is less error-prone than a dict's key. When u refactor the property name, IDEs support that in a click, doing that for key string is quickly becoming a mess. You cannot also hint the data type in case of dictionary.
@@TrungNguyen-mj2idThat's not necessarily true. You can use type hinting in the dictionary definition to get auto completion.
e.g. my_dict: dict[str, dict[str, MyObject]] = {'foo': {'bar': }}
Would allow you to get completion on a call like:
attribute = my_dict['foo']['bar']
attribute.method()
As for maintainability you're right, using string keys in a dictionary is really only useful if you're driving those indexes programatically to read a data stream that's given to you that way. Or if you have to say pair up arbitrary keys with values (like writing code that processes ang given datatable agnostic of headers/row names).
When you're building a data structure in code though, it's good practice to start with a dictionary and if you start running into overuse of magic string keys then migrate that structure into a more maintainable/documentable structure like a data class.
And python classes should primarily be used as a way to re-use functions and prevent pollution of the root level namespace with generic function names
For a really simple and dumb example: instead of 2 functions like get_number_as_float and get_number_as_int, youd have a Number class that has two subclasses called FloatNumber and IntNumber then call FloatNumber.get_number or IntNumber.get_number.
Being able to link data and functions is also a good way to make sure that users are feeding the correct data types to the class methods. If the object initialization fails (putting type checks in the __init__()) then you can immediately raise an error instead of letting them continue to misuse functions or hope they have their data formatted properly.
I enjoyed your video. In your tip #2, it would be useful to add an explicit "Why you create separate data and behaviour classes". It sounds like you are transitioning to FP when you say that often the behaviour classes could be replaced by a module of functions. Are you trying out any pure -FP languages?
i'd very likes your approach and sharing knowledge thanks for you good tips
I'm not sure about the section where seperate method and data-classes are promoted. As allready said in video, if you use data this should be in same class. As long as it is not about GUI programming nearly all of my functions process a bunch of data. Therefore I often have classes with data and functions/methods. I don't see anything bad about this.
Regarding the question if I would also put functions in my code (mix FP and OOP): Yes, but I would only write functions if it don't use class data, I don't want to store results and I do this only in one instance. Regarding the credit-card programming example: If I write code for a singe payment machine, I would stick to a function for this check-card-method, but if I programm a payment system with many payment machines, I would prefer to store the card-data in the same class and maybe also stroe the result of the check in this class to not call this too often.... so I would put it in a class.
Take a look into the python's zen!
Thank you for making this video. Great advice.
Glad it was helpful!
always great to see a video Arjan!
Enjoy it :)
Awesome tips man. For me coming from non object oriented background I have always used a functional and object oriented mix. It just feels easier for some reason.
One thing I don't understand is why you see so rarely these tips applied, even in the python standard libary. One recent exemple is the pathlib library. It does everything you advise against like multiple inherentences and even the use of the fency __new__ to create an os dependant path instance. So is it worth using this style of coding when not many people seem to use it ?
один из лучших каналов по теме
Great tips again teacher!
God, I love this channel.
Happy to serve 😊.
I noticed you sometimes use the UML class diagrams to explain some OOP patterns (e.g. adapter pattern).
I would love, if you would explain how to read those diagrams on some examples. I can't follow them in other videos.
Thank you for the suggestion!
Great topic and thank you for share your knowledge
Can someone elaborate on separation of behaviour and data? I sort of see some places where that could useful, but that's not everywhere or maybe I just lack experience to notice. I think it is a design decision important enough to have a separate video dedicated to it.
I like your explanations