Even More Code Smells - Purge These 7 Python Putrid Peccadilloes Now!

Visit bit.ly/ARJAN50 to get 50% off the Pro version of Tabnine for 6 months.
Yes, I'm back with 7 more code smells for you! I describe each smell using an example in Python and then show you how to fix it. The code I worked on in this video is available here: github.com/ArjanCodes/2021-ev....
Other code smells videos:
- • 7 Python Code Smells: ...
- • More Python Code Smell...
💡 Here's my FREE 7-step guide to help you consistently design great software: arjancodes.com/designguide.
🎓 Courses:
The Software Designer Mindset: www.arjancodes.com/mindset
The Software Designer Mindset Team Packages: www.arjancodes.com/sas
The Software Architect Mindset: Pre-register now! www.arjancodes.com/architect
Next Level Python: Become a Python Expert: www.arjancodes.com/next-level...
The 30-Day Design Challenge: www.arjancodes.com/30ddc
🛒 GEAR & RECOMMENDED BOOKS: kit.co/arjancodes.
🚀If you want to take a quantum leap in your software development career, check out my course The Software Design Mindset: www.arjancodes.com/mindset.
💬 Join my Discord server here: discord.arjan.codes
🐦Twitter: / arjancodes
🌍LinkedIn: / arjancodes
🕵Facebook: / arjancodes
👀 Channel code reviewer board:
- Yoriz
- Ryan Laursen
- Sybren A. Stüvel
- Dale Hagglund
🔖 Chapters:
0:00 Intro
1:29 Explaining the example
6:02 About code smells
6:36 #1: using the wrong data structure
9:23 #2: using misleading names
10:54 #3: classes with too many instance variables
14:23 #4: Verb/subject
18:03 #5: Backpedalling
21:32 #6: Hard-wired sequences with a fixed order
24:31 #7: Creating unrelated objects in the initializer
27:04 BONUS: Not relying on keyword arguments
#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!

