I’m entering the final sprint of my current iPhone App project, so I thought
I’d post some notes on the practices used (and some I should have used much
more!) during its development. I’ll post further on the low-level development,
submission and review process later. For now I’ll focus on high level
development issues. These points are not iPhone specific but the ecosystem of
the App Store makes them particularly relevant for a lot of the start-up,
one-man band or small indie team projects that are buzzing at the moment.
Define Your Purpose
It sounds so obvious, and yet plenty of projects flounder for lack of it.
Begin by explicitly defining your purpose. Be as specific as you can be. The
very first step you take in any endeavor is the one that establishes your
direction. Every single move you make should be in agreement with your
purpose. All those mini decisions you make every hour, week, month and so on
have a compass. If you don’t define your purpose, those compasses can drift
without any clue where they should be pointing – the odds of all them pointing
in the right direction are arbitrary and extremely unlikely. Defining your
purpose establishes your polar north and gives each one of those decisions a
shared context and allows them to proceed intelligently, as if in concert. This
applies as much to individuals as to teams. Always define your purpose, and
refer to it regularly.
Prioritize
You can’t do everything. You have limited time, resources and energy. Make
a list of what you need to do, and sort it by priority – what do you vitally
need to do and what can you live without? Be prepared to drop features.
Establish up front which ones are core, and which ones you can drop later if you
need to.
Be Realistic
If you’re working on your first iPhone project, keep it small, simple and
straight forward. It’s very easy to bite off more than you can chew. The
smaller your team is, the more sensitive you’ll be to schedule overruns.
Keeping things simple helps minimize this. Use your first project as an
intelligence gathering exercise. You want to find out the full extent of the
pipeline of going from an idea to a finished App on the deck. If you can’t
complete a simple project, you can’t complete any project. Don’t let your App
turn into Duke Nukem Forever Never.
Use Agile Practices
This is really a no-brainer for any software development project. If you
have not had the good fortune to have tried out proper Agile dev practices, stop
what you’re doing immediately. Pick up Agile Principles, Patterns, and
Practices or any of the many great books on the subject and dig in. The
ultimate payoff is this. Clean, simple, safe and focused code, regular working
builds that actually do something useful, and best of all low stress levels even
in high paced dev cycles. Pick a practice, say Test Driven Development, and
start using it. When you’re comfortable with it, pick another. Make Agile
practices second nature and you’ll never look back. If you’re like me, it’s not
that difficult to occasionally slip back into old-school habits, particularly if
you’re working on your own. Resist!
Get to the Heart of the Matter, Quickly
Whatever your app is supposed to do, make sure it can do it as soon as
possible in stub form. If it’s a game, then you should be able to play it early
in the schedule, not late. Use content placeholders. Don’t leave the core
feature of your app until the last few weeks of your development schedule. Any
kind of app needs time to settle into it’s final shape. You rarely see this
happen immediately – it takes time, attention, testing and iteration. Write
your code to facilitate this. For example, I wrote a Finite State Machine
compiler for UtopiaGL which allowed me to flesh out the overall app flow in
literally 30 minutes. On day one of my current app, I could navigate through
all screens and menus (splash screens, main menus, sub-menus, level selection,
in-game etc). The same process was used for game play, and all entity
behavior.
Procedural Content
One of the best ways to cut your content creation time down is to make good
use of Procedural Content. It will depend largely on the type of app you’re
working on, but many apps can benefit in some way. Terrain generation and
texture generation are the usual things you hear about within game development,
but you can apply procedural methods to pretty much any type of content. Ninety
percent of the content in my current app is procedurally generated (most of it
off-line). The world terrain was generated by a mixture of hand made level
layout images (a simple two-color image mask that identifies where a player can
go) which feeds into a noise based terrain texture and geometry generation
system. The net result is a terrain that exactly matches the game-play needs,
but looks like typical landscape. I also used code to create some of the
regular geometry using basic primitives.
In-App Editing
My current app is a simple arcade game. I’m using it to flesh out my
middleware engine and ensure that it’s as flexible as it can be. I wanted the
game-play creation cycle to be as quick and friction-free as possible, where you
can make changes to levels and immediately test the game-play. Rather than
creating a separate editor I opted to implement editing in-game. For the
windows build of the App (I’ve done 99% of the work in Windows) you can play any
level, hit the on-screen edit button and go into editing mode. You have full
editorial control over all entities (placement, attributes etc), and an
on-screen edit palette that allows you to create, drag and drop, zoom, pan etc
and otherwise manipulate the scene. When you’re happy with your changes you hit
commit and you’re back to normal game-play. Each level was drafted in less than
an hour. I further play-tested over the space of a few days, and that’s still
on-going with minor tweaks here and there. The typical cycle was:
- EditMode: Layout overall level structure.
- PlayMode: Test overall timing.
- EditMode: Flesh out a small section of level up to a check point.
- PlayMode: Test game play up to check point.
- Repeat steps 3 and 4 until level is fleshed out fully.
- PlayMode: Play test the entire flow and timing of the level.
Before editing commenced I established the overall design goals of each
level, so that I could work through them fairly quickly and still have them fit
into the overall scheme of the game. There’s a very interesting latency issue
with any kind of creation process. There’s a timing ‘sweet spot’ where the
whole process flows very smoothly provided you can get the details out of your
head and onto the screen at a rate fast enough to move with your thoughts, and
not be held up waiting for something (like having to quit an editor, compile
content, load into the game, navigate menus, load a level, move to the point in
the level you’re interested in, and…what was I doing again?!?!). It would have
taken considerably longer if I had opted for offline editing.
There is also another very important creative aspect: feedback. When you
plan on a certain type of game play, it usually doesn’t translate into reality
just the way you expect – there will be things you didn’t anticipate. I really
enjoy watching this process happen, because you can usually find a wealth of
opportunities you overlooked initially. Some things you thought would be fun
may not be, and something you never considered important may end up being your
game-play center piece. You can only capitalize on this if you get game-play
working early.
If you’re contemplating creating editing tools yourself, whether in-app or
not, think carefully about how they should work. Consider the workflow of the
artist or the designer in detail, how much time each step will take, how much
effort is involved, what can be automated etc. Multiply your timing estimates
over the expected creation cycle timeframe, and identify the stages that should
be focused on to increase production speed.
Pragmatism
This is something you need to get clear to ensure the best chance of lift-off
for your project. Programmers often slip into a frame of mind where they want
their code to be spotless. I don’t sleep well when I know there is a mess
waiting for me the next time I sit in front of my machine. The problem is, it’s
impossible to make things really spotless – everything has a context in which it
is judged and that context is a moving target. This can turn into an enormous
tar pit. Avoid it.
You can deal with this by referring to your project’s purpose and by keeping
Agile. Does the work I’m about to do agree with my purpose? Will cleaning up
this class, writing a general purpose solution, etc, get me closer to my goal?
If the answer is “no, but…”, then it’s probably time to stop and have a think
about what you’re Real purpose is, because it’s not what you’ve convinced
yourself it is. Use Refactoring (to allow your code to change quickly,
dramatically, and manageably), TDD (to help keep the design clean and guarantee
changing or refactoring your code doesn’t break anything), User Stories (to keep
User focused, and avoid wasting time writing code that doesn’t help your
project) and short iterations (to help establish your pace, and allow better
forecasting of completion times) to ensure you keep on track and avoid getting
stuck in this pit. Do the least amount of work to get to your goal.
If you’re writing an app to be used by people then…you’re writing your App
for a User. That clarifies everything you need to know. You want things to be
perfect? That’s great. Don’t try to make your code perfect. Try to make the
App perfect instead. Ideally, when the User uses your App they should see as
close to Perfection as you can create with the time and resources you
have. When a programmer looks at your Apps source code they should see
Pragmatism.
If you’re using Agile practices, then it’s ok to have parts of your code
appear a little messy by traditional standards – it’s the quickest way to get
your User Stories implemented. Short, simple code is beautiful. When you start
needing to revisit that code, or repeatedly duplicate it, or require more
flexibility, then (and only then) you generalize and clean it. It’s ok, because
you have automated tests that constantly watch that code for bugs. It’s ok
because refactoring allows you to radically change the code quickly and in a
stable way when you need to. When you leave your work at the end of a day, you
know with a high degree of certainty where you are on your schedule, how stable
your work is, and that with one click you can spit out a release you could put
in someone’s hands and have them use the App. You also feel far less stress –
one of the most welcome side effects of Agile practices.
Pragmatism means writing solid code, not perfect code. Perfect code usually
means Indulgent Code – someone indulging their appetite for elegant,
sophisticated, complex-toy kind of code, often at the expense of clarity, time,
usefulness etc – this kind of code is absolutely not for the Users benefit, it’s
for the Coders ego, or misplaced idea of what good code is. Indulgent Code is
what happens when a developer gets so focused on the code that the end result,
the App they’re developing, gets completely overshadowed by the act of coding.
This is detrimental, and usually forecasts failure for the project. Ironically,
shifting a perfectionist focus off the code and onto the App by using robust
practices is when the code actually starts to approach the only measureable
perfection you can humanly achieve.
Conclusion
If you’re aiming to put applications out on the iPhone then you’re up against
some pretty stiff competition. The sheer numbers of competing Apps is daunting
to say the least. It’s more important than ever to try to minimize development
time and maximize quality. The practices you use can make or break your
project. I benefitted from using Agile practices on my current project, but I
could have used them more fully – something I intend to do on my next project.
I can’t recommend them enough.