I remember the fad for dependency injection frameworks in ruby, and the eventual similar pushback pointing out you could just use the language features for most of it
Design patterns you should unlearn in Python
91–100 of 110 posts
Re: Design patterns you should unlearn in Python
#92He didn't mention the worst pattern, the visitor pattern, which has extremely few use cases.
The value of the visitor pattern is that it lets you emulate tagged unions in languages that don't have them (e.g., Java 16 and earlier). Of course, Python has no need of this because you can check the type of anything at runtime and the optional type annotations also support union types.
Re: Design patterns you should unlearn in Python
#93I was writing a python thing where the class was going to have like at least 20 paramaters to configure it. Builder pattern was kind of feeling like a good idea to keep it cleaner for the user. But it is surprising to see in the python world. It felt like a mess of default values though for the user to handle.
I like method chaining (not the same as builder patterns) for code that needs to run chained operations on objects. It is not exacrly the same because each chained operation usually does more than just setting a variable. E.g. signal = Sine(freq=440.0, amp=1.0) .rectify() .gain(2.0) .center() .clip(0.5) Each of the methods may return a Signal object that can get processed by the next function, allowing you to chain t…
Re: Design patterns you should unlearn in Python
#94I remember the fad for dependency injection frameworks in ruby, and the eventual similar pushback pointing out you could just use the language features for most of it
When I first heard the term "dependency injection", I spent quite a bit of time trying to understand it. And then when I was pretty sure I had grasped it, I felt even more confused. "Isn't that just... passing an argument to a function instead of having the function access the information from global state? ... Isn't that normally what the function should do?"
1. there are certain dependencies that it was natural to access as global state - e.g. there is typically one stdout in a program and most code just prints to it 2. a class often hard codes constructors for its internal state, e.g. if you have a Graph class it would likely have associated Edge and Node classes that it calls internally to create new edges and nodes.
the big issue with both those is testing; if you want to mock the behaviour of the print statement, or you want a graph to hold nodes that track their own creation, or whatever, you have no way of overriding the internal constructors your class uses. hence dependency injection, the idea that e.g. a graph class would be defined with a node interface and you would pass it a concrete class when constructing it (some languages have type parameters for this, but even if they do you might not think to make something as simple as the node class used internally by the graph a type parameter, and more importantly you might want to set it at run time rather than compile time).
the issue was not that ruby didn't need dependency injection the concept, it's that it didn't need the sort of dependency injection frameworks that more rigid languages like java needed, you could use ruby's built in features to do the same thing.
Re: Design patterns you should unlearn in Python
#95> Okay, maybe you want to delay creating the object until it’s actually needed — lazy initialization. Still no need for Singleton patterns.
> Use a simple function with a closure and an internal variable to store the instance:
The given example does not actually defer instantiation, which would be clear to anyone who actually tried testing the code before publishing it (for example, by providing a definition for the class being instantiated and `print`ing a message from its `__init__`) or just understands Python well enough.
But also, using closures in this way actually is an attempt to implement the pattern. It just doesn't work very well, since... well, it trivially allows client code to end up with multiple separate instances. In fact, it actually expects you to create distinct ordinary instances in order to call the "setter" (instead of supplying new "construction" arguments).
So actually it's effectively useless, and will just complicate the client code for no reason.
Re: Design patterns you should unlearn in Python
#96Earlier quoted context omitted.
When I first heard the term "dependency injection", I spent quite a bit of time trying to understand it. And then when I was pretty sure I had grasped it, I felt even more confused. "Isn't that just... passing an argument to a function instead of having the function access the information from global state? ... Isn't that normally what the function should do?"
there are at least two separate use cases I can think of; 1. there are certain dependencies that it was natural to access as global state - e.g. there is typically one stdout in a program and most code just prints to it 2. a class often hard codes constructors for its internal state, e.g. if you have a Graph class it would likely have associated Edge and Node classes that it calls internally to create new edges and n…
Right, but that's still just a generic instance of "plan ahead to use a parameter (possibly with a default value) instead of grabbing something hard-coded". I don't see a proposed fix for a class that was already designed to expect its own inner node implementation instead of an abstraction, except to rewrite it. Which is why it confused me, because the rewrite would just involve adding a parameter, so that you could pass an argument to it, and making the implementation use that parameter. I suppose in statically typed languages you might have to actually define an interface type for that parameter, whatever. None of that explained to me why the Java guys were talking about needing a "framework" to accomplish this, that apparently somehow involved a ton of XML.
> the issue was not that ruby didn't need dependency injection the concept, it's that it didn't need the sort of dependency injection frameworks that more rigid languages like java needed, you could use ruby's built in features to do the same thing.
Yes, it's much the same in Python. (And yes, I have for example used `print` as an argument to a higher-order function before.)
Re: Design patterns you should unlearn in Python
#97Re: Design patterns you should unlearn in Python
#98I have observed these "design pattern shoehorned into Python" so many times ... Great post. When you see these things done in a code base, you know that you got people, who would rather want to write Java working on it. Or maybe people who don't have the feel for Python as a language or something. First thing I looked up in the article was "singleton", as a sanity check, whether the article is any good. And yes, it s…
In fact, I've pissed off some people in interviews for holding this view. We aren't really that empirical as an industry about best practices.
Re: Design patterns you should unlearn in Python
#99I really appreciate how this article explains why certain design patterns became a thing. Usually, it was to address some very practical problem or limitation. And yet, a lot of younger programmers treat these patterns like a religious dogma that they must follow and don't question if they really make sense for the specific situation they are in.
The explanations are great! The condescension, not so much. > Simple: we just use the language like it was meant to be used. > Use Default Arguments Like a Normal Human etc
Re: Design patterns you should unlearn in Python
#100I really appreciate how this article explains why certain design patterns became a thing. Usually, it was to address some very practical problem or limitation. And yet, a lot of younger programmers treat these patterns like a religious dogma that they must follow and don't question if they really make sense for the specific situation they are in.
> I really appreciate how this article explains why certain design patterns became a thing. Usually, it was to address some very practical problem or limitation. I don't agree at all. I feel that those who criticise design patterns as solution to practical problems are completely missing the point of design patterns, and the whole reason they have the name the have: design patterns. I'll explain. Design patterns are…
It sounds like they've not had to use it for any meaningful work, and basically described a constructor. Yeah, named parameters are great, and I miss them when I don't have them, but if you think a builder only works like this
Object.setX().setY().build()
Then it tells me that you haven't built anything meaningful. It's a way of building a state and running an operation at the end in a contained manner. If your build method doesn't run some sort of validation then it's probably a waste of time, might as well just call setters, return this and call it a day if you want to be verbose and chain commands.