3D Bookshelf has been out on the App Store for just over two months now, and we’ve had over 25,000 sales in that time. We’ve been very lucky. Apple decided to feature us in ‘What’s Hot’ and ‘New and Noteworthy’ and helped us get great exposure. We didn’t count on this because the odds are incredibly slim, but deep down every App Developer hopes it will happen. We did our best to make our App stand out, we responded with gusto to user feedback on iTunes, and it paid off. One of the interesting stats from over the last two months is that we haven’t logged a single crash report through iTunes. There are many contributing factors: the type of App, usage patterns, etc, but if your code base isn’t rock solid, you will see crash reports. Below are some of the aspects of 3D Bookshelf that helped achieve a robust code base.
Values from Game Engine Development
Our background ranges from high-end PC game engine development, right down to low-end mobile development and porting. It is very interesting seeing the different approaches game developers take to problem solving versus those of non-game developers. Game engine developers have a laser focus on two main things: frame rate and resource usage. Game engine developers with experience on low-end mobile development (and especially porting) have an even greater focus on those things! Non-game developers are also focused on these things, but they tend not to weight them in quite the same way. These are things that were front and center in our minds during the entire development of 3D Bookshelf.
One Single Memory Allocation
Memory management though the OS, if not used carefully, can fragment memory, degrade performance, and worse (at least on iPhone OS) can simply fail altogether if the OS decides you’re not being reasonable about the rate at which you are making large allocations. 3D Bookshelf is written on top of our middleware platform, UtopiaGL. One of the main features of UtopiaGL is a solid, fairly typical game-engine style memory management system, that helps avoid the issues that iPhone OS presents. When 3D Bookshelf initializes, it tells UtopiaGL to make a single, app specific (in this case, 8 megs) memory allocation, and from that point on, there are NO further explicit OS memory allocations. All allocations are made through UtopiaGL (using the C++ placement new operator), which it allocates from this heap. The UtopiaGL memory manager is hooked into all aspects of the engine, for example, the zip loader, and png loader have hooks to use the UtopiaGL allocation system, and not the OS. UtopiaGL completely avoids internal fragmentation very simply by dividing memory into two heaps: constant and temporary. Constant memory is allocated from the bottom of memory up, and temporary memory is allocated from the top down. Allocations that result from loading a zip or a png, for example, always get allocated from the temporary end, and are released the moment they are no longer necessary. Permanent allocations are always made from the constant end. This means that at the end of a load step (like loading the Main Menu), you are left with a neatly packed heap, with zero gaps between allocations, and a clean lump of contiguous memory (towards the temporary end of the heap) for real-time use.
There are of course other allocations you can’t control, for example, OpenGL textures, OpenAL sound buffers etc. but you certainly can do a lot to minimize the pressure you place on the handset on the application side.
Simplicity is a Pre-requisite to Stability
I read years ago that in typical, professionally written, untested code, there is usually a minor bug in every ten lines. I’m not sure if that number holds water, but it does point to a simple observation: bugs live in code, so the less code you write, the fewer bugs you’ll have! Shorter code is almost always simpler – the challenge is to keep it readable. During development, we always favored short, simple code. In fact, we only rolled up our sleeves on a few parts of the code base that really required high-performance – the 3D Book Geometry Generator and animation system, and even then, we prototyped in simple code first, and optimized where we needed to based on speed measurements.
Automation
There is another important observation here. The reason you need to favor short code isn’t because short code is inherently more stable. It’s because humans are the ones writing the code, and the more code they write, the more bugs they introduce. Human error is the root cause. Remove human error and chances are good that even with larger code bases, they’ll be more stable. Enter automated code generation! Another powerful feature of UtopiaGL is its FSM (Finite State Machine) support. This allow you to create a simple text file that describes the many states your App can be in, what causes the App to transition from one state to another, and how to make those transitions. This simple text file gets compiled by the UtopiaGL toolchain, which generates the necessary C++ and Header files required to implement all that management code. Best of all, it scales without any human error being allowed in – a large FSM is just as stable as a small FSM. You may have bugs in the code you use to augment it, but the state management code will always be rock solid. For large projects this is very important.
The advantages of using a FSM system go well beyond stability. Increased development speed is also a major advantage. It takes very little time to flesh out a FSM. It also takes very little time to make large changes. All of this, with the confidence of stability.
FSMs drive the overall App Flow (how modules transition, for example, Main Menu to and from the Info Screen, Settings screen, Book Reader etc). They drive the internals of the Main Menu and the Book Reader. And you can even have a FSM within a FSM, for example the logic in the Book Reader that hides the UI by tapping is implemented using a small FSM, seen here.
FSMName BookUIButtonsFSM
Context BookUIButtonsController
Initial LimboUIButtons
Transition Immediate
{
// Event NextState Action
LimboUIButtons
{
Begin InvisibleUIButtons DoInvisibleUIButtons
}
InvisibleUIButtons
{
Tap FadeUpUIButtons DoActivateUIButtons
}
FadeUpUIButtons
{
Done VisibleUIButtons DoVisibleUIButtons
Tap FadeDownUIButtons DoDeactivateUIButtons
}
VisibleUIButtons
{
Tap FadeDownUIButtons DoDeactivateUIButtons
}
FadeDownUIButtons
{
Done InvisibleUIButtons DoInvisibleUIButtons
Tap FadeUpUIButtons DoActivateUIButtons
}
}
I wrote the FSM system based on the one described in Agile Principles, Patterns and Practices in C#. For more information, check out that book – it has a wealth of information.
Conclusion
Creating stable software is a major challenge. There are many things you can do to limit the chances of introducing bugs into your code. The two most effective ways we kept the 3D Bookshelf code base stable were to tightly control memory management and as much as possible remove human error from the equation. There were many other methods used, but these two areas more than likely had the biggest effect.





Hey Kevin, great article on an often overlooked aspect of software engineering…! Keep up the good work.
Steven
Cheers Steven!