4 ms·
> No. It's that when people who prefer type systems go to use a popular dynamic language, they try to drag in features that they like from other languages. Ver
by gklitz 2y ago
> No. It's that when people who prefer type systems go to use a popular dynamic language, they try to drag in features that they like from other languages.
Very much. The “problem” people try to solve with things like dependency injection isn’t even a problem in python. 99.99% of the time you can just import you dependencies everywhere they are needed.
So many times now I’ve had to unteach bulky OOP patterns for people coming from strictly typed languages to python believe are “good practices” or are “needed for reliable code” and you go from 20 different interdependent classes down to 3 functions that just directly do what they are supposed to do.
And you always end up with someone being disappointed that all of these complex patterns they learned to solve problems that don’t exist in python aren’t needed, rather than someone just happy that you can proceed directly to a value adding solution and skip the crud and design pattern spam.
And then they start arguing crazy stuff like the 200 extra lines unneeded code makes the solution “more readable” or “more reliable”, when in reality it’s just a desire to use the solutions they are used to even when the problems don’t exist.
- indigo945 2y ago> The “problem” people try to > solve with things like > dependency injection isn’t > even a problem in python. > 99.99% of the time you can > just import you dependencies > everywhere they are needed. That's... Just not the problem DI fixes in any language? Sure, in C++ or Java you can just create a global static instance and use that everywhere. That's pretty much equivalent to just importing the same thing everywhere. But the downside of both approaches is testability: it becomes much harder to test units in isolation when they access global resources. Consider a function with `import datetime`, that gets the current time and does something with it. You want to make sure that this function still does the right thing in the extreme case of the current time being 23:59:59. How do you write this test without DI?
- wizzwizz4 2y agoEasily. from datetime import datetime, timedelta def f(): now = datetime.now() future = now + timedelta(seconds=1) return now.time() < future.time() from unittest.mock import patch with patch('__main__.datetime', spec=datetime, side_effect=datetime) as mockdt: mockdt.now.return_value = datetime(2024, 10, 3, 23, 59, 59) assert f() If `datetime.datetime` were implemented in pure Python, one could even use `patch.object` here, saving a line.
- Hackbraten 2y agoI feel reluctant about mocking types I don’t own, and prefer small, tailored abstractions instead: from datetime import datetime, timedelta def f(now = datetime.now): timestamp = now() future = timestamp + timedelta(seconds=1) return timestamp.time() < future.time() def mockdt(): return datetime(2024, 10, 3, 23, 59, 59) assert f(mockdt) Admittedly, this approach adds _some_ noise to the function signature. On the other hand, it feels more honest. It makes it unmistakably clear that this API relies on, and uses, some external state. Also, this approach scales poorly with the number of dependencies, and that’s a good thing. If `f` were to also depend on a `db_connection` in addition to `datetime.now`, then this pattern automatically alerts the API designer that it might be time to redesign `f`.
- indigo945 2y agoExactly! And now you've invented Dependency Injection. That's all DI means, passing dependencies to where they're needed instead of pulling them in via global state. You're doing it by hand (and in an impure way) instead of relying on an IoC container for convenience, but it's still the same thing.