Building Side Projects

07/12/202011 Min Read — In Code

I recently spent some time building a website called kitten pop. Check out the site here: kittenpop.net.

Building this game was really enjoyable. It involved not only engineering and product, but also recording and producing background music.

Listen to the song here:

I cannot recommend building side projects like this enough.

Why build side projects?

1) It gives us the opportunity to think about the applications we build overall.

In our day to day work what can happen is we can lose sight of the bigger picture. How our task fits into the overall application we are working on and also in turn how that application fits into the overall ecosystem it may belong to. For example, I may be working on a particular task, let’s say I am adding a new sign up flow to an application for a particular subset of users. How does this task fit into the overall idea and function of our overall website as a whole? What is the user journey and is it relatable? If we don't ask these questions, we may overlook an important consideration. For a crude example, what if our feature is already available and is duplicate? Or what if our feature needs an important addition that may be lacking and that fits into the overall experience and user journey that is intended to be fulfilled? Developing side projects on our own give us that perspective—helping us think like entrepreneurs.

This is applicable even at a much smaller scale—like with one side project alone. Thinking of the overall application and user journey as a whole can help your development by empowering you with considerations that may have been overlooked. Considerations that allow the small feature or change to fit into the overall application as a whole, thereby improving your user experience or offering a much smoother development experience.

“Expect the output of every program to become the input to another, as yet unknown, program.” - Unix philosophy, Doug McIlroy

Enhancing our perspective around the normal micro tasks we might perform in our day to day jobs as engineers, it encourages us to ask the hard questions we must ask when developing any application. What impact will this cause in our overall experience and platform?

Building side projects and taking them from an idea to fruition help to reinforce a broader vision around our sites as a whole and to instill a product and analytics perspective. The micro engineering tasks we might undertake when maintaining or building out features on prolific multipage apps can hide us from this broader view—we don't get to think overall about the product, like what our problem statement is, what value it delivers overall, and how it might fit in to an overall platform. When building small personal projects we get to think about the design, product and how these will tie into our architecture and library choices overall. We get to think like entrepreneurs owning the product from top to bottom.

2) It gives us the opportunity and flexibility to explore new technologies, techniques and to learn something new.

Have you been curious about a new and popular technology? Try building your project with it or including it when possible. Have you heard about a certain technique that might help in some aspect of your design or overall problem statement? Do some research on it and try it out. If it has good support and adoption you can be more confident in your implementation. Does it work? Great. If not, scrap it. Try something else. Repeat until you find a solution.

I tend to learn best by doing, and building out a side project with that cool new technology you've heard so much about can be a great way to learn it. Never understood the hype behind GraphQl? Build something with it.

3) It gives us the opportunity to identify technologies and features we enjoy working on

Did you enjoy working with that new technology you tried out? Lets say you built the game 2048 using Typescript. Did you enjoy working with Typescript? Do you think it might solve a particular problem that is often faced in your day to day job? Awesome! Apply it elsewhere, whether that be other side projects or your day to day work.

Building a side project: Kitten Pop

Here's our agenda:

  1. Overview and problem statement
  2. Architectural overview
  3. Deployment
  4. Hosting decisions
  5. challenges

Overview


The first thing to do in any new project is to understand what problem or need is being fulfilled. How will you provide meaningful content to users that will give them reasons to visit, and return, to your website. What problem and solutions are being proposed? These are important steps to consider. You must provide content that gives users a reason to visit, and return, to your site. Any good project kickoff contains an overview of the project with a problem statement and proposed solution.

Some may not be cognizant of the typical project or feature lifecyle. How do features get developed at your company? A great tool I like to use when working on my own projects is Notion. I couldn't recommend Notion any more. It has great templates, like one for Project Kickoffs. It gives you predefined areas for some important considerations when starting off a new project, like problem statement, proposed solution, success criteria, user story epics and requirements/scope. These are all important considerations when kicking off any project.

View screenshot of Notion template on Imgur

our problem statement (Kitten Pop)

  • Users can be frustrated when playing similar flash based games that contain bugs and other issues.
  • Similar games not available on mobile devices.
  • Flash is being deprecated
  • Cats are fun (lol)

Our proposed solution was to address these issues but while also giving the game a unique and creative design, with custom made background music.

Architectural Overview


For this project I chose to write it without the aid of a template system like Gatsby or Next.js, but to write it from scratch in React. I wanted to write the site using pure React state management using the context API for simple front end design changes and future growth around the app, and to also learn more about how a larger app like the ones I work with at PayPal could begin to strip away its extensive use of Redux for state management. Kitten Pop is a basic React SPA that uses pure React state management.

