NHL Finns Project

elixirphoenixpostgresqldevelopmentpreactdigital ocean
NHL Finns site

This post is about a site I created as a side project: NHL Finns

I’m a huge NHL (hockey) fan and want to be able to follow the scores and stats effortlessly. As with all North American sports, the games usually start during the night time in Europe and I’m eager to check the results in the morning after the games have ended. If I happen to be awake when the games are ongoing, it’s important to get real time updates to the scores. Also, as I’m Finnish, I’m especially interested in seeing how the Finnish players did in the games.

Many of the apps or sites available are a bit heavy or do not highlight how Finnish players did (and why should they?). Some places are also quite heavy on ads. This led to a idea to create a lightweight solution for just checking the content that I wanted to see, i.e. results of last night games and main stats categories. I know it’s useful for me and it might also be useful to other people. As for any side project, an important factor for me is that I want to use it as a learning experience to work with some technologies that I enjoy and believe are a good fit for the problem.

Requirements

Some high level requirements that I came up with are in the following list:

  • Clean UI
  • Quick access to results
  • Providing other supporting information that a user could be interested in, for example “player X scored two goals last night, I wonder how is he doing in the top scorers list now”
  • Score updates while the games are ongoing without page reloads
  • Responsiveness, needs to work well in desktop browsers and mobile

Architecture

I’ve been working on some projects lately with Elixir and the Phoenix Webframework and it seemed ideal for this job, especially taking into account the excellent WebSocket functionality. Read more here about a test where the team run a benchmark with 2 million connections against one (big) Phoenix server.

I wanted the site/front-end to be light-weight and after reading about the approach the Changelog.com had taken with their site, decided to use a similar approach to how the pages are rendered. I decided to add Preact, which is a lightweight alternative to React, to the mix to build the score board components but still keep the page weight low and to enable adding more UI functionality later on. It also fits well with how the data updates come in via WebSocket messages and components get re-rendered when the global state is updated.

The site is built as an Elixir umbrella app with three apps:

  • web  -  Phoenix app to serve the pages and send score updates to clients
  • feed  -  Polling game and player data from MySportsFeeds
  • data -  DB (Postgresql) access and operations

MySportsFeeds is a great data service for major North American sports leagues:

The BEST source for democratized, crowd-sourced sports data with a real-time API

Retrieving data from the feed and serving the data to clients are separated so that each client gets the data as fast as possible. A GenServer holds the data in memory and handles updating it from the feed and serves it to clients without having to fetch the data from a database. When the data in the DB is updated after polling, a WebSocket update message is sent to the clients and the scores are updated without reloading the page.

Page Rendering

Page rendering depends on the page. For plain statistics tables, the page is rendered server-side directly by Phoenix. This could change in the future if the tables need to be more dynamic but for now it seems like a reasonable approach. For the main score page the data is inserted as JSON in the page, which the Preact components then render.

Navigation

Similar to Changelog.com, navigation between pages uses Turbolinks, which enables loading to a new page without full page reload similar to single page applications, even though this is not a Rails app (see this post for more background). I recommend also reading more background on how they built their site here.

Building releases and deployment

Another great element of Elixir and OTP projects is the deployment and hot upgrades of an app. In this case, I’ve chosen to use distillery and edeliver for building releases and deploying the server(s) (distillery is a dependency for edeliver). The server setup is done using Ansible from operating system setup and installing packages to creating users and the database and setting up the Nginx web server.

There are two ways of deploying an app: full release or an upgrade. The main difference is that an upgrade can be done without any interruptions to the site while a release causes some seconds of downtime. Creating a full release and deploying it consists of the following three steps:

$ mix edeliver build release — branch=<branch name>
$ mix edeliver deploy release to production
$ mix edeliver restart production

For an upgrade release, the following commands are required. Both of the versions also need to be tagged with git tag.

$ mix edeliver build upgrade — from=v0.1.6 — to=v0.1.7
$ mix edeliver deploy upgrade to production

What’s Next

It’s fun to fiddle with side projects and spend some time on them when the time allows. While I’m happy with several aspects of this project, at least the following things are on the cards:

  • Fixing some bugs
  • Adding new features to make the site more comprehensive what comes to player stats
  • Styling of the site could be cleaned up a bit
  • Google Lighthouse results for a progressive web app should be improved

Summary

I’ve been very happy with all the tech used in this project. It feels easy to extend the current functionality and fix problems I’ve encountered. Also the performance is great for a small Digital Ocean box. This is going to be my default stack for future projects.