3 ms·
100%. Recently I've been frustrated with the Python ecosystem and how many "object oriented" libraries there are which can't easily be tested because of all of
by throwaway894345 5y ago
100%.
Recently I've been frustrated with the Python ecosystem and how many "object oriented" libraries there are which can't easily be tested because of all of the weird shit their constructors do (most recently, the class I'd like to test just builds JSON documents and sends them to an API, but the constructor hard-codes the HTTP client so you have to use magic to swap the hard-coded client with a mock).
Of course, someone will come riding in to defend OOP with "that's not true OOP" and another will come riding in to defend Python with "you can write bad code in any language!", both of which miss the point: this sort of thing is much more prevalent in the Python ecosystem than, say, the Go ecosystem or the Rust ecosystem precisely due to culture. And by the way, I'm sure there are lots of other languages that have a culture of poor programming practices--the intent here isn't to pick on Python (I've used it professionally for 15 years).
- deleted 5y ago[deleted]
- AmpsterMan 5y agoI wonder to what extent these problems have to do with OOP being poorly defined vs poorly understood vs poorly implemented.
- throwaway894345 5y agoBy the way, if anyone is curious what a really terrible constructor looks like: https://github.com/jupyterhub/kubespawner/blob/81e6059a1481138d27d0d3c32f403ecd21d576d8/kubespawner/spawner.py#L157-L228 https://github.com/jupyterhub/kubespawner/blob/81e6059a14811... ^ I'm also curious to hear from people whether this kind of design is "OOP" or not, or if there are any good terms for talking about this particular antipattern.
- blandflakes 5y agoI'm not really an OOP or Python defender, and generally agree that this type of constructor is inscrutable, frustrating, and quite common in the Python ecosystem. That said, I would not consider default mock values in a constructor to be good OOP. In general, "new"ing things in a constructor IMO is a no-go and makes for harder testing and confusing behavior. At the end of the day I'm not even sure why this class supports mock behavior. I'd expect two separate classes with divorced implementations, instead of an if statement on a boolean param.
- lamontcg 5y ago"Don't do work in the constructor" is an OOP principle that must be decades old. The problem with Python and Ruby is that being dynamic it makes them real easy to do highly lightweight OOP. There's just a cultural disconnect in the OO world where once you get past objects wrapping data the design patterns tend to come from the Java world and quickly descend into explaining dependency injection containers that nobody uses in Python or Ruby. There's a bit of a cultural middle ground which is not well defined due to the history of how it all evolved.
- Tozen 5y agoThis is why I like how various newer languages such as Go (golang) and V (vlang) or prototype languages like JavaScript or Lua have approached OOP. V even allows to easily choose if you want it on the stack or heap. With these languages, there is either no class-based OOP or classes are optional. "Freedom of choice", is way more obvious. Maybe a "shout-out" for Object Pascal in this regard too, as they have advanced records (structs with methods) and Free Pascal has simpler objects (but Delphi's dialect doesn't). Though I will say, Object Pascal's implementation of class-based OOP is a gentler version, versus the "harsher" implementations in other languages. Still, as with all the class-based OOP languages that I've seen, you are going to get forced feeding and forced to use plenty of OOP libraries. Forcing or pushing class-based OOP is debatably how things can more easily and unnecessarily go bananas. Complexity traded for simplicity. Users are usually trapped in the paradigm, until they like it (programming version of Stockholm syndrome?), and are often scared to go outside of it or think the world might end if they do.