Libraries/technologies used:

  • React

    • Context API
    • Hooks
  • Webpack

    • CSS Modules
  • React DnD (Dan Abramov's library for drag and drop)
  • React Bootstrap
  • React Router
  • Netlify continuous deployment and static site hosting
CSS Modules

I am a fan of CSS in JS and for that matter CSS modules because of the benefits around maintainability, performance and scalability. When using CSS modules CSS changes are locally or globally scoped and so we reduce the chance of global style clashes with our library or others. This also helps with performance, because CSS can be split with the webpack module chunk. CSS can also be separated out into it's own file using Webpack's mini-css-extract plugin if we prefer, and this also comes with a lot of flexibility in that regard. In one of the apps I have worked on we have separated CSS into separate files based on a recursive issuer for that CSS file, or based on the first issuer of the request for a particular file (using mini-css-extract plugin). This allows us to code split and deliver CSS based on the particular flow it belongs to within our application.

CSS modules also allows us to confidently refactor/maintain CSS because we know exactly where each style implementation is used because styling is locally scoped to each module if used correctly. This means that styles are imported directly into the file where they are used, and added inline. We don't have to worry about removing CSS for fear that it is used by an unkown module.

This project uses both global boostrap styling (only bootstrap library is global) and CSS modules for individual components to reap benefits of CSS in JS. I use Webpack's CSS-loader for css modules. Here is a great article comparing the benefits of many CSS in JS libraries: https://github.com/MicheleBertoli/css-in-js. I'm a fan of this technique of both global css with css modules and may take this up soon in other projects of mine.

Pure React state management

Often all application state ends up in in our Redux store. It is simply convenient. While developing we may think to ourselves, "this new information I am adding can be used in the future in other components! I'll add to our global state just in case." so everything ends up in global state, and also consuming that global state. But, there are some performance and readability issues here. Regarding performance, every component that consumes that application state must re-render. This can be a problem if there are multiple components or expensive rendenders happening in your app. Users on older devices might be especially vulnerable here. One other implication is that developers need to track application state throughout the app and throughtout the global state lifecycle. In many apps I have worked with, this means that there is one or two global containers that pass down state for all child components within an entire multipage web app. :/

Kent Dodds has some great articles regarding both state management with pure react and also how to use the context API effectively: https://kentcdodds.com/blog/application-state-management-with-react https://kentcdodds.com/blog/how-to-use-react-context-effectively

Deployment and hosting


A few important things for me were 1) cost, 2) ease of development and 3) continuous deployment with Github integration.

I chose Netlify for our deployment platform (what this site is hosted on). Netlify's Github integration and tooling is seemless for continuous deployments. To fix or add a change, pushing changes to Github and then a 40 second automatic build and deploy is all it takes. Changes are live basically immediately. And it's totally free, supports custom domains, and also HTTPS.

There also had to be hot module replacement for both modules and CSS. Developing this app had to be quick (I work full time after all), and so hot module replacement was mandatory. This made developing the app a joy. In both my apps at work and in personal projects, Hot Module Replacement is by far worth the investment.

I couldn't justify the need for SSR (Server-side rendering) for this project, and also by having a statically built site hosted by Netlify (with no backend), this was out of the picture until our budget got a lift. Netlify also supports serverless functions, which I use with this blog site to handle things like form submissions or newletter signups. I plan to use serverless to build a leaderboard in the future and the fact I can accomplish this without a hosted server is attractive. Serverless designs use only the resources necessary. For now, our leaderboard is hosted by Heroku and is a basic node REST API that uses redis only for the backend.

Right now our total cost is $12/year for the domain. Turns out not having SSR also makes hot module replacement a lot easier (though can be done with SSR! I have implemented this before for an SSR app).

Hosting a static SPA on Netlify with no backend

If you use a static site generator like Gatsby this works out of the box for the most part, but if you don't there is no need to worry. For my site, it is a usual React/Node SPA, but instead of hosting the backend I use for development, Netlify provides a redirects functionality, that allows you to serve your single page app appropriately for all routes without a hosted server. Basically you tell Netlify to send your index.html for all routes. This can be an issue at points, especially in terms of SEO, but there are some hacky workarounds here and for now this serves our needs (and budget).

Via netlify.toml file:

[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200

Netlify even supports custom cache headers per route:

[[headers]]
  for = "/assets/*"
  [headers.values]
    Cache-Control = "max-age=31536000"

Leaderboard

The leaderboard is a basic Node Rest API hosted on Heroku. It also uses a Heroku deployed Redis instance using one of their newer features (appropriately named Heroku Redis). The API does take some time to respond (especially if the server needs to 'wake'), but it is okay for an MVP. The redis lookup should be one of the quickest things. In the future I plan to move this to a serverless function. Maybe I can just leverage the Heroku deployed Redis instance via serverless Netlify functions?

Thankfully Heroku also uses continuous deployment so a Push to the Github repo redeploys the app in around 30 seconds, which greatly aids development

Challenges


Site performance with heavy asset usage

The site uses a 2.7MB audio file along with many gifs and images. Compressing and delivering an optimized audio file that begins playing as soon as the user arrives at the site was the greatest challenge here, or so I thought. Luckily using the html native audio element enables the audio file to download in the background even after it has already begun playing. On a slow 3G connection the audio file itself takes about a minute to download, but the site is still accessible and usable all with our song playing in around 5 seconds on a 1.6MBPS network connection because of the background download capability.

The images are compressed using Imagemin. It's important to get good source files here. In this case SVGs were much larger because of the design of our images. Rasters did not work well here. The PNG files worked well and look fine at around 7-8KB each. Same goes for the Gif images. The images and audio file leverage agressive caching headers. The max age is set as max value and luckily we can set these headers via Netlify, as described above.

Closing remarks


Hope this was insightful for you and gave some knowledge regarding why working on side projects is helpful and also gave a good overwriew and learnings from one of my more recent ones.

Cheers! -Michael