Well, I'm back from my travels, and I did indeed do a lot of thinking. And a lot of driving. At least eight hours behind the wheel plus other odds and ends of time gave me plenty of opportunity to mull things over. When I had a chance, I scribbled down notes on notepads and scraps of paper - collected they fill seven pages of bullet points in my A4 project journal. This should certainly give me something to work on. Rather than just dump all my notes into this blog, though, I hope to gather and re-organise them into more readable stand-alone topic areas.. So here's the first.
My biggest frustration during the exercises in "Baking Pi" was the way that it seemed so far from the way I like to develop software. A fragile black box, which gives no indication of what might be wrong other than simply not doing what is expected, and which can only be tested by manually trying things out. Just about doable for a tiny, single-purpose program, but hardly a way to build flexible, useful software. I think of this as "level 0" software development:
Development level 0 was all we had back when computers were new, and it can be tempting to think that this is all it can ever be. This assumption is particularly common in the field of embedded systems, but can also be found in people developing for big systems with all sorts of tools and infrastructure.available. It's very hard to do Test Driven Development (TDD) in this kind of development cycle. There is only so much a test could possibly manipulate and observe - in the "Baking Pi" exercises testing was limited to inserting an SD card, powering the system and watching an LED for a pattern.
I find level 0 development, clumsy, time-consuming, restricting and error-prone, and want to climb up to where I can begin automating tests and instrumenting behaviour as soon as I can.
One possibility is to ignore the real raspberry Pi hardware completely. In PC development it's common to run "virtual machines" using tools such as VirtualBox. VMWare, or QEMU. Mostly these use the host processor of the development machine directly, and just do some clever process-switching to run one OS "inside" another. In this case that won't work. My development machine is a generic x86 PC running Windows, and has a different CPU to the Raspberry Pi. Luckily QEMU can also emulate an ARM I found some useful information about using QEMU to emulate a Raspberry Pi .
This all seems quite complicated, and mostly aimed at running Linux so it's not clear how well it might cope with bare metal OS software. The main benefit it offers is to avoid all the plugging and unplugging of power leads and SD cards, which helps speed up the development cycle, but does not really help with testing as such. I'll park that Idea for the moment, and maybe come back to it later.
What I'd really like to do is to severely limit the amount of the system which is machine-dependent, and build/test the rest of the code using all my favourite development and test tools on the development machine itself. For this to make sense I reckon I need two key design principles in my operating system:
- Get out of ARM assembler into a portable, testable, language as soon as possible.
- Minimise and separate code that requires the Raspberry Pi hardware from the bulk of the code which can be tested independently.
It's commonly said that TDD is a technique for improving the design of software. I think it's fair to say that in this case it's a technique for improving the architecture of an operating system.
More about how I might implement this clean separation and minimal size of the Raspberry Pi-specific code another time.