Software engineering links
(and unopinionated horribly dogmatic advice)

This is not a hard-and-fast canon, nor is it even well-organized; rather, it is a bunch of tips I thought of and subsequently revised after sharing them with a pal from my consulting days. Like any philosophical problem, the problem of building good software is thoroughly multifaceted and has several possible (partial) solutions, and the best way to find a solution (or to understand the problem) is to examine as many of the facets as possible.

Unit testing

Nothing will save you pain and suffering the way unit testing will. Unit testing is not a substitute for large-scale, functional testing, but it can let you know exactly when and what is broken by an errant CVS commit. There are a couple of paradigms for unit testing in Java: the basic "testing main" (i.e. every class has a main() method which performs tests on every public method member) and the "testing harness", or large-scale framework, like JUnit. JUnit is more advanced and better for large projects, but a testing main is better than nothing.

My best advice to you wrt tests is use them. If you're already convinced, an extremely close second is Write the tests before you write the methods that you'll be testing. That alone will deliver you from almost as much additional pain and suffering as deciding to use tests in the first place did. Also, writing the tests first ensures that you actually write the tests (!) and that you have real requirements for your classes. Here are some helpful testing links:

Coding style and naming

Whatever you do, be consistent. There are many horrific bondage-and-discipline coding styles and naming conventions (i.e. the "Hungarian notation" so absurdly popular with Windows programmers); one of them may be helpful to you. Following one of these conventions may help you and future maintenance programmers, but following one of those conventions inconsistently is a TGV ticket down the path to ruin. (I don't put a lot of stock in formal naming styles; I instead opt for common sense, readibility, and maintainability -- which leads us to....)

Use self-documenting names. Method names like doStuff() or performAction() are suspect at best. Banish these charlatans and replace them with methods that aren't ashamed to taks responsibility for their actions. If you do design patterns (you should; see below), then incorporate the name of a pattern into your class names, like CachingJDBCDecorator or DocumentSaveCommand. Since the patterns have simple names with rich meanings, this will allow you to tersely convey a lot about your design.

The corollary to the preceding rule is If you can't name it, it shouldn't be a {method|class|etc.} If you can't decide what to call your wonderful foomatic class or method, it is very likely because that class has poorly-defined or (even worse) ad-hoc responsibilities. Naming should be intimately intertwined with design -- good names should help to reveal the design.

Document your method specifications (parameters, return values, state changes) with comments. Does this mean that your code should not be self-documenting? By no means! Write self-documenting code and then document methods. If you're needing many comments within methods (except for extremely tricky bits), then you should really decompose the method into its constituent parts, so that each has a self-documenting name and performs a "molecular" (i.e. small and functional but non-"atomic") task.

Name interfaces after adjectives and classes after responsibilities. Does it really matter that something is an Iterator (well, yes -- but mostly so you can have generic structure-traversal/node-visiting algorithms). You really want to know whether or not something is Iterable. If you use adjective-interfaces carefully, you can have very general classes and algorithms with great ease. Likewise, (generally), you don't care about implementation in a class name -- just what it does, not how it does it.

Engineering and Mechanics

I lump "engineering" with "mechanics" because often the activities of building good software ("mechanics") and designing good software ("engineering") are intimately intertwined. One of the most important developments in recent years has been the increased popularity of refactoring, or improving the design of existing code. (This is, of course, not a substitute for having a good design up-front; the myths about macho "real programmers" who magically architect brilliant, robust, and maintainable systems while coding are just that -- myths.)

Here are some useful links, organized into sub-categories:


Comments to Will Benton (willb at cs dot wisc dot edu)