Пікірлер: 173

  • @ArjanCodes
    @ArjanCodes2 жыл бұрын

    Visit bit.ly/ARJAN50 to get 50% off the Pro version of Tabnine for 6 months!

  • @mikefochtman7164
    @mikefochtman7164 Жыл бұрын

    @12:25 The little flip back and forth to confirm your customer ID was an integer, reminded me of a huge argument / debate our team had once. One side was, "It's made up of digits, so it's an 'int'." Other side was, "You do NOT perform any math or calculations with it so it is NOT an integer, it's a string of digits." (and a single individual that voted for, "It's a unique identifier, so it's its own class.") Couple of boring meetings later, the 'string of digits' camp finally wore everyone down and won the debate. lol

  • @ehsisthatsweird
    @ehsisthatsweird2 жыл бұрын

    python docs prefer raise NotImplementedError to ‘pass’ or ellipsis in empty abstract/protocol methods. I guess the reasoning for this is if you use super() then ‘pass’ might get you into trouble.

  • @ChrisBNisbet
    @ChrisBNisbet2 жыл бұрын

    The common prefix "customer_" is a hint to the dev/reviewer that the variables could/should be moved into some separate class/structure. I often see something similar in 'C' code where people create groups of structure fields all starting with the same prefix.

  • @TheTacticalDood

    @TheTacticalDood

    2 жыл бұрын

    Indeed that is the practice in C since it has no other way of avoiding namespace collisions.

  • @cheebadigga4092

    @cheebadigga4092

    Жыл бұрын

    @@TheTacticalDood well it has structs though.

  • @XRay777
    @XRay7772 жыл бұрын

    A small side note on the annotation matter: 'from __future__ import annotations' is only available from python 3.7+. If you are on 3.6 you can just turn the annotation into a string, which will delay the evaluation until after the class is defined (see PEP 563 for details). The import actually does the same thing, but automagically.

  • @pedromartindelcampogonzale9613
    @pedromartindelcampogonzale9613 Жыл бұрын

    In the last code smell, the one about keyword args, if you are programming on a language that doesn't have this feature, you can use the builder design pattern when you have too many arguments for a constructor. If you're calling a method that is not a constructor, first, your method may be doing too much, but if you really need all the arguments, you can wrap them in a dataclass if it makes sense. Maybe you can even move the whole method and even others to this new class, if it feels better.

  • @artemhrytsenko1353
    @artemhrytsenko13532 жыл бұрын

    27:05 you can put * at def some_function(*, a, b): ... and using it every single argument have to be assigned with keyword arguments (otherwise, TypeError would throw).

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Good point, thanks!

  • @bocckoka
    @bocckoka2 жыл бұрын

    to 6: in Rust, where you have move semantics, you can guarantee at compile time that you use your objects with stages properly, meaning that a state transition 'moves' the object, and you can't call methods of the previous state on it anymore, because it doesn't exist. it's called typestate pattern

  • @Claxiux
    @Claxiux2 жыл бұрын

    Code smells is an excellent name. It’s what made this series stand out and your channel with it!

  • @ZapOKill

    @ZapOKill

    2 жыл бұрын

    yeah, i am 100% sure he came up with the name all by himself!

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Haha, I wish 😊. I think it was Martin Fowler who came up with the name.

  • @programming_in_ukrainian
    @programming_in_ukrainian2 жыл бұрын

    Hey Arjan! Nice video, thank you, but I have two things to discuss: 1. I slightly disagree with add_line_item implementation. IMHO it's better to pass native data types (name: str, quantity: int, price: int) than some custom type 'cause at least you can simplify communication with outer code (unpack dict or they would call method by passing native types) and not obligate other people to use your own object to do so. 2. Importing annotations from future is not the only way to declare your method would return value of the class itself, you can wrap its name in quotes and type hinting would still work the same way class A: def method(self) -> 'A': pass

  • @AlexBerkk
    @AlexBerkk8 ай бұрын

    Tabnine ad. Pre-Copilot days were wild. I'm not crying, you're crying!

  • @sergiovasquez7240
    @sergiovasquez72402 жыл бұрын

    I am not a Python programmer, but I feel this an amazing resource to start good coding practices as soon as possible. Most of this advices translate very well to programming in general. Keep the hard work, and I hope there are more of this kind of videos coming. I bet there are very hard to make.

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Thank you Sergio, will do!

  • @GulfCoastGrit

    @GulfCoastGrit

    2 жыл бұрын

    Agree completely! I use these to improve my C# skills! 😊

  • @rdwells
    @rdwells7 ай бұрын

    I would argue that there is one more minor code smell here: using an integer for a customer ID. My rule of thumb is that if you are not doing arithmetic on it, it's not a number. I learned this hard way with some manufacturing software I wrote. It had to read a list of order numbers in a text file dropped by some IT system and process those orders. They were 12-digit numbers, so I stored them as ints. (This was C++, so they were 64-bit ints.) Then IT decided to slowly replace their old mainframe database with a new Oracle system, and decided to mark orders from the new system by replacing the 12th digit with an "E". They did this without warning. I had one day to modify the program and change the type of a primary key on a bunch of database tables.

  • @joem8251
    @joem82512 жыл бұрын

    You do a lot of good videos that illustrate SOLID principles. I think if you expand on those concepts with automatically-generated UML diagrams with Pylint's Pyreverse you could create some interesting content! Thank you for your videos -- you somehow always have something I need -- occasionally just when I need it!

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Thanks Joe, will look into it!

  • @imadetheuniverse4fun
    @imadetheuniverse4fun2 жыл бұрын

    I think you did a really good job showing code smells in code that may pass as "good" at first glance. For example the payment processor having a Protocol at first glance seemed like a good thing, but it turns out you don't need to use that and can decouple even further by simply creating the payment function with the correct parameters. Really shows that you should really think about how and where you apply these design patterns and principles.

  • @dariuszspiewak5624
    @dariuszspiewak56242 жыл бұрын

    Ha! Finally found somebody who does not teach Python basics and the dry stuff of how to loop over a list (it's important as well, don't get me wrong), but actually teaches about Python software architecture and best practices :) Thank you, Arjan. That's genuinely valuable. By the way, Arjan, if you want really, really, REALLY awesome programmer keyboard and heavenly typing experience, get yourself the Kinesis Advantage keyboard. Once you do it, you'll never, ever look back on the usual QWERTY crap (even the so-called "ergonomic") which I don't touch today and don't want to even look at. I've also re-trained myself to type on a modified Dvorak layout (called Dvorak Programmer), so my hands and wrists will be healthy and thankful to me for the rest of my programming life :))) Not to mention the speed of touch-typing. Great videos. Gonna subscribe and have a look at your courses.

  • @marcosoliveira1538
    @marcosoliveira15382 жыл бұрын

    Great content. I would love to see a video about meta-programming, about your favorite decorators.

  • @shS83
    @shS832 ай бұрын

    Watched your videos for the first time yesterday and became an instant fan. Subscribed. Keep up the good work!

  • @ArjanCodes

    @ArjanCodes

    2 ай бұрын

    Welcome aboard! Happy to have you here.

  • @MichaelFJ1969
    @MichaelFJ19692 жыл бұрын

    Thanks for this video. It is really helpful. Please do consider making more such videos.

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Will do ;)

  • @saitaro
    @saitaro2 жыл бұрын

    Thanks again, mate, your videos really make me write better code!

  • @deatho0ne587
    @deatho0ne587 Жыл бұрын

    To your bonus tip, I agree in general. For most IDEs or Code Editors worth using, you can hover over the function/method name and get the names of every parameter/argument and their respective types. Also should give different impementations of a function if their are mutliple versions. VSC which it seems like you are using even did this around 27:59. Meaning a dev does not really have to do it if they know how to use their respective editor.

  • @timjohansson4304
    @timjohansson43042 жыл бұрын

    Hi Arjan! Great video as always, thanks for that. I would like to see a video describing your process of finding codesmells, this example is a really small code base to easily show and correct what you already found. Tips and tricks for modelling and finding these code smells would be much appreciated :)

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Thank you Tim! I do it on some level in the code roast / refactoring videos on this channel, but great topic suggestion to dive more into how to find them, thanks!

  • @Andrumen01
    @Andrumen012 жыл бұрын

    Just wanted to say that I like your channel very much. I am on a career change move and your tips have helped a lot to make the project I am currently working on be more organized. That being said, I was going to ask you about the implementation of Python events, how do you feel about code implementing events rather than direct calls to functions? Is there any "code smell" for implementing event systems? Best regards and keep up the excellent work.

  • @rdean150
    @rdean1502 жыл бұрын

    I prefer "code aroma". It really rolls off the tongue more nicely. Because, as we all know, mouthfeel is a crucial aspect of software design patterns.

  • @DanielWeikert
    @DanielWeikert Жыл бұрын

    Hi found your channel and I really appreciate your videos. So far I always used python without paying much attention to structure and best practises (so 180 degree different to your style). I like to learn how to change that but I am not sure how to start the best way. Is there any order, guide,.. which helps to learn and apply your concepts and strategies the best way? Tahnks

  • @BrunoReisVideo
    @BrunoReisVideo Жыл бұрын

    These videos are great. Feels like getting a brand new bottle of nice perfume

  • @ArjanCodes

    @ArjanCodes

    Жыл бұрын

    Thanks so much Bruno, glad you liked it!

  • @kidsforcode3052
    @kidsforcode30522 жыл бұрын

    Thanks very much. Very well explained practical advice!

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Glad you enjoyed it!

  • @andyanderson222
    @andyanderson222 Жыл бұрын

    Not only these tutorials are awesome, but i really like your sense of humor. These 7 x "Code smell" at the beginning was very funny) By the way, 1 question i have watching this video is why do we put default values on every Customer dataclass field? If we let user to create empty instance of customer without putting any info into constructor is it good for us? Like what will we do with this totally empty object later?

  • @SoChot
    @SoChot11 ай бұрын

    Great video! In section 6, when you're defining the static method `create()` for the `StripePaymentProcessor` class, is there a reason you didn't use a class method since those are often used as object constructors?

  • @NanaAtiekuFrans
    @NanaAtiekuFrans2 жыл бұрын

    Your contents are always great. Thanks.

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Glad you like it, you’re welcome!

  • @Acuzzio
    @Acuzzio2 жыл бұрын

    This video is just excellent. Thanks a lot for providing such a good content!!

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    You’re most welcome - I’m happy you like the content!

  • @DjegGoEu
    @DjegGoEu2 жыл бұрын

    Hey Arjan, At minute 22:56, doesn't it make more sense to use a class method to handle the creation and deployment of the object? I always have a hard time distinguishing between class method and static method usages, but that case seems to work fine with class methods. What do you think?

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    The main reason to use a class method is if you need to do something with the class. It would be a great solution in this case actually, because then you can call the initializer using cls and if you change the class name, you won't have to update this method. So yes, good point!

  • @frustbox

    @frustbox

    2 жыл бұрын

    I think in this case a classmethod would make a little more sense. It's strongly coupled to the object, in fact it's kind of a constructor. Some other examples are `datetime.now()`, `datetime.fromtimestamp()` or `datetime.strptime()` They are constructors that take some input to create a datetime object. In the code example here the `create()` method is a constructor (or initializer) that creates a PaymentProcessor object. So in this case, I would use classmethod, yes. IMHO staticmethods are more loosely coupled to the class. Kind of helper functions that are not really tied to the class or the individual object but may be used in conjunction with the class/object. And they are tacked onto the class as staticmethod solely to make imports easier. Otherwise in almost all situations I tend to avoid staticmethods and just use functions on the module/file level to not clutter the class with functions. But of course … that's all a bit convention and personal preference. There's no right or wrong here, I think.

  • @zacky7862
    @zacky78622 жыл бұрын

    Another great tutorial :) Thank you so much

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Glad you liked it, @Zacky!

  • @an-lo9787
    @an-lo97872 жыл бұрын

    Hey Arjan! I appreciate you and the content you post weekly is very helpful. I have one question, do you import these codes and then determine areas you could improve, or do you write these codes and are going back over them now having a different perspective? Thank you for your feedback in advance!

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Glad to hear it's helpful! It depends on the video type actually. For the code roast videos I work off the code of someone else, so there I mainly treat it as a code review and try to find areas of improvements. For these code smell videos, I have a list of things in my head that I've seen people make mistakes with in the past (including myself), and then I try to come up with an example that shows these things in a logical way. Overall, if I refactor code it's always an iterative process, where I try to improve something and then that triggers another possible improvement. Or what I had in mind didn't work and I have to change it back, haha :).

  • @slavrine
    @slavrine Жыл бұрын

    Using wrong data structures vs backpedaling seems contradictory to each other. Should we be wrapping data in a class, and passing the instance around? This will allow us to avoid multiple lists around, but would make other code dependant on the names of methods and attributes of the data class. Thus by using a better data structure we introduce backpedaling. Thank you for great content Arjan!

  • @5ihdi
    @5ihdi Жыл бұрын

    It would be interesting to see how we can implement Factory Design Pattern to create multiple Customer, Order etc in the main() function that manages to add this multiple instances to the POSSystem. And maybe even incorporate different PaymentProcessor classes

  • @aliemamalinezhad6523
    @aliemamalinezhad6523 Жыл бұрын

    Excellent as always

  • @ArjanCodes

    @ArjanCodes

    Жыл бұрын

    Thank you Ali, glad you liked the video!

  • @kingremonoire239
    @kingremonoire2392 жыл бұрын

    Hi Arjan. Love your content. please keep it up :)

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Thanks, will do!

  • @robertbrummayer4908
    @robertbrummayer49082 жыл бұрын

    Another great video! The only thing I do not like and I guess also Uncle Bob would criticize are some redundant comments, e.g. the comments in the main method "create a customer", "create the order". As I have already pointed out in another comment, this is a code smell called redundant comments. Every programmer can see that you create a customer and order object there, so there is no need for these comments. There is also a doc string "Order status" that simply repeats what the name already tells. But this is just a minor point, great job!

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Thanks Robert! You’re right. I was still on the fence here on what to do with code comments in my videos, as the default linter settings I used wanted to see comments everywhere. I’ve since turned that off and went with only adding comments if they contribute to the clarity of the code. I might do a video about comments soon to share my ideas about them.

  • @robertbrummayer4908

    @robertbrummayer4908

    2 жыл бұрын

    @@ArjanCodes Such a video would be great. Thanks Arjan! Best wishes from Austria :)

  • @Gummibandet1
    @Gummibandet12 жыл бұрын

    Could you do a video showing what packages you use and recommend, as well as key commands you often use when coding?

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Thanks for the suggestion!

  • @tehdusto
    @tehdusto Жыл бұрын

    As part of my job I'm having to move from python to LabVIEW. All of these practices are still applicable in the data flow paradigm and this content is helping me improve my companies LabVIEW code base. LabVIEW is cursed though

  • @DS-tj2tu
    @DS-tj2tu2 жыл бұрын

    Awesome! Thank you!

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    You’re welcome!

  • @pypro
    @pypro2 жыл бұрын

    Amazing video, great bro!! =) many thanks

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Glad you liked it!

  • @1oglop1
    @1oglop12 жыл бұрын

    I like the examples, however, I noticed that most of the videos work with data classes that are easy to change. What about refactoring an app that is using an ORM (Django or SQL Alchemy) - the pain going through the migrations (and data changes) during the refactoring is often well underestimated. I think that it would be nice if you can show the cost of changing the data model like that. Big plus point for saying `initializer` instead of constructor!

  • @alexandersnow5867
    @alexandersnow58672 жыл бұрын

    Hey Arjan, Great video. I’ve been learning a lot watching this series. I was curious about your choice to make the create method for the StripPaymentProcessor a static method and not a class method? That would resolve the annotations. I’ve found myself to be a bit unclear on the benefits of either. I would assume a classmethod might be more handy if we wanted to make additional processors that inherit from StripPayment?

  • @akivazonenfeld7285

    @akivazonenfeld7285

    2 жыл бұрын

    You can't do it with a class method since a class method is called on an instance of the class. And since this 'create' method supposes to be used to create the instance, it doesn't make sense to make it a class method. And I'm pretty sure It won't solve the typing problem.

  • @alexandersnow5867

    @alexandersnow5867

    2 жыл бұрын

    @@akivazonenfeld7285 a class method is called on the class itself and usually returns an instance of the class, which seems to be what we’re doing here. It may not resolve the typing issue if we still say that the return is the StripePaymentProcessor though

  • @XRay777

    @XRay777

    2 жыл бұрын

    I agree with you, Alexander. If you are implementeing the factory method pattern the default choice should be classmethod precisely for the reason you mentioned: it gets a reference to the type it is attached to as the first argument (usually denoted cls). If you derive from a class with a classmethod then the derived class will be passed as the cls argument if you call it on the derived class. Thid is the defining distinction between classmethod and staticmethod. A staticmethod does not get a reference to the instance / type it is attached to. It is mainly used to indicate that the method is logically connected to the class but not tightly coupled.

  • @xnick_uy
    @xnick_uy2 жыл бұрын

    Another excellent video. I think I got the majority of the main points. I'm not very experienced with async calls, and I'm also not too sure that I understand correctly the purpose of the @staticmethod qualifier. But now I have new learning goals!! :-) Please keep making these videos. Besides the content, the narrative and the edition is fantastic.

  • @XRay777

    @XRay777

    2 жыл бұрын

    staticmethod (or classmethod for that matter) allows you to call a method directly on the type as opposed to an instance. Using this to create objects is actually also a design pattern. It usually goes by the name 'factory method'.

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Glad it was helpful! I'm going to post a video about async soon!

  • @funkenjoyer

    @funkenjoyer

    2 жыл бұрын

    @@XRay777 Isn't usually used with @classmethod instead of @static? I guess both work just fine but I usually use the class one so that the method is decoupled from object but still tied to the class.

  • @XRay777

    @XRay777

    2 жыл бұрын

    @@funkenjoyer yes, i agree. With instances you would more often see cloning behavior like implementing __deepcopy__ or some custom clone method of you need more control

  • @ZEDAWMN
    @ZEDAWMN2 жыл бұрын

    Thanks Arjan very helpful video. Can you make a video for the vscode extensions you are using for Python development ? I see you are using vscodevim and it will be interesting to see the rest. Thanks again

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Good idea, thanks for the suggestion!

  • @TomWoodland
    @TomWoodland2 жыл бұрын

    You create a class variable "id", isn't that overwriting a built in/protected variable? Great video. Learnt a lot.

  • @XRay777

    @XRay777

    2 жыл бұрын

    Yes, it is shadowing it, meaning that you cannot use the built-in id function in the scope of the class.

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Indeed. I’m aware of the shadowing, but I never use that function and it’s a really useful variable name 😊. Alternatively you could name it _id, following the naming scheme used in NoSQL databases like MongoDB.

  • @alfonsov3190
    @alfonsov31902 жыл бұрын

    Thanks for the video! Especially for clarifying the problem with self-reference typing. Does the __future__ import also solve problems when there is a cyclic type reference between two or more classes?

  • @XRay777

    @XRay777

    2 жыл бұрын

    Yes, it does and it also helps with cyclical imports. You can combine this with the TYPE_CHECKING flag from the typing modulec if you still want static type checking e.g. with mypy but want to avoid cyclical imports. In essence, you can then dump all the cyclical imports in a `if TYPE_CHECKING` block.

  • @alfonsov3190

    @alfonsov3190

    2 жыл бұрын

    @@XRay777 Thanks a lot!

  • @erikdeveloper
    @erikdeveloper Жыл бұрын

    Man, you're legend!

  • @ArjanCodes

    @ArjanCodes

    Жыл бұрын

    Thank you Erik, glad you liked the video!

  • @puddlejumper1
    @puddlejumper12 жыл бұрын

    Love the code smell videos. Question: How can you reduce boiler plate code? For example you introduce 'LineItem' class but now you have to type it out 3 times in the main file (and potentially alot more if you have more items). Adding to the order.add_line_item function would reduce the code in main file. Thoughts?

  • @Milamber5186

    @Milamber5186

    2 жыл бұрын

    In a typical pos system, all of your items would be in a database. You would not add items into the code, but instead add them to the database. In this video, it was added to the code for demonstration purposes.

  • @themadichib0d

    @themadichib0d

    2 жыл бұрын

    Doing so saves you some code lines in the short term for this example, but in the long term and/or real world use youd be making more work for yourself. And like the other person said, rarely are you constructing specific objects like this directly in code, and would be in taking from a source(eg database or a client) in which case youd never run into your specific concern in the first place.

  • @javier232010gmail
    @javier232010gmail2 жыл бұрын

    I wonder if not is better to pass the Order dataclass to the payment method? From my point of view, probably at future, you need more information about it and you will need to add more params

  • @adjbutler
    @adjbutler2 жыл бұрын

    thank you for this video

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    You’re welcome!

  • @allanmuller3486
    @allanmuller34862 жыл бұрын

    I may be getting ahead of myself, but mightn't it have been better to link the customer to the order using the id and keep the customer data in a dict keyed by id? Plusses include being able to maintain the customer id in one place, the minuses include not being able to having alternate shipping addresses for specific orders.

  • @XRay777

    @XRay777

    2 жыл бұрын

    I have to say I don't really see a benefit to that. The way he did it you can easily get all ids by doing '[c.id for c in customers]' but grouping the customer data nicely from what you are suggesting is much more involved.

  • @theguy2887
    @theguy28872 жыл бұрын

    I love these videos!!!!

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Thanks, glad you like them!

  • @potlurikrishnapriyatham
    @potlurikrishnapriyatham11 ай бұрын

    any tool/ide extension to detect codesmells?

  • @davidlakomski3919
    @davidlakomski39192 жыл бұрын

    Fortunately, my coding skills aren't advanced enough for my code to really stink xD Really love your videos and admire your teaching skills, thanks a lot !!

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Don't worry, David, the smell develops all on its own regardless of your skill level ;).

  • @davidlakomski3919

    @davidlakomski3919

    2 жыл бұрын

    Eager to discover my own putrid perfume mature then 😁

  • @alessandroferrari2166
    @alessandroferrari21662 жыл бұрын

    what a gem of a video! Jam-packed with value, thank you Arjan! I was wondering: wouldn´t be better to have that staticmethod be a classmethod instead, since it returns a new instance. I'm a bit confused on the use of @classmethod in Python so my suggestion might be totally bs :D On another note, videos suggestions for the future: enterprise architecture patterns in Python, microservices in Python, DDD in Python. Again, thank you for your inspiring work!

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Hi Alessandro, thank you, glad you liked it! Yes indeed, this would be a great use case for a class method!

  • @aadithyavarma
    @aadithyavarma2 жыл бұрын

    Great video! One question: class StripePaymentProcessor: def __init__(self): self.connected = False How do you change this into a dataclass? Should you use field(init=False, default=False) or use __post_init__() or both?

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Thanks! You can change it into a dataclasses really easily: @dataclass class StripePaymentProcessor: connected: bool = False

  • @aadithyavarma

    @aadithyavarma

    2 жыл бұрын

    @@ArjanCodes Isn't the above dataclass equivalent to the below: class StripePaymentProcessor: def __init__(self, connected=False): self.connected = connected Since we do not want to initialize the value by passing it as an argument while creating the object, it should be avoided. 1. @dataclass class StripePaymentProcessor: connected: bool = field(init=False, default=False) OR 2. @dataclass class StripePaymentProcessor: connected: bool = field(init=False) def __post_init__(self): self.connected = False Which one do you think is better 1 or 2? Or is there a better approach?

  • @finleycooper8844
    @finleycooper88442 жыл бұрын

    Make sure to add this to your code smell playlist so people can find it easier

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Done - thanks for pointing that out!

  • @jurgen6706
    @jurgen67062 жыл бұрын

    I'm not familiar with Python's Protocol classes. But since there is no dependency between the PaymentProcessor protocol and the StripePaymentProcessor is it just assumed that when you pass the StripePaymentProcessor instance that it implements the protocol? Python being Python it probably will only actually throw an error at runtime, but I'm wondering what happens at write time. Does the type checking system check this when referencing a class that does not implement the protocol and will it give a warning if in this case the StripePaymentProcessor does not implement all the methods from the PaymentProcessor?

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    That’s indeed how it works. Check out my recent protocols vs ABC classes video where I show exactly what happens and at what point you get an error. When you’re writing code and you use a type checker like Pyright, it will point out protocol implementation inconsistencies.

  • @peterkuchar219
    @peterkuchar2192 жыл бұрын

    I'm not sure customer should go as an input to Order. Shouldnt be other way around?

  • @Evkayne
    @Evkayne2 жыл бұрын

    I love those 10 seconds haha!

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Haha, good to hear :)

  • @dirk6531
    @dirk65318 күн бұрын

    Your Order class ist decorated with @dataclass. Requestion: why contains the class functionality? Is it a good Idea to Split into Order class (only Data) and a OrderManager ( contains the business logic to handle Orders)?

  • @luukvdv5238
    @luukvdv52382 жыл бұрын

    What is your opinion about explicitly setting states from outside? I expected e.g. a pay() method that sets the state to paid instead of setting the state to paid explicitly.

  • @XRay777

    @XRay777

    2 жыл бұрын

    Seems like something you would find in Java or C++. In python you can escalate access to attributes of you need to. If you only change the value of an attribute, leave it as an attribute. If at some point you need to restrict access or do some other stuff, like verification, just turn the attribute to a property with a setter. The interface for the user remains unchanged. You cannot do this in Java or C++, which is why programmers in those languages are so pedantic about getters and setters, since it is really hard to change an existing interface without breaking stuff.

  • @luukvdv5238

    @luukvdv5238

    2 жыл бұрын

    It feels like leaking information of the implementation. From the outside you need to know the enum of those states.. also the state is already marked private using the _. So it's private and then set using a set method.

  • @XRay777

    @XRay777

    2 жыл бұрын

    @@luukvdv5238 Fair points. Regarding the first, what I usually do is put all enums that are used throughout the project / package together in a file like common.py, which makes them easily accesable from everywhere. You can also expose them in the __init__.py of your package. I would not consider enums as implementation details, rather they are discretized options that can be used with the framework. To your second point, I missed the '_', but that only marks it protected. If you want to make it private you would need two '__' and then you can still have a read-only property with just 'status'. I don't really see the benefit in having a 'pay()' method that anyone can call over a property setter that restricts the status value which you can set. The latter gives you a simpler interface for the class.

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    In general it's not a bad idea to separate implementation details like the order state from the users of the order. I can definitely imagine a pay() method as you suggest, or a set_to_paid() method. It becomes an issue though once there are many different values for the enum (cancelled, returned, refunded, payment_failed, etc.). In that case, adding a bunch of different setter methods for each of them leads to a cluttered Order class and it's better to expose the enum instead.

  • @getpoked101
    @getpoked1012 жыл бұрын

    I know you are using the vim extension but you still use your most quite a bit to navigate. Is that just for demonstration or do you have a method to the madness ?

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    That’s mostly me having to unlearn 30 years of text editing with a mouse. I’m slowly adopting more Vim-like practices though, so I’ll hopefully get better at it soon.

  • @getpoked101

    @getpoked101

    2 жыл бұрын

    @@ArjanCodes I'm at about 15 years of it. It's odd I learned on emacs, then as I become a professional I used a bunch of mouse driven IDE's and now I'm in the same boat as you. I find my biggest issue with the vim extension is when it plays poorly with other extensions.

  • @polyliker8065
    @polyliker80652 жыл бұрын

    Hey Arjan, I've recently been in an introductory course as part of a new job where we had to work with a system where stored procedures ruled the game and handled everything from data access to business logic. I asked the instructor why there was business logic in the database when we're already doing business logic in the visual basic app. He kinda got upset and said he didn't hear a good argument why it shouldn't be there, and only said that stored procedures are safer but less portable. I didn't really agree on that but kept my mouth shut since I didn't want to cause a scene. (I can think of a few reasons why stored procedures aren't considered best practices.) Do you have a view on the pro's and con's of stored procedures, in which case they are usefull and when they should be avoided?

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    I avoid using stored procedures in my projects because I like to have my business logic in a single place. Having it in multiple places leads to more work in the future: if you need to change something, you’ll probably need to change it in multiple places. Also, you now have an extra decision to make: should this new thing be a stored procedure or in the backend code? If you make the wrong choice, it costs time to fix it. Finally, having two places where business logic is stored might limit you in how you setup your software architecture, leading to a potentially less optimal solution.

  • @andreacazzaniga8488

    @andreacazzaniga8488

    2 жыл бұрын

    You might be true, but that's not very relevant. (disclaimer: not requested advice) many business implementations are far from ideal, and this is not even a case where the implementation is necessarily bad. Wait until having a stored procedure gives a problem and be the one who knows how to solve the issue. If the stored procedure works and has never given a problem.. Keep it like this, even if it could be better. You will always want to change the cod base and stuff of projects, but.. Focus on fixing stuff that don't work or that you are asked to change. The rest.. Wait until you are more senior and your colleagues know you and trust you.

  • @polyliker8065

    @polyliker8065

    2 жыл бұрын

    @@ArjanCodes Thanks for the reply! Those were indeed some of the reasons it seemed not to be a best practice to me. I didn't think about the limitation in terms of architecture though. Another was having two code bases to maintain and deploy potentially causing synchronisation issues which might introduce errors.

  • @polyliker8065

    @polyliker8065

    2 жыл бұрын

    ​@@andreacazzaniga8488 Yeah, it was not meant as a correctional comment but more of a question on why we've gotten this as a sample app. I mean it'd be nice to be introduced to stored procedures without the sample app actually using them. So we get more of a message along the lines of 'while we'd rather put our business logic in one place, but you might encounter this. Just don't touch it unless asked'. And don't worry, the focus is always on what is asked. Don't be afraid to ask why something is done a certain way when you see possible improvement though.

  • @guilhermearantes4627
    @guilhermearantes46272 жыл бұрын

    Where can I learn these topics in depth?

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    I'm going to launch an in-depth course on software design before Christmas!

  • @gustavorangel729
    @gustavorangel7292 жыл бұрын

    On 16:00, is there a particular reason to implement a property instead of a method like get_total_price(self)?

  • @funkenjoyer

    @funkenjoyer

    2 жыл бұрын

    it's pretty much a personal preference, they would behave pretty much the same, one thing tho that i've run into is that you can't rly create an abstract property so if you had a hierarchy of classes that all have get_total_price and you had an abstract base where it's defined as abstract method you couldn't rly swap it for property

  • @XRay777

    @XRay777

    2 жыл бұрын

    It is considered more pythonic. You can think of the total price as just a value that is automatically updated. Therefore it makes sense to access it just like any other attribute, hence the property. It allows you to skip the empty parentheses when calling it as opposed to a method.

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Exactly what @X Ray says!

  • @XRay777

    @XRay777

    2 жыл бұрын

    @@uqams I disagree somewhat with that statement. The whole point of properties (or the whole descriptor protocol for that matter) is the flexibility to change access without changing the interface. If you would never use properties if computation is involved the whole concept would be moot. On the other hand, when the computation has side effects, as in changing something about the state of the class other than the attribute you are setting, or if the computation can be costly, then you should definitely go for a method instead.

  • @kuishikama348

    @kuishikama348

    2 жыл бұрын

    @@XRay777 So it works all very much the same, but you would use properties when you don't change the state of the object, basically when "not much" is happening and you basically just want to return a saved value or derive something directly from the saved values (like the totalprice = quantity * price)? You would use a method, indicated with the () if you want to describe that something is changing, like a create(), run(), start(), close() and so on? I think this is a TIL moment for me. Thanks for that. I just wonder what happens if you want to determine the totalprice, but it involves a costly function, something like accessing a web-resource, lots of calculations, things like that? Do you still use a totalprice property or do you use a method get_totalprice() to indicate to someone reading the code that this is costly? I just imagine someone extending or maintaining the code later on, not realizing the costs of these simple looking properties and then wondering why it is so slow. Profiling and debugging until realising that obj.totalprice is actually generating requests, starting a long calculation and so on. Would you use properties or methods for that?

  • @pacersgo
    @pacersgo2 жыл бұрын

    I still don’t get at 23:03, why the “create” function is used instead of directly put the contents to __init__?

  • @kristik432

    @kristik432

    2 жыл бұрын

    It's better to keep init clean kzread.info/dash/bejne/Y4d8y5OkosyweZc.html

  • @pacersgo

    @pacersgo

    2 жыл бұрын

    @@kristik432 it makes sense. Thank you for the link!

  • @stefanobailey740
    @stefanobailey7402 жыл бұрын

    Can someone explain to me why you wouldn't use a Dataclass over a regular class? I understand that you can't use the dunder method new, but with slots being added to 3.10 that can't be a factor. If anyone could clear this up, I would really appreciate it

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Sometimes your class is not at all data-oriented, and has mostly methods and not many instance variables. In that case you might als want to have more control over the initializer instead of what a dataclass provides by default. For example, a ExportFactory might not have any instance variables, but simply have as a task to create a variety of Exporters. In that case, turning it into a dataclass doesn’t add any value.

  • @stefanobailey740

    @stefanobailey740

    2 жыл бұрын

    @@ArjanCodes thank you so much for your response. I really appreciate ypu taking the time to clear it up for me

  • @andymachine6545
    @andymachine65452 жыл бұрын

    What's the code smell related to the thumbnail? Cause thats what my code typically looks like :D

  • @ChrisBNisbet
    @ChrisBNisbet2 жыл бұрын

    Given the number of times you use the word 'interface' when describing protocol classes, I wonder if a better name for Protocol would have been Interface.

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    I would have liked a more strict interface-like programming concept in Python, like Java or Typescript has. But protocols are still quite nice and tie in well with Python’s typing system.

  • @mypegionworld7612
    @mypegionworld76122 жыл бұрын

    You are the only person that makes me insecure about my code..

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    No need! We’re all here to learn (including myself).

  • @Kahitar1
    @Kahitar12 жыл бұрын

    Why don't you ever use multiple cursors? For example you could have selected all "add_line_item"s and changed them all at once to pass LineItem. Just curious if you don't know about multiple cursors or have another reason to never use them :) Also just want to say that I love your content. I learn a lot from you in every video and it already improved my python code A TON! Thank you :) ALSO: I noticed you are using pyenv. I never used that, I always used venv or pipenv. As a suggestion for a video: I would love a pyenv Tutorial from you. Of course you don't have to do it just for me, I can just watch other tutorials. Just if you think it fits to the content of your channel ^^

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    The main reason I avoid them in my videos is that I'm concerned it would make the explanations less clear since text is changing in multiple places at the same time. I do use name refactoring a lot (F2 in VSCode). Glad to hear the videos are helpful to you. Regarding pyenv, good suggestion, thanks!

  • @felipealvarez1982
    @felipealvarez19822 жыл бұрын

    I love your smelly and stinky videos Arjan! Thank you, now I'm going to go take a shower.

  • @TomWoodland
    @TomWoodland2 жыл бұрын

    Code smells!!!

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    You bet! ;)

  • @amir3515
    @amir35152 жыл бұрын

    Come on, it's only smellz 😉

  • @rrwoodyt
    @rrwoodyt2 жыл бұрын

    I still miss the whteboard!

  • @aclassypotato8155
    @aclassypotato81552 жыл бұрын

    hi arjan

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    Hi classy potato

  • @originalvbgunz
    @originalvbgunz2 жыл бұрын

    These videos are cool but smaller/quicker videos *focusing* on single subjects may be a better idea. Think seven videos each focused on a single subject, best practice, idea, skill Vs 1 video of seven subjects in which it is easy to get lost, confused, bored, stuck and forget altogether. Your videos are great and better than nothing (thank you for them) but focused videos might be a better idea

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    I agree to a certain point - I'm actually working on focusing my videos more at the moment. It's a balance though between focusing on a single thing but still allowing for enough depth. Sometimes, too much focus can lead to content with too little informational value. And I'd like to avoid that :).

  • @williamwatkins6669
    @williamwatkins6669 Жыл бұрын

    regarding the last code smell. I actually learnt from mcodes (kzread.info/dash/bejne/hGxh0aOqc8qukco.html) that you can force the user of a library to use keywords by using the * in the arguments. Can be handy

  • @ChazAllenUK
    @ChazAllenUK2 жыл бұрын

    "So here's a warning..." ROFL

  • @Manas-co8wl
    @Manas-co8wl Жыл бұрын

    Lol people complaining about the word "code smell" as if he invented it when it was a programming jargon since the stone ages (when code really did smell btw..)

  • @abdulahhi
    @abdulahhi2 жыл бұрын

    goats milk?

  • @PeriOfTheGee
    @PeriOfTheGee2 жыл бұрын

    You used named arguments for all 3 `LineItem`s, but shouldn't doing it just for 1 be enough to let the developer know which argument means what? Of course, as a devils advocate, I can say that they could all possibly be in a different order than in the ctor, but no sane person would do that while still indicating only one of them with named arguments.

  • @ArjanCodes

    @ArjanCodes

    2 жыл бұрын

    It might be enough but it’s also hard to do this consistently because any argument following a named argument also has to be named. So you can only do this if you want to clarify it for the last few arguments, in which case you can keep the first ones unnamed. Overall, I tend to use unnamed arguments for simpler functions with one or two arguments, and named arguments for anything else, or when it’s a function with arguments of the same type.

  • @grimonce
    @grimonce Жыл бұрын

    Great explanations and implementation, I however don't like the tabnine as a sponsor :/ I've heard some worrying things about tabnine and tried it myself, quite bloated. Tabnine is not open about its methods and there really is no reason to trust it. It is advertised however and people will start asking you to use it in your professional environment - bad influence on our community...

  • @ArjanCodes

    @ArjanCodes

    Жыл бұрын

    Thanks! It's been a while since I did this video and I thought Tabnine was a nice tool at the time I recorded this, but perhaps things have changed since then. I don't think Tabnine is less open about their methods than other companies though, or am I missing something?