A quick few pointers this week on writing unit tests for 4×4 matrices. I’m building myself a vector math library, and using Test Driven Development to make it. I only get about an hour on the way to work – and another hour on the way back – to work on it, so it’s moving along slowly. I add to it every time I find a vector math function I need for my iPhone project that I haven’t implemented yet :). Most recently I needed to implement inverse matrices. Here’s some things that helped me write unit tests for them.
A matrix has an inverse if and only if the determinant of that matrix is zero. A matrix that can’t be inverted is called a singular matrix. An easy way to create a singular matrix is to set an entire row, or an entire column to all zeros
Matrix4 matrix(0, 0, 74, 1,
0, 435, 0, 1,
345, 0, 34, 1,
0, 0, 0, 0);
float expectedDeterminant = 0;
TS_ASSERT_DELTA(matrix.Determinant(), expectedDeterminant, 0.0001f);
There aren’t a great lot of matrices out there that have nice neat integer inverses either. I managed to find one in a discussion (which has since hidden from me in my web history) about different ways to calculate determinants, I post it here for your stealing:
Matrix4 matrix( 1, 1, 0, 0,
1, 1, 1, 0,
0, 1, 1, 0,
0, 0, 0, 1);
Matrix4 expectedInverse(0, 1,-1, 0,
1,-1, 1, 0,
-1, 1, 0, 0,
0, 0, 0, 1);
Matrix4 result = Matrix4::Zero;
TS_ASSERT(result == expectedInverse);
For other helpful hints regarding the creating and testing of matrices, check out the Euclidean Space page on Matrices for plenty of win.
P.S. I will migrate my blog to WordPress on my own site soon, which should clean up a lot of the code formatting issues. For now, my apologies.
Posted by Tatham
I’ve been writing my own code using Test Driven Development (TDD) for about 6 months now, and at the same time have found myself professionally working for two different non-games firms. In this time I’ve had the opportunity to try using agile methodologies – and unit testing – in a few different environments: business through to casual. I want to share some thoughts and musings from this time.
Firstly, tests are hard. Plenty of people have covered this point in the blogosphere and beyond, but until I actually tried it just never truly sunk in how hard they are. It’s one thing to be “informed” that “agile is difficult”, but it’s an altogether different experience when I’m staring blankly at my screen with absolutely no idea how to write a test for this functionality I want. And those moments happen. A lot. And they are truly a struggle to get through, but I learn very important lessons once I figure them out. And yes, it takes dedication and effort to figure them out.
Secondly, getting tests onto legacy code is even harder. I have a secret obsession with Michael Feathers’ fantastic book Working With Legacy Code, which gives some plentiful ideas for how to add tests to code that was never designed with tests in mind. Armed with these suggestions, some experience writing brand new code covered by tests, and the right environment, one can get tests on just about anything. In a casual environment i.e. When I’m my own boss, I find it pretty easy to see the benefit for refactoring old code to make it testable (I’m easily convinced though) :). Things get a bit iffy when the work is for someone else though. In my experience there are often factors preventing the system going under test that have absolutely nothing to do with the code. People can be lazy, or busy, or scared of tests. Unless the whole team makes a commitment to getting agile, it’s probably not a good idea to spend hours finding seams and getting code under tests.
Finally, it’s worth it. It’s damn worth it. I’ve never written such beautiful or simple code as I do when I write tests first. But code aesthetics is a nothing phrase to most managers and business men. Luckily, along with writing nice code I find I write code that catches bugs more easily (at this stage each bug is usually a situation where I didn’t think to put a test case in), code that’s easier to maintain and understand (easy to tell what something does and how it works when a test is written for it) and my favourite: it increases my productivity (I make it a point to end each of my coding sessions on a failing test. It’s lovely to just hit compile and see exactly what that next thing I need to do is. Straight back into it!)
The smartphone market is leading to a big battle. On one side, a million starry-eyed Apple fanbois and the behemoth that is the iPhone. On the other side, the freedom and flexibility of Google’s open-source Android smartphones*. It’s a battle that is to Google’s advantage to put off as long as possible, for the simple reason that it’s probably going to lose.
Okay, let me pull back and explain myself here. Anyone who’s regularly read my blog – and yes, there is at least one – knows I’m not exactly a fan of Apple. They’ve locked off their devices, forced consumers to use their software, and ruthlessly dictated the approval process on their app store. And to add injury to insult, the iPhone is a terrible phone, iTunes is a terrible application, and Apple only pay developers their due when they feel like it. Yes, I’m certainly no fan of Apple. But as a developer, the one thing both Apple and Android have in common is this: you get what you pay for.
To get an app onto the Apple app store costs developers approximately $99 US (it ends up being more for us Aussies because apparently Apple decides its own conversion rates). If starting from square one like myself it also costs the price of a brand new Mac. And for that price we get comprehensive SDK documentation, an excellent emulator, the XCode development environment, and a bevy of performance-testing tools.
To get an Android app into Google’s rather quiet app store costs nothing. And for that price we get a very similar deal to Apple’s offering just…cheaper: online documentation that’s not particularly intuitive to navigate, an emulator that takes forever to start up and kicks the bucket 5 minutes later needing a complete restart, the very un-intuitive Eclipse IDE, and a complicated in-code tracing system that links in to the debugger.
All in all, as a developer it’s just not fun to make stuff for Android. If I end up cursing my tools every 5 minutes, I don’t want to keep making applications for that platform. And when I add to that the frustration of having to support dozens of different screen sizes, button setups and phone hardware capabilities….well, it’s not worth my time.
Sorry Google, even though Apple is happily taking aim at it’s own foot with the iPad – Android still isn’t ready to take the reins of the smart-phone (sorry, superphone) market. Right now, this battle is more likely to play out something like the Sauron and the hordes of Mordor versus Frodo and some helpful gophers.
* Windows Mobile 7 is throwing rocks at both parties somewhere in the middle, but charging through the nose on a per-rock basis.
Posted by Tatham
Unit testing in XCode. Using Git with ProjectLocker (or at all). Using Eclipse for C++ development. These and many other things had been lingering on my todo list far too long before they actually got done. And basically this is because I tried them once, and it wasn’t a straightforward path to get them working.
When adopting a new tool, or trying out a new way of doing things, half the battle can turn out to be actually getting it working the way it’s supposed to. Sometimes, such as when changing to Scrum or XP, learning 3D modelling, or trying to use any of Adobe’s top-shelf applications, this is because it’s hard to learn. Old ideas or techniques or heuristics need to be thrown out and I have to try and learn from step one in a strange new world that looks eerily like the same computer I was just happily using Visual Studio on.
Some other times, however, it’s not so much a challenge as it is a bare-knuckles bar brawl with the ghost in the machine. Unit testing with XCode, for example, threw up a random “unknown error” message that Google was powerless against. It could only be fixed by completing removing, reinstalling and then updating XCode to the Snow Leopard exclusive version. Eclipse seemed to gag on its own shirt shortly after the installation procedure finished, and a tutorial that was almost 3 versions behind didn’t help. Eventually a friendly guru helped me to set it up, and I now have a half-dozen *nix-based command-line tools installed on my system that I’m only slowly learning about one at a time.
Git is a similar story. Like Eclipse, it seems like a damn good idea in theory. In practice, it requires setting up security keys, which requires ssh, which requires installing yet another half-dozen unknown nix-based command line tools into my windows with blurred lines regarding where the Windows prompt ends and the Nix-prompt begins. In the end – and I thought I’d never say this – thank god I had a Mac. With everything already set up in it’s distant-cousin-to-Unix OS, installing and setting up git finally become a “follow the tutorial” affair. Which was all prompted by wanting the latest version of the fantastic App-Sales Mobile.
Anyway, rambling aside my message for this week is: sometimes trying something new is hard because it takes a refocus, sometimes it’s just not as easy to set up as possible. If anyone reads this thing, feel free to leave your own comments about installs or set-ups that were way harder than they needed to be, and how you eventually conquered them.
Posted by Tatham
| Tagged: Apple