Communities.com Design Rules and Coding ConventionsVersion 1.1, 21-April-1997 This page is maintained by Chip.The following is the official set of design rules and coding conventions which we will henceforth be using here at Communities.com. This is intended to discipline us into writing better software. We have demonstrated by the current state of things that we both lack this discipline and require it. All of these rules are motivated by practical experience. However, they are not set in concrete. Expect them to change and expand as we learn. Your feedback in improving these rules is encouraged, nay, demanded. And when you find it makes more sense to break one of these rules, break it - but be conscious that you are doing so and that you have a good reason you can articulate. These rules are not intended to harass you or make your life difficult; quite the opposite. However, I will harass you and make your life difficult if you don't start following them. First rule: regardless of whatever other rules you may be following or not following, you must format neatly and consistently. Prefer small methods, small classes, shallow inheritance, small packages OrderingOrder your classes neatly when you have multiple classes in a file: public before package scope, then interfaces before classes, then alphabetical by class name.Order the things declared inside a class too: instance variables before constructors before static methods before non-static methods, then public before package before protected before private, then in alphabetical order by name. ScopingAlways prefer the most restrictive scope that works. If a variable is only used inside a block, declare it in that block. Take advantage of the fact that, unlike C, Java lets you declare anywhere, not just at the top of a block. Declare simple iteration variables in the for construct if they're not used outside it:for (int i=0; i<limit; ++i) { ... No public instance variables, ever. Package scope instance variables only under duress. No public mutable static variables, ever. Mutable static variables in general should be avoided. Assume that statics can get reinitialized at any time (under persistence, they can) - you can use statics for tracing, caching, and diagnostics, but not for holding critical state. Import individual classes, not packages. That is, don't have imports of the form: import foo.bar.*; NamingInstance variables should have names of the form myFoo. In addition to improving legibility, this convention has two other beneficial consequences: First, it makes dealing with the no public instance variables rule less burdensome, because you can (now by convention) name accessor functions after the things they access, i.e., instead of:int getFoo() { return foo; } you can say: int foo() { return myFoo; } Second, constructors no longer have to dance around naming their parameters, i.e., you can have a constructor like this: SomeClass(int foo) { myFoo = foo; } instead of the somewhat awkward: SomeClass(int foo) { this.foo = foo; } or the truly evil (which I have seen in some of our code!): SomeClass(int Foo) { foo = Foo; } Methods which implement boolean predicates should have names of the form isFoo. That said, we have too many of these and often they should be avoided (see below). Symbol capitalizationmidCaps: first letter of new English word always capitalized, even if one letter. Underbars and dollar signs only in generated names. initial small: methods, non-static variables, package names Initial Cap: types (classes, interfaces), static variables. ALL_CAPS: manifest constants (static final int FOO = 47;). Underbars as word separators but dollar signs only in generated names. Indentation and brace formattingUse 4-space indents. Since Pluribus nests structures with wild abandon, in Pluribus sources 2-space indents are the norm.However, the TAB character per se is BANNED. We will use the one true brace; style: if (cond) { stuff; } if (cond) { stuff; } else if (cond2) { morestuff; } else { evenmorestuff; } while (cond) { stuff; } do { stuff; } while (cond); switch (num) { case FIRST: stuff1; break; case SECOND: stuff2; break; default: stuffd; break; } try { stuff; } catch (AnExceptionClass e) { catchstuff; } public foo aMethod(AClass param1, AnotherClass param2) throws Foon { stuff; } Use braces even if the consequent or loop body is one line. Never put conditions and their consequents on the same line: if (....) { y = f(x); } // BAD Line breakageFormat lines to fit within 80-characters. First choice for breaking up long lines is to indent so that parameters line up: somevar = methodCall(expr1, innerCall(expr2, expr3), expr4); If this does not work (because you are already too deeply indented or because expressions themselves are too complicated), break at a logical point and then indent one level deeper than the start of the expression: somevar = reallyReallyReallyReallyLongMethodCall(longparameterexpr, extremelylonglonglongstuff, evenmorestuff, evenmoreevenlongerstuff, yetmorestuff); The exception is when the thing being continued is itself a conditional or a method declaration which itself would be followed by indented code. In such cases the continuation should be indented two levels deeper. E.g.: if (aReallyLongPrettyComplicatedConditionalExpression && anotherOne && yetAnotherOne && stillMore) { consequences; } ExceptionsUse exceptions. Don't write methods that indicate error conditions by returning special values that have to be checked; have them throw exceptions instead. Then catch these exceptions. Catch exceptions and handle them sensibly. Don't handle exceptions by simply discarding them. Don't handle exceptions by printing error messages and stack traces, unless you KNOW you are in some reasonable context for doing so (e.g., the top of a command-line interpreter loop). If you do handle exceptions by printing error messages and stack traces, output them to System.err, not System.out. Don't catch exceptions indiscriminately (e.g., don't catch Exception unless you have a REALLY good reason). Note: a more comprehensive set of guidelines for exception usage will be forthcoming, giving a taxonomy of exception types and principles for their sensible enjoyment. Irksome habits some people haveThrow and return statements should look like statements, not method calls: return aResult; throw new FoobarException("hey!"); not
return(aResult); throw(new FoobarException("hey!")); Don't put spaces between a method name and the parameter list in either calls or declarations: doFoobaration(47, mySnozzgrom); not
doFoobaration (47, mySnozzgrom); Don't put spaces between a statement and its terminating semicolon. If you have a boolean flag that you are testing for falsehood, the test is: if (!flag) { ... not
if (flag == false) { ... Certainly you should use parentheses for disambiguating complex expressions, but don't get all silly about it. Java/C/C++ operator precedence rules may be a bit obtuse at times, but they're not crazy. Use parentheses on the weird cases (e.g., the ?: operator), but multiplication does take precedence over addition, and comparison does take precedence over and and or, and that's mainly what's important. My eyes hurt from trying to parse conditionals which are illegible because every single subexpression has been parenthesized: Use if (0 < i && i+1 <= k+1 && j == k-1) ... or maybe
if ((0 < i) && (i+1 <= k+1) && (j == k-1)) ... but not
if (((0 < i) && ((i + 1) <= (k + 1))) && (j == (k - 1))) ... Avoid assignments within conditionals. They're too easy to misread. DocumentationComment your code! And make the comments useful and accurate - which means keeping them up to date. Don't forget that comments are not code; the program doesn't execute them. If what the code does and what the comments say it does are different, the result is bad confusion (by the way, bugs in comments which you find should be reported to ec_bugs just like any other). Don't write uncommented code with the intention of commenting it later. Later usually doesn't come. Also, I've found that the mental discipline of writing clear comments as you code actually increases significantly the odds of producing bug free code on the first try. Comment for javadoc, even on private things. (Javadoc comments on private things are currently ignored by javadoc but our soon-to-be-available edoc tool will use this info, and human readers certainly can use this info too). FYI, documentation on javadoc itself can be found at http://www.javasoft.com/products/jdk/1.1/docs/tooldocs/solaris/javadoc.html Use HTML tags in your javadoc only very lightly, if at all, but do use @param, @returns, etc. And make your makefiles have targets for running javadoc on your code. Use javadoc commenting conventions in C code too. It's a reasonable notation for describing functions. And once you've developed the javadoc habit from Java, using it in C too is quite a natural thing to do. When we have a chance we'll produce a tool to process javadoc comments in C (and also in E code that javadoc currently chokes on). Implementation comments are the non-javadoc ones. Use implementation comments liberally. Always be skeptical as to whether something is self evidently obvious. Use longer class, method, procedure and variable names in preference to short names that require a comment to be comprehensible. In any case, instance variable declarations should be accompanied by brief comments stating what the variables are for. By convention, the easily-grepped-for string "XXX" in a comment flags something demanding future attention. Use this for things that should be taken out before ship (kind of like those big red "REMOVE BEFORE FLIGHT" tags on airplane parts), known hacks that need to get fixed, questionable security situations that need to be revisited, etc. Chip has also written up more extensive guidelines (XXX javadoc guidelines not found) for using Javadoc at Communities.com. Security and robustnessNo public instance variables. No public mutable static variables. No static methods which confer authority (i.e., which let you effect the state of the system or the outside world or which provide access to objects that let you do this). Don't directly refer to Java library classes (such as java.io.FileOutputStream) which statically confer authority, unless what you are doing is writing a wrapper to protect other people from having to break this rule. Use the EEnvironment to obtain access to privileged powers rather than using class names. Avoid separation of designation from authority, even when you don't think the authority concerns anything important. For example, don't create methods where you indicate things via, say, string parameters that get looked up in hashtables, if you can indicate things by passing objects that directly embody the operations desired. More generally, try to program in an object-oriented style. This should be one of those things that goes without saying, but experience shows that it's not. In particular, don't write methods that take a string or a number that is then used in a switch statement or cascaded-if to decide what to do - just pass an object that KNOWS what to do; it's cleaner and more extensible. It's also generally bad to write predicate methods of the form isFoo to determine if an object is a foo or not - usually being a foo means that it supports some kind of foo operations, in which case this should be reflected in the object's type and you should be able to test it with the instanceof operator. Similarly, you generally shouldn't create objects with methods of the form: if (iAmAFoo) { actOneWay; } else { actADifferentWay; } This is what classes are for. If you really need to do a test of this sort, the form is: if (someobj instanceof SomeKindOfFoo) ... |
||||||||||||
Unless stated otherwise, all text on this page which is either unattributed or by Mark S. Miller is hereby placed in the public domain.
|