Live data from Hacker News

Design patterns you should unlearn in Python

lihil.cc

51–60 of 110 posts

Re: Design patterns you should unlearn in Python

#51
post #24

I 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…

Module-level initialization has one huge problem in Python, though. That means that as soon as you import a module, initialization happens. Ad infinitum, and you get 0.5s or more import times for libraries like sqlalchemy, requests...

Initialization only happens once, when you import the module for the first time, afaik. Unless you are running multiple Python processes, that is.

Re: Design patterns you should unlearn in Python

#52
post #43

Earlier quoted context omitted.

> Great post. Now let's do C# because if I see a repository pattern doing nothing but calling Entity Framework under the hood again I'm going to rip the planet in half Your comment shows a hefty amount of ignorance. Repositories wrap Entity Framework because Entity Framework's DbContext & Co are notoriously complicated to mock and stub. Once you wrap EF stuff with a repository that implements an interface, that probl…

We don't really have this problem in .NET 8, we mock stuff just fine using an in-memory database provider. But I admit my tone missed the mark. It may have been much harder to do in the past, or maybe I'm missing some nuance. But also at this point why not just have your DbContext directly implement an interface that you can mock? Surely that must be more straightforward than adding an entire abstraction layer, that…

> We don't really have this problem in .NET 8, we mock stuff just fine using an in-memory database provider.

No, you don't. At best in-memory databases represent a test double that you can use in integration tests.

If you need to write unit tests, EF leaves you no better option than to add repositories to abstract out everything and anything involving DbContext.

Re: Design patterns you should unlearn in Python

#53

Builder patterns are seriously useful for high complexity state construction with the ability to encore rules to prevent degenerate state. A good example from my experience might be connecting to a Cassandra cluster it other type of database that can have extremely complex distributed settings and behaviors: timeouts, consistency levels, failure modes, retry behavior, seed connector sets. Javaland definitely had a pr…

In my experience everyone will hate on Spring, showing how much easier other frameworks are using tiny unrealistic examples, until they hit a really hard architectural challenge (imagine reimplementing @Transactional in pure Java) and that's where Spring shines.

Yeah, it's sad, I like Groovy a lot. It got relegated to a second-class citizen role on Jenkins, for the most part.

Re: Design patterns you should unlearn in Python

#54

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. 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…

I see you’ve been downvoted.

Design patterns aren’t solutions to common design problems. They’re after the fact descriptions of solutions for design problems. That’s the issue. That’s the beef. Everyone thought of that book as a cook book instead of a naturalists’ musings on an ecosystem, which is what they are.

Those of us who designed before people discovered that stupid book were constantly asked what the differences were between this pattern and that. And the book just isn’t thick enough and Eric Gamma was just trying to complete a thesis not write a book, so despite having at least 8 years in industry before completing his masters he cocked it up. And ruined Java in the process.

We had a contemporary of Vlissades teach a class at my last company and he crystallized all of my suspicions about the GoF book and added a whole lot more.

My advice for at least fifteen years is, if you think you want to read GoF, read Refactoring instead. If you’ve read Refactoring and still want to read GoF, read Refactoring a second time because it didn’t all sink in.

Refactoring is ten times the value of GoF for teaching you how to do this trade and how to break up architectural brambles.

Re: Design patterns you should unlearn in Python

#55
post #14

I 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.

Good example for Python not needing this pattern sometimes is Pulumi. Check out the differences between example code in Java and Python.

https://www.pulumi.com/docs/iac/get-started/kubernetes/revie...

In Java (or even Go) this pattern is required to enforce type safety. In Python it seems that they ignore the typing part and just pass a bunch of dicts. Looks much cleaner, even if not entirely typesafe.

Re: Design patterns you should unlearn in Python

#56
post #45

I don't agree with the builder pattern. For basic objects yes its a bit silly. But the ACTUAL value of the builder pattern is when you want to variadically construct an object. Create the base object, then loop or otherwise control flow over other state to optionally add stuff to the base object. Then, additionally, the final "build" call can run validations over the set of the complete object. This is useful in case…

Couldn't you build up a dictionary of keyword arguments instead and do all the validation in the __init__ method? E.g. kwargs = {} if is_full_moon() and wind_direction == EAST: kwargs["baz"] = 42 thing = Thing(foo=3.14, bar=1, **kwargs)

Builders have some neat properties like partial evaluation, which becomes especially neat when you use stateless builders that return new instances. They can also be subclassed, allowing not only behavior that can be overridden at individual method granularity, but able to build a different subclass.

Obviously don't reach for a builder if you don't have these use cases though.

Re: Design patterns you should unlearn in Python

#57
post #29
post #14

I 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…

This also greatly increases API discoverability, because I can just type "." and see the IDE pop up me all the options right there, no need for docs.

Re: Design patterns you should unlearn in Python

#58
post #40
post #28

Earlier quoted context omitted.

yep, the legacy codebase I maintain does a lot of this kind of stuff and has made it difficult to write unit tests in some cases due to all the code that runs at import and all the state we end up with

The article addresses this.

I know, I'm just complaining about the mountain of code that does this at my company. And there is no fixing it using the article's approach or any other for that matter due to the sheer scale of the abuse.

Re: Design patterns you should unlearn in Python

#59

I've never seen anybody do that... In Python you can use a module as a singleton (mentioned in the article). Or provide some data like: from functools import lru_cache class Whatever: pass @lru_cache(maxsize=1) def get_whatever(): return Whatever() And use `get_whatever` as your interface to get the resource.

I do this in fast api and then pass get_whatever as a dependency to an endpoint

Re: Design patterns you should unlearn in Python

#60

Earlier quoted context omitted.

How does Python do mocking if it doesn't use singletons? Or do people just not do unit testing in Python using spock-like technology? And I do use the word technology because Spock is that much better than just a bunch of test scripts

You can overwrite pretty much anything in Python at runtime, and the mock tooling in the standard library can help you with that, if you can't straight up just override a method or object.

Global vars?

So with a Singleton what you can do at least in Java land is have your service invoke the method to get the Singleton semi-global object.

So you can mock that method invocation to return a different object. So you basically have the local object to play with in your test and won't be affecting any actual real global state

But basically the article was just saying just use global variables. Does python have a means for then intercepting the value request and data assignments for that global variable for the local scope of the testing code? Or is it hardwired like a global variable, presumably is?

Post reply on HN