PrEV
Thoughts from a NeXTStep Guy on Cocoa Development

Writing Perfect Code?

Sep 17, 2007 by Bill Dudney

I've just started writing the debugging chapter of the Objective C book and I'm thinking about many conversation I've had with many programmers over the years. Is it possible to write perfect code? Most programmers when asked that question scoff and say 'duh, there is no way'. But our behavior says differently. In other words, most people would say that they can't write perfect code. But when they code they act as if they can.

I think the base of this issue is the difference between intellectual assent and belief. Intellectually most folks would agree that they are not capable of doing much of anything perfectly. They know instinctively that they have written bad code in the past and are likely to do so in the future. However many people code as if they won't mess up or worse (IMO) that no one that uses their code will mess up. An example to illustrate my thinking...

For example you have probably seen something like this error message if you've had a chance to play with CoreData;

exception: Cannot perform operation since entity with name '(null)' cannot be found (when saving file).'

As a developer using CoreData and ObjectControllers would you rather see this error message while your app is running or would you rather see the thing fail on loading the busted nib? The underlying problem is that the entity name was not set in the nib file for the array controller. Simple to fix and easy to understand from this error message if you'd been hit in the head with it once. If you've not had to solve this issue before though its not so obvious what the underlying problem is. Why is the entity name null, is my model messed up? Aw man I was just editing that and I though it was fine. Break out GDB and starting trying to track down the problem....

For me death on loading from the NIB would be preferable to sometime during the execution of the program. As a developer I'm a lot more likely to find and fix errors if I can find them quickly. If the controller would simply die when the entity name is not set I'd know about the error early instead of late. The controller has all it needs to know it won't be able to do what it should. I could easily die an early death on awakeFromNib (you specify the mode of the controller in IB, set it to Entity or Class). So why not do that?

This is by no means an attempt to pick on the CoreData folks or the AppKit folks or anyone for that matter, its just an example of something that happens to all of us. I'm no exception here. I have to constantly remind myself that my code is not perfect, and I better code that way.

So how do we make it better? There are a few tricks that I'll talk about here but more or less these ideas just common sense;

  • Code for the developer not the machine.
  • Clever is sometimes required but most of the time its not.
    • Clever leads to difficult to find problems.
  • Test everything, automate what you can.
  • Invest in decent error messages.

Code for the developer, not the machine: Developers have to read your code (and if you are a one person show you have to read it, sometimes months after you wrote it) and maintain the code. The ease of use inherent in your code is a result of good API and good error messages. We should write methods that can easily be understood from their names. And the code should be defensive, it should expect that all the code that calls it will forget to do something that is required. If you code (esp in debug mode) asserts its assumptions and those assumptions are violated you will know a lot sooner than the memory access exception. When I code I try to think, what does this method expect to be true, and what can I do to make sure that those things are true. This might slow you down a bit in the beginning but as you start to build on the small 'bullet proof' parts of the code you will be much more productive because you won't be dorking around with finding bugs in your assumptions.

Clever: Almost all 'clever' code I've every written or used has ended up being a liability to the project. There are a few exceptions but very very few. By clever I mean code that uses tricks or side effects to accomplish the goal. Sure the code might do something amazing. But in the long run that code will weigh you down. It will cause unforeseen problems and restrictions with every upgrade etc etc.

Testing is key. If you test your code you will know if it works at least how it fails and thus how to fix it. I have recently come from the Java space so spent a lot of quality time with JUnit and TestNG. I'm a big fan of unit testing despite what Wil Shipley said here I've seen unit testing save many a team's back side during refactoring/reworking of code. Wil ends up posting some great comments in the responses to his blog entry BTW, if you have a spare 10 or 15 minutes to read through there is tons of valuable stuff there from many view points. In addition to some pretty funny responses from Wil about drones etc. Its a good read. But back to the subject at hand. What ever you do make sure to test, be it integration tests where you are pretending to be a user, unit testing or anywhere in between. What I have found especially useful is to write tests for bug reports. That way I have an automated way to make sure the bug does not come back.

Finally on testing, automate everything you can. If you can exercise your code with OCUnit tests then do so, if you do gui testing then do you best to automate as much of that as you can.

As a side note I find that most of my bug related tests end up being writing around clever code or my use of it...

And finally thought that inspired this post... Write decent error messages. If you take the time to put an assert into your code please put a decent error message in there. I've seen stuff like 'dood it didn't work' on the console. And while that is clever and punchy and all its not very helpful. Take the extra 30 seconds to say what you mean so that when you or someone using your code violates the assertion they can fix the problem quickly.



Post a Comment:
  • HTML Syntax: Allowed