Edit 1 (12/19/2020): I changed how filters placed their content and defaulted the base content filter to place its content at cell (1, 1). This allowed me to implement vertical and horizontal stacking based on the previous blocks content size. I added an example of that class below, along with the base content filter I implemented.
Edit 2 (12/30/2020): I added the code for my vertical stack filter at the end of the article
AI hype is everywhere in the tech landscape today, and there are many rumors and falsehoods about it's value. It feels like everybody from large corporations to aspiring startups are lunging at the opportunity to insert AI into their tools and products to capture their share of the tech angel investing budget.
Personally, I think that AI is a crucial tool, but like any tool, it has its good use cases and then use cases that it just doesn't excel at. Maybe this statement will age like milk in the future, but I'm fairly confident that AI in March 2025 is a glorified text generation tool. However, like any tool, I do realize that my own bias comes from the bad anecdotes I've seen in person and read online. I don't actually understand how AI works behind the scenes, I just see the final "products," even if they aren't necessarily applied to the correct or appropriate use cases. So, I set aside some time this spring to truly sit down with a good friend of mine and genuine learn what AI has to offer and how it works at a lower level.
But first, let's check out some final graphs showing the data + context I used to keep everyone engaged. This same context eventually is fed into the ML training loop and used to train the AI.
Backstory
Early into my refactor of Skirmish's tournament backend, I realized that I needed to make fetching and updating the bracket as quick and efficient as I could on the frontend. I ended up doing a lot of research into how I could speed up my queries to the database, but I also was reading a lot about caching and using in-memory storage to store and serve data instead of querying the database every time. However, there was one problem that I never really liked about Django's built-in caching system -- it lacked support for clearing a view's cache and forcing a recalculation of the data.
So, to give a clear example in tournament terminology, let's say that a player had reported the results for their match, and the match advanced the winner and the loser to their next respective matches. After this, if the bracket were to be requested again, django's built in @cache_page decorator would create a cache key for the request, look for it in our cache before performing calculations, grab the old data and serve it to the user. To show specifically why this is the case, let's look at @cache_page's key creation implementation:
I sometimes pause during the day to laugh at how much like my father I am becoming. There are many times when I catch myself thinking or acting in a way that I know he would and it makes me reflect on how much wisdom was in a lot of his actions. Pops, if you're reading this - thank you.
I remember being younger and scoffing when he brought up the idea of getting security cameras for their new house. My whole life my parents have lived in remote locations with lots of land, so the idea that someone would travel out into the country to find a single door on a single house seemed foreign to me. Also - once criminals were out there in the country, they likely had already decided to commit a crime. What would video cameras do to prevent it?
However, what I had not considered at the time was that the idea was not to prevent the crime from happening, but rather know about the crime quickly and respond immediately. Crimes are often unpreventable and unavoidable - it often comes down to bad luck. The idea is knowing when you are unlucky.
So, naturally, as I began my journey of self-hosting software I use daily, I began to wonder...