As a programmer working on video games it is difficult to practice “proper” software engineering methods most of the time. From my experience, the reasons for this are numerous. For a start, not a lot of programmers I worked with have the knowledge or interest in working that way. Maybe there were bad experiences with needlessly over-engineered code. Production does not care too much about it either as long as features get completed and defects resolved, even if the resulting code is bad. Burn-down charts and hitting dead-lines is what counts instead. Last but not least management is not interested in these numbers because for them, as long as the product “looks good, it is good”. And it is not like anybody could easily pin a financial benefit of following practices – rather on the contrary, all of a sudden there is need to purchase some extra software licenses. In short, following software engineering practices can be a very hard sell in this environment. Truth be told, I’ve rarely been willed to push for the application of software engineering principles myself, simply because I could not be bothered with the political game involved.
But anyway. With having recently started a new job and having been professionally developing software for almost 10 years now, I felt the need to challenge myself again a little bit and actually exercise good engineering principles when programming. And to add some extra pressure onto myself to stick to this principle, I’ve decided to document the processes I’ll use, so that it will be useful even to the novice software developer.
As a first such exercise I decided to write a C++ library to track usage patterns of a Qt desktop application using the Google Analytics Measurement Protocol. To do this, I began by setting up a GitHub repository, because having a version control system should be considered as the bare minimum requirement along side a good IDE when writing software . The second principle I set to myself was to use test-driven development. I’ve more and more become a fan of this development model since it helps you gain a lot of confidence in what you are building. However, it does add some overhead as that you are no longer just compiling, but also running a small test application continuously. This overhead can easily be addressed in your favourite IDE by specifying adequate post-build steps, which I will leave as an exercise to the reader, but ideally you’d want to have these tests also run when you commit your changes to your code repository. After all, nothing is more annoying than breaking a build because you forgot to submit a file and not discovering it until you (or someone else) pulls the latest changes on a different machine. Since I already know that I will also want to run a few more things in an automated fashion (static code analysis, doxygen), I’ve opted for setting up what is called a “continuous integration loop” using the Travis CI platform which is freely available for open source projects. Since Travis does C++ compilation on Ubuntu using gcc and/or clang then there is even the added bonus of getting some cross-platform exposure for my code since I personally develop on a Windows system at the moment. In other words: Even more win for your code!
Setting up Travis CI for a GitHub project is dead simple and straight forward. Once you’ve logged into Travis using your GitHub account (hooray for OAuth!), you can select which of your projects should be observed by Travis. After selecting your project, all you need to do is provision a file with the name .travis.yml which contains the build instructions for your project. One thing that you’ll want to pay attention to is that Travis always spins up a clean virtual machine for your build, so you will need to include commands for installing required Ubuntu packages. Feel free to take a look at the configuration I provisioned for my little project.
Now, I’m all set up for developing my project and it’s time to write some code to see how this plays together. But wait, this is going to be a library communicating via HTTP, how do I write tests for this? Well, it turns out this is rather easy in the end, but it took me a moment to figure out a good solution. And I’ll tell you more about that in the installment of this series.