-- FILE --------------------------------------------------------------------- -- name : DevGuideLines.txt -- project : BoarderZone: Development Environment -- created : Leon Poyyayil - 2001-01-26 -- language : English -- environment: the human readers mind ... ;-) -- copyright : (c) 1990-2024 by Leon Poyyayil (private), Switzerland -- license : this is free software licensed under the GPL. see COPYING ----------------------------------------------------------------------------- Table of Contents line ----------------- ---- 1. Executive Summary ..................................................... 24 2. Organizational Issues ................................................. 35 3. Naming Conventions .................................................... 55 4. Coding ............................................................... 110 5. Style ................................................................ 163 A. References ........................................................... 325 B. Revision History ..................................................... 332 C. Authors contact info ................................................. 346 1. Executive Summary -------------------- This document intends to provide a basis to coordinate the software development process for the BoarderZone.net namespace. It covers the most basic issues to ensure the code developed by different people can be viewed, understood and enhanced by others. For this to work it is necessary that everybody sticks to some common rules which are outlined herein. 2. Organizational Issues ------------------------ - Documentation has to be kept in non-binary formats only. => usage of .txt, .htm, .xml, .rtf, ... Advantages: - independent of (possibly platform dependent) tools - can be 'grepped' through ... - can be compared with standard diff tools - Test programs go into a sub-package named "test" of the package of the module to be tested. - All identifiers, comments and documentation are to be kept in English => least common denominator of languages in IT (more folks are comfortable with English than with German) => supports a fluid reading of the code without necessity to switch between languages (keywords are English anyway) 3. Naming Conventions --------------------- - Generally: according to the Java guidelines, see [FLAN] in short: - packages: lowercase names (e.g. "net.boarderzone.util") - classes: mixed case style, starting with a capital letter (e.g. "SuperDuperTool") - interfaces: same as for classes, but DON'T start with the letter 'I' to distinguish them (e.g. "IClientHandler"). instead the implementing classes should append an "Impl" to their name. this encourages working with the interfaces instead of the implementations ... - methods/variables: mixed case style, starting with a lower case letter (e.g. "getMemberValue()" ) - use self describing names rather than cryptic abreviations. the typing overhead for writing the code is worth the better readability! - Avoid underscores in identifiers (for better 'typeability') - If an identifier contains a commonly used abbreviation, don't write it in all capital letters (e.g. "MyHTTPHandler") but rather capitalize it as a normal word, e.g. MyHttpHandler. This increases readability. - Give all variable names a one- or two-letter lower case prefix to prevent confusion between variables of different scopes etc: - 1. scope prefix: - 'c' for class statics - 'm' for class members - 'l' for method locals - 'p' for method parameters - 2. type prefix: - 'n' for numeric values of base types - 'b' for boolean values - constants are to be kept in all uppercase letters Examples: - a global numeric constant: public static final int MY_ID = 12345; - a value accessible to all class instances: private static boolean cbInitialized = false; - a member instance of some object private SomeClass mOutputFrame; - an instance method of some class: private void myFunc( final int pnValueToSet // this is a comment for this parameter ) { final int lnFactor = 10; // a local constant mnValue = pnValueToSet * lnFactor; // set the member ... } // myFunc 4. Coding --------- - All code has to be located under the package net.boarderzone - All data members are private, access exclusively via methods => do not declare public or protected data members! => makes sure the state of an object can not be rendered inconsistent by some extern code. The only exception to this are package protected members which allow direct access to the sibling classes in the same package. This is allowed because normally within a package the classes are written to cooperate closely and hence the author has complete control because no classes will be added by others. However, this should only be used if really necessary or if it allows significant simplification. - Order of methods in the file: first constructors, then other methods grouped according to functionality. Don't artificially separate methods which functionally belong together just because of different access levels (public/protected/private). - Avoid returning mutable class instances of members (java strings are immutable) because these objects can then be modified from outside, what breaks the desired encapsulation! Exceptions can be made from this rule if the returned class ensures its proper state and all possible mutations will not render the owning class instance invalid. - If returning class instances is necessary and its proper state cannot be enforced, then do it by returning a (deep) copy of the object instead of the actual member => this is a performance loss, but currently the only way to pre- vent breaking the encapsulation ... :-( This might be changed in the future, when java (finally) supports the 'const' keyword (currently only reserved). - Define a copy constructor and a copy method for classes with data members whenever possible (when doing this, implementing the Duplicatable interface isn't much more work, so do it ...) => provides for easy deep-copying of an object when returning it from an accessor method => the additional (covariant) duplicate() method has the advantage of returning an object of the correct type, so no casting is necessary under certain circumstances - Initialize all variables of base types explicitly (for readability) if the default value is different from the java standard default value. - Mark all method parameters as final to prevent their accidential modification in the method body. 5. Style -------- - No use of the TAB character, do all indenting with spaces => prevents code layout problems when working with different editors that have different settings for the tab width (code that looks nicely arranged for a tab width of 8 may look pretty unreadable in an editor that uses a tab width of 4) - Use a consistent 'tab' (indentation) width of 2 => enough for good readability without extending the code width too much for deeply nested sections - Keep the maximum line length below 100 chars => less problems when printing the source code (otherwise ugly wrapping occurs or the end of the line is not visible ...) - Prevent trailing spaces at the end of lines - Prevent trailing empty lines after the end-of-file line - Usage of CR/LF for line breaks throughout all files => this is 'on the safe side' when looking at the code on a platform with a different end of line marker, because the lines are still distinct. When viewing a file with a LF line break on a system with CR/LF or LF/CR end of line marker, it appears as a single _very_ long line ... Exceptions to this rule are only allowed if a file doesn't work with the CR/LF line ending (e.g. unix shell scripts). - Every statement has its own line in the file => easier debugging (step through, stack trace line numbers, etc) example: if ( lSomeClass.doSomething() ) lSomeClass.doSomethingElse(); when stepping through the line above it's not intuitively clear which statement will be executed next ... - Avoid changing the values of non-final method parameters to prevent influencing the calling code (treat them as constant objects). - Always terminate case statements with a break (don't use the "fall through" possibility for better encapsulation of the different cases). Only don't do this if it would result in unreachable code (e.g. after a return or throw statement). - Try to avoid the continue statement (don't write "spaghetti code") - Provide only one return statement in a method (see above ...) => otherwise cleanup code has to be kept in multiple places (e.g. closing network connections etc.) - if, else, while and do statements shall be followed by a block in braces, even if it has only a single statement or is empty => prevent the (surprisingly rather common) error of changing the program flow when commenting out a single line ... - Dates should be kept in the format yyyy.mm.dd (especially for file names and log entries) for correct sorting. Sorting files according to their file system timestamp will not yield the desired results when the files have been modified ... - _each_ file has a file header of the following (general) form: // -- FILE ------------------------------------------------------------------ // name : <filename> // project : <project> // created : <author> - <date> // language : <java|shellscript|...> // environment: <JDK 1.3.0|bash|...> // copyright : <copyright notice> // license : <license type & reference> // -------------------------------------------------------------------------- Of course the comment characters have to be adapted to the various file formats (xml, sql, java, ...) but the information of each line should always be present. - _each_ file ends with an end-of-file delimiter line and an empty line - _each_ class/interface has a header of the following form: // -- CLASS ----------------------------------------------------------------- /** This is a short description of the class. Some more explanation on the usage/behavior of the class. @author <author> @version <version> @since <version> *///------------------------------------------------------------------------- - _each_ method has a header of the following form: // -- METHOD ---------------------------------------------------------------- /** Overloaded version of this method. outputs a simple string to state where we are ... @since <version> @param pText the text specifying where we've been called from @return state of completion: true if all is ok *///------------------------------------------------------------------------- more tags can be added if necessary/desired, but the @since tag should always be present - avoid multi-line comments (except for the javadoc class/method headers) => better possibility to temporarily disable a lot of code => no problems with nesting such comments (the first closing tag closes all opening comment tags ...) - repeat the method name as comment on the terminating line of the method => clear which method ends even when only looking at the last lines => especially helpful when a printout of a method spans a page break ... Example: public void myFunc() { // do something here } // myFunc - indentation according to the following examples: private boolean myFunc( final int pnValueToSet, // the value as read from the file final int pnFactor // the factor to scale the value with ) throws Exception { boolean lbValueSet = false; int lnFactor = pnFactor; // create a local copy we can modify if ( lnFactor < 0 ) { throw new Exception( "invalid factor: below zero" ); } else if ( lnFactor == 0 ) { throw new Exception( "invalid factor: is zero" ); } for ( int lnI = 0; lnI < lnFactor; lnI++ ) { // do something here } while ( lnI > 0 ) { // do something else here } do { // yet something else } while ( lnI < 0 ); switch ( lnI ) { case 0: // something here break; case 1: // something else here break; default: // yet something different here break; } mnValue = pnValueToSet * pnFactor; // set the member ... lbValueSet = true; if ( mnValue > 0 && pnFactor < 2000 && ( lbValueSet || mnValue == 0 ) ) { // nothing to do here with this weird condition ... } return lbValueSet; } // myFunc A. References ------------- [FLAN] - Flanagan, David Java In A Nutshell, ISBN 1-56592-487-8 Chapter 7 - Java Programming and Documentation Conventions B. Revision History ------------------- 2001-01-26 - lep - created 2001-02-12 - lep - pre-release for public comment ... 2001-11-14 - lep - changed prefix for variables in naming conventions 2002-01-28 - lep - changed naming convention for interfaces 2004-04-22 - lep - adapted to current style & requirements 2004-06-19 - lep - changed to require final keyword where appropriate 2004-06-19 - lep - changed table of contents to point to line numbers 2004-08-16 - lep - fixed some minor typos and added some clarifications 2007-09-20 - lep - updated to reflect new style and findings 2023-10-17 - lep - minor formatting changes C. Authors contact info ----------------------- Leon Poyyayil (lep) : leon.poyyayil@boarderzone.net -- EOF ----------------------------------------------------------------------