My latest side project: Finished Games

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. You can also check a live demo at https://finishedgames.kartones.net (to me the most useful part is the user catalog). Note: Game and Platform catalogs are not totally imported yet, just a few hundred samples to do some real usage scenarios.

The tech stack is mainly Python 3.5, Django 2.1, Docker & 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 Javascript so I wouldn't consider it a "main" technology (be advised it uses 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 run, make test, 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, Coverage + Pytest-cov, plus the code is fully type-annotated so there are MyPy & 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 make test.

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: Finished Games main site screenshot

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... Finished Games admin screenshot

Everything that can be configured using existing ModelAdmin features is done, like list_display, list_filter, search_fields, readonly_fields or ordering.

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): Django command example output

Settings files use a simple hierarchy: base.py defines things, then dev.py, test.py or 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 FetchedGame and 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".

As the README mentions, there's a roadmap but is the only thing I'm keeping private for now, as I want to work on this project at my pace, with my rules and as much as I want/decide to. For example, initially I was decided to migrate it to Django REST framework and React/Redux for a version 2.0, but now I'm not totally sure I'm going to do it, as a classic/non-SPA approach is working so nice for now (and I can just do any other side project focusing on Javascript). That doesn't means that if somebody leaves issues, pull requests or comments I will ignore them, far from it, but my priorities might not be the same as others.

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.

Posted by Kartones on 2019-03-16

Comments? Share via Twitter Share via Linkedin