This post is a mere declaration of intentions and brief explanation of where I spend lately not-tiny-but-neither-huge blocks of spare time when at home. Still, can be of some interest if you do Python and Django.
I won't enter into details of the project purpose (you can read it) other than mentioning that Finished Games is a small website to catalog and track your videogames playing history.
The tech stack is mainly
Docker-compose (for testing and development, not required for production). It only has at the time of writing this blog post less than 50 lines of
ES2015 without polyfills on purpose so no old browsers neither IE). In local it uses
SQLite for storage.
Everything is dockerized to ease testing and not polluting your computer with Python packages you might not desire to keep. Initial setup requires you to run the migrations (for now, I want to add a first-run aware bootstrapper) but other than that, [commands are as simple as
make coverage, etcetera. Check the README to see many of them in action.
Regarding Django the project includes installed
django-debug-toolbar but with just a few modules, mainly to be used to detect unoptimized queries. I would recommend it to be switched off in production, it's easily configurable.
Testing is done with
Pytest-cov, plus the code is fully type-annotated so there are
Flake8 "linter tests" so tests won't pass if you don't type the code or have it clean (almost no custom rules except 120 chars line length and default double quotes). Continuous integration is using CircleCI and just rans the same tests as
I'm doing my best to build the code in a legible, pythonic and simple (I'd add "clean" but not in the craftmanship meaning) way. It is an ongoing effort, and as I'm iterating quite fast from an initial MVP sometimes a piece of code might be pending some deeper testing or refactor, but in time it will come.
The code includes as many Django best practices as I'm being able to apply, from avoiding N+1 query problems using
.select_related(), how to properly instantiathe the defined
User auth model (did you know you it can be overriden so you should never directly import the model?), statics configuration for development and production, class-based views for non-trivial views (or multi-verb HTTP endpoints), named url paths...
I'm very pragmatic so I didn't wanted to reinvent any wheel if not needed. That's why I've chosen simple yet beautiful CSS:
But also by trying to do as less as possible I'm heavily relaying on Django Admin to all the CMS management, only extending it with extras I really need to build: Custom actions, custom filters (including context-based smart filtering), field decorators, hand-made views...
Everything that can be configured using existing
ModelAdmin features is done, like
Instead of the classic
scripts folder so prone of becoming a dumpster, I'm sticking to Django commands for any operation, django migrations for any database change (even if is a mere DB field description/comment update):
Settings files use a simple hierarchy:
base.py defines things, then
prod.py (not included, but provided a
prod.py.sampl placeholder) inherit from it, and optionally if you define a
local.py it can override
dev.py values (handly for testing some production setting locally, careful to not abuse or pollute it!).
There are some tests and many more will come once I reach the point of being able to import hundreds of games quickly (really only remains a batch import feature, as one by one import is already implemented), after all code coverage wasn't added for nothing. Pytest plugs correctly to django so coverage is accurate (at least more accurate than not properly configuring it). As the first catalog source adapters are defining both the fetch/import API and the database structure in this case I'm prioritizing quick iteration and manual verification over tests. Once settled tests will harden the code as much as possible.
Plan is not to do hundreds of view integration tests but a few ones will be provided to showcase how to test Django views (so my future self can easily remember how it's done). Similar scenario for Django Commands, I'll do some basic testing but won't mock the whole universe regarding data sources, instead focusing on testing
FetchedPlatform entities and their interactions with the import process.
The code doesn't contains any super-algorithm nor does anything clever, the coolest piece being a token bucket rate limit implementation (sample usage as a method decorator here) that mostly comes from StackOverflow and Wikipedia (at least the tests are built from scratch by me), but I've never been a brilliant mind creating amazing algorithms, I just "get shit done".
The license is Unlicense so you can do whatever you want except helding me liable for any problem :)
Ok, enough talking, show me the code and leave me alone! https://github.com/Kartones/finished-games
Closing up, I'm having a great time with the project as I'm combining building a tool I really want to use with being able to go deeper into some Python packages/libraries I don't use so much in my daily work. And for once it'll be a non-totally useless project to showcase on my Github profile.