Writing Good Code

(This article contains my scribbled thoughts on writing good code, advice I posted to the forum for a course I was tutoring at VUW. It's neither complete nor perfectly written and has been written in the context of an assignment the students had to complete. For this assignment they were given a whole heap of code (an interpreter and GUI for a simple language) which they had to tidy up and make more readable. Thus my thoughts are in the context of cleaning up code that already exists. You can and should apply these exact same processes and more to writing new code though.)

OK, here are some of the very unofficial scribblings of a tutor on Lab 4 :) If anything I say here is different from what David, James or Tim [the lecturers] say then they're right and I'm wrong. In addition I'd like to make explicit that none of these comments are directed at any specific individual. I have very carefully not looked at anyones scripts in thinking about this post, and so these are my general impressions only.

But enough disclaiming :)

First things first: your sole and single goal in the project was to simplify and tidy the code. Further functionality is very cool, but not necessary. Ditto optimisation. What does this mean? It means that you should probably think very very carefully about any optimisations or extensions: if they do not also improve the readability of the code they will not gain you many (any) marks, and could well lose you some. Remember: CPU's are cheap, programmer-hours are extremely expensive. The money an optimisation saves is almost always less than the cost of the hours taken to implement it, test it, and then debug the inevitable errors.

(OK, so focusing on doing what the assignment asks you to do is just a good plan for any assignment, COMP or not, but still - the dark side is the fast side in COMP and it is seductive.)

Having clarified then that your goal is only to reduce complexity and improve readability you might ask how you go about this… and this is not in fact a stupid question, by any measure. I see two main ways in which you can improve the code, neither of which is easy to define but hopefully I can give some useful examples.

The first way is generally pretty effective and always easy - easy to do and easy to forget to do. In short, it is Encapsulated Consistency. This means the style and case of variable and class names (all upper case, lower, polish, whatever - just be consistent!). It means making sure that members are properly hidden (private is good, btw). It means reading every single damn boring comment and making sure it says what the code says. And use the API or standard library! It's nearly guaranteed to be bug free, it's almost always more efficient than your code and we all know what it does! It sucks to learn that the library is better than your code, but at least for me it always has been. My sort has never been as fast as C++'s std::sort, and I'm willing to trade in my ego for a faster sort. Whitespace. Blank lines. They are good. Do not be afraid to use them. I personally use 3 blank lines between every function, and then, where necessary, single blank lines within functions, but pick your own style and be consistent. Oh, and comments. Comments are critical. You need them, but too many will destroy an applications readability as surely as none. Focus on commenting the stuff that isn't obvious, plus all functions and classes. Hint (from C++): *a→energise() qualifies as unobvious. Comment functionality and role rather than gory algorithmic details (but like all rules of thumb ignore this one at times). There are more things you can do here but I'm sure you get the picture :)

The second way you can improve your code's readability, often much more dramatically, is at the level of the class and function. Here you're looking not so much at algorithms as you are at the relationships and interactions between classes, i.e. patterns! Your aim should be to minimise what someone has to learn or know to understand your code. If you can use stuff they already know, e.g. patterns, this is good. If you can make it so they don't have to read all your code this is also good. Think not about consistency or encapsulation but instead about functionality. Be sure you're very clear in your mind about what role a class plays in the application and then consider how well it fills it and what alternatives there are. There may be simpler alternatives that provide all the generality the application needs, or perhaps you need to go the whole hog and build yourself a fancy tree of interfaces and strategies and MVC's. Whatever - again, it's a judgement call, but you definitely need to think about it.

Which one of these types of task you do first I'm not sure - whichever strikes your fancy I guess. I'd personally lean towards doing the first one first, if only because it'll make the second one easier (since the code'll be more readable) but hey, whatever floats your boat.

So how do you do all this? Gut it out. I wish there was an easy way, and maybe there is one, but I haven't found it. It will be as dry and boring and dull as it is crucial, which is to say so amazingly so your brain will collapse. As to specific methods… check each class, within each class, check each method. This is one way. Alternatively look for specific problems: e.g. check every file for badly encapsulated variables. Then go and check every file for badly used patterns or places where a pattern used makes the world go round. And do all this early, cus doing it on the night of your deadline only makes it worse.

Finally, the change log: there was a range of change logs, some good, some bad. When putting together your change log remember that it exists only to be read. Therefore any changes or styles you can use while writing it that make it easier to understand will only improve it, and often dramatically so. As with code there are about 50 batrillion styles you can use, and no one style is better than any other (except mine, of course). Think about how you can group the information to make reading it faster and easier - remember, making the markers job easier is a Good ThingTM, as is making easier the job of the user of the API you've written too… Grouping by date is one of the obvious approaches, as is grouping by the class or file affected. Deciding which (or which combination) to use is of course one of those nasty judgement calls, but if you keep forefront the fact that the goal is to make it as informative and readable as possible you'll probably decide well.

 
essays/goodcode.txt · Last modified: 020071011 1019 by christo
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki