Recently, I’ve been getting more and more interested in lower-level styles of programming. It began when I started researching how to develop Gameboy games, learning all about the old hardware and the assembly instructions that can be used to program for it. As I started working on a small Gameboy project, I took the time to learn a few new command-line skills that would help me out, such as how to use Make to organise the build system of the project, and using it to automatically rebuild everything whenever I make a change. Following that, I started having a read of Crafting Interpreters by Bob Nystrom and really enjoyed its introduction to programming language design and implementation (though I am still very early in the book). Feeling a little inspired, I decided to start writing a REPL environment for Gameboy assembly language in C, as yet another exercise in working without all the modern trappings I deal with in my typical work.
In pursuit of an element of minimalism for the project - and since getting the standalone C compiler
gcc working on Windows is a bit of a pain - I ended up starting the project on Linux (using the Ubuntu subsystem on Windows), using vim as my text editor for the project. My Linux experience is limited, and I’ve never made a proper go at learning how to use vim before, so this seemed like a fun time to try and get used to working in that environment. At the very least, it made starting up the project feel quite simple seeing as all I had to do was make sure the OS had gcc, make, and vim installed, and I was all ready to go.
This also feels like it marks a small step in my learnings as a software developer, as I have started to gravitate more and more towards using command-line utilities over GUI-based ones in recent years. Compelled to try and understand more about what is happening under the covers rather than relying on GUI applications, I have taken to using tools like Git via the command-line and additionally learning how to orchestrate my software projects without relying on IDE wizards. Although there is nothing wrong with doing everything in the GUI, this ultimately has helped improve my understanding of how everything hangs together and made me feel more empowered to set things up in a way that I prefer rather than simply following the beaten path.
Writing in C
The last time I wrote anything in pure C must have been for a university assignment some time ago. It is a language I consider myself to be quite familiar with, due to my time spent coding in C++, but have never specifically spent much time working in. So far, the toughest part about writing a project using only C has been dealing with the tighter constraints that it poses. When trying to think of how to organise my parser for the Gameboy’s assembly instructions, it is very easy to want to fall back on designs that rely on forms of dynamic dispatch such as C++’s polymorphism, or on other approaches that utilise functions as first-class values. It has really encouraged me to keep the implementation simple, and although I’ve still only implemented quite a small portion of the software as of writing this, I think I’ve settled on an approach that will work well. Hopefully, as I expand it, I won’t find my current design lacking.
This was also my first time writing any kind of unit tests in C, and I was very unsure of how to do so given I don’t know of any industry-standard practices for doing testing with C. Although there exist various utilities to help you do unit testing in C, I was mildly taken aback when I came across the simplest suggestion of them all: to simply have a separate C file, let’s say
tests.c, which is built into its own executable, and runs a set of tests using
assert to check that your code is behaving correctly. Thus, you run your tests simply by building that file and running it, outputting whatever console messages you feel are appropriate along the way. I went with this approach for its simplicity and it has been perfectly effective for me so far; it is also a helpful reminder that, while I typically associate testing with all the bells and whistles of a modern testing framework/environment, at the end of the day it is just another program like any other being run on your machine, and the only special thing about it is how and when you run it.
As with C, this is my first time using vim in earnest, and although it has quite the reputation of being hard to use, I must admit it is not so difficult as it is sometimes made out to be. Once you Google some of the essential information - such as how to actually save your work and quit out of it - accomplishing the basics of text editing is mostly straightforward, and it feels quite comfortable to work in provided you find a sensible colour scheme that matches your preferences. From there on, as long as you are willing to occasionally take some time to research how to do that one thing you need to do right this moment - such as, er, copying and pasting text, or deleting lines - it is not too painful to just get on with whatever you are doing and learn the skills as you go.
I appreciate that vim has a lot of power if used correctly, but what I am liking more right now is the minimalism - there’s that word again - of keeping my work largely within a simple set of command line operations whilst still having everything I need at my fingertips. In fact, I’ve gone ahead and dug out my fiancée’s 11-year-old laptop, installed Ubuntu on it, and set it up as a dedicated Linux machine which I am using to write out this post right now, and the experience is perfectly smooth* (as it should be for a command-line affair). I like the idea of being able to undertake my personal projects on a low-power machine that reminds me to keep things simple. I attribute this mindset somewhat to hundred rabbits who I have been following on Twitter for a while, and although I doubt I would ever be so dogged in the pursuit of minimalism as they are**, it is a nice principle to keep in mind for my personal projects.
Perhaps it is slightly remiss to call all these things old-school - after all, C, Ubuntu, and vim are all still perfectly relevant in today’s world. It’s not like I’m writing in FORTRAN. But as I sit here typing away in a terminal screen, I must say it certainly feels old-school to me. I’m certainly not about to declare the superiority of working purely within the command-line, or swear allegiance to our open-source overlords, but considering how enjoyable this has been so far, I intend to keep giving it a crack for the time being, and see what else new I can learn from the experience.
*Admittedly, a part of me still wants to go out and buy the cheapest, smallest laptop I can find for this purpose, such as an 11-inch Lenovo Ideapad, since it would probably have a newer and nicer keyboard, screen, and battery life. But even though they can be quite cheap at $300AUD, that is still a lot of money to spend on something which I have no practical need for.
**Specifically, I don’t think I’ll ever design my own VM with its own unique assembly language as a low-spec portable platform for all my software to run in. That’s a deep rabbit hole to go down.