Once upon a time I used to program in Perl. There, I admitted it! My dirty secret is out 🙂
Perl is an odd language, and there are plenty of things not to like about it, but one thing I did like is how it is designed to let you choose your own coding style based on whatever problem you are trying to solve. Larry Wall, the creator of Perl, put this rather nicely:
[you can] choose what to optimize for, whether that’s computer speed or programmer speed, verbosity or conciseness, readability or maintainability or reusability or portability or learnability or teachability. You can even optimize for obscurity, if you’re entering an Obfuscated Perl contest.
I think Perl took this philosophy too far, but the basic principle of choosing what to optimize for is useful for all the code I write. I find myself doing several different kinds of programming:
Prototype code, to learn a new technology or find out whether a new idea will actually work.
- Optimized for development speed.
- Code will be thrown away as soon as it is finished.
- Don’t bother with any comments or error checking.
- Don’t waste time thinking about good variable names or program structure.
Internal utilities, for instance a script that deploys new framework builds onto my Xbox, or the unit tests that make sure my code really does what I think it should.
- Optimized for a mixture of development speed and maintainability.
- Code must be readable, because other team members might have to maintain it.
- No error checking. We have source code, so if something goes wrong we can just look at the exception in the debugger to see what the problem is.
- Only ever has to work on our development machines, so it is ok to depend on all kinds of external tools that I happen to know everyone on the team has installed.
Shipping product code, for instance the games I wrote in my previous life.
- Optimized for performance and reliability.
- Readability and maintainability matter too, but not if they get in the way of performance.
- Has to work on a huge range of machines. Different graphics cards, drivers, operating systems, DirectX versions, 32 and 64 bit processors, varying Unicode locales, timezones, user account settings, etc.
- Needs robust error handling.
- Must be thoroughly reviewed and tested.
Framework APIs, such as the work I did on XNA or Allegro.
- All the same requirements as product code, plus more!
- Spend more time on API design issues like the programming model, naming, which types should be sealed, which methods should be virtual, etc.
- After we think we have a final API, take extra time to review it with the .NET Framework Design Guidelines people.
- Public methods need more careful parameter validation, so they can throw useful exceptions when the caller gets things wrong.
Sample code, shipped in source form for other people to learn from.
- Optimized for readability.
- Lots of comments.
- Not too much error checking, because that would obscure the focus of the sample.
These styles of programming are obviously very different. I can write prototype code maybe twice as fast as an internal utility, while product or framework code is an order of magnitude slower.
Once you start thinking about these differences, an interesting question occurs. How can I spend less time writing product code? How can I write low-overhead internal utilities that will somehow automate or reduce the amount of slower product code development?
This is one of the reasons I like having a content pipeline that separates build time data processing from my runtime game code. The more computations I can move from my game into a custom content processor, the less product code I have to write. Processors are internal utilities that only ever have to run on my computer, so I can get away with all kinds of shortcuts that would never be acceptable if I was doing this processing as part of my shipping game code.