Given some examples, I'll do a follow-up blog post.
Given some examples, I'll do a follow-up blog post.
Regardless:
pathlib.Path:
- https://docs.python.org/3/library/pathlib.html
Django's class-based views and mixins:
- https://docs.djangoproject.com/en/3.1/topics/class-based-vie...
- https://docs.djangoproject.com/en/3.1/topics/class-based-vie...
Hell, you don't even need to look into other code. Just use the sample from the article.
What if client_a and client_b write to different APIs? One expects authentication, the other has pagination and rate limiting. Actually, one of them returns XML. Their URL structure is completely different.
Classes are great when you want a bunch of different things to produce a similar result. You don't care how the client fetches and transforms data, as long as it returns it in a certain format.
For example, you might want TwitterTweetSource.get_items() and FacebookPostSource.get_items() to both return a list of Posts that have certain attributes. The implementation details don't matter; you just want these methods to have the same signature, because you call [s.get_posts() for s in source_list]. Maybe you'll add FacebookCommentSource, which reuses the same authentication strategy, but on a different endpoint.
I was hoping the code in the article would form (an admittedly small) piece of evidence. I'd just really like someone to show off a nice neat counter example, that demonstrates the true beauty of Python OO, and is "unrefactorable" to a data types + functions equivalent.
Pathlib is a great example, maybe a canonical one, of:
> Very occasionally, you come up with a core type that's used so often, it's nice to have the cutesy stuff.
Django's class based views I think could probably reasonably refactored into data types + functions. I'm not too au-fait with Django or its internals, but if someone could send me a "demonstration Django clone in 800 lines", I'd give it a go.
> What if client_a and client_b write to different APIs? ...
Then you use an if statement to split at that point. Again, given a specific toy example, I'm fairly certain a reasonable refactor is possible.
This quickly falls apart as the difference between the classes grow. A view that turns a Facebook API call into Post-like Facebook objects has very little in common with a view that turns Twitter API call into Post-like Twitter objects. Doubly so if you factor other parts of the request like authentication, pagination and rate-limiting. You'll need a bunch of if-else statements in a bunch of different places.
This gets even hairier when you need to test that code. It's a lot easier to make sure a FacebookView calls the right endpoint and returns the right data, than to test every path of a combination of if-else blocks.
And what if you want to extend this code, but don't have control of it (external module or different team)? It's easy to extend parts of a class that do exactly one thing. It's not easy to extend big if-else block without overwriting it.
I have seen the benefits of this approach first-hand. We got more reliable code and better test coverage with less effort, and greatly simplified maintenance and development.
> I'm fairly certain a reasonable refactor is possible
To what benefit? There is already a nice construct for self-contained objects that offer a similar interface, that can be inherited from, and that can be unit-tested. Objects.
As a bonus, there's no need for inheritance in python due to duck typing.
Still the state and the functions that operate on them can be separated out. Right? No reason why the state and the functions need to be tied together inside a class.
Things like
- Maintainability
- Extendibility
- Testability
- Reusability
etcOne problem with OO is that you can organize your code in many different OO styles and somewhat depending what you try to achieve you should pick a style matching that.
Personally I think your example is not separated enough,
- Client configuration
- Url construction
- Reading data from API
- Saving data
In the first example everything is mixed up in one class, it is like having a huge main function. I would probably have three different classes to solve that.I'm not sure how you would go about replicating similar async/await sugar without tying functionality to Task instances but I'd like to see it.