Coding guidelines - SAF2/documentation GitHub Wiki
Coding guidelines
Most of the guidelines presented in this section are extracted and summarised from the software developer best practice guide of GÉANT project [Marek Lewandowski Antoine Delvaux Tihana Zuljevic Candido Rodriguez Rade Martinovic Spass Kostov Ognjen Blagojevic Branko Marovic, Marcin Wrzos and Waldemar Zurowski. Gn3 software developer best practice guide 2.0. online: here, 2010.], a very comprehensive description of various best practices. Additionally, some of these guidelines are based on the Development, release and testing procedures online document of MyGrid project.
General rules
Use English – Results of whole work in the project will be used and maintained in a multilingual context, because of that please use English in both source code (i.e. names of variables) and documentation
Keep your code simple – Please keep in mind the code is written once but read many times
Keep the implementation simple – "Smart" tricks, hacks or optimisations should always be avoided, unless there are specific functional requirements related to them
Avoid repetition – If given piece of the code is duplicated, you should encapsulate it and create new class/method/function
Some other complementary recommendations are:
- Write unit tests before coding, to verify bug and desired behaviour
- Add integration tests to the integration test module
- Ensure build is not broken before committing
- Monitor emails from CruiseControl about build and test failures - Fix build issues immediately
- If unsure about where to place code, contact the release manager to confirm whether your code needs a new module, and where it should go
- Never copy code. If code could be reused, feel free to do a refactoring to a common class/module. Coordinate with other team members
- External dependencies must be to stable versions pulled from an official Maven repository - and should not be added to the project as JARs or copied source code
- Update the @Author tag on any class modified Also, to assure interoperability between various systems, all source code files should be encoded using only ASCII (Latin-1) characters (if necessary use native2ascii for Java classes). Each class should be placed in its own separate file, named after the class. You should also avoid using white spaces in the names of all files.
Assuring code readability
Simplicity of the code is in fact quite complex issue, among other factors which influence code readability you should remember about the following things:
- Use meaningful identifiers using terminology that applies to the domain also helps a lot.* Do not hesitate to use long names of variables if this adds clarity.
- Avoid abbreviations and acronyms.
- In documentation, describe the variable’s purpose rather than its type.
- Avoid negated Boolean variable names e.g. isNotSet.Code Conventions
Code conventions are programming guidelines that focus on the physical structure and appearance of a program, rather than its logic. They make the code easier to read, understand, and maintain2. We would like to suggest using well established standards in terms of code conventions:
- for Java – Sun’s Java Code Conventions (JCC) [Sun Microsystems. Code conventions for the java tm programming language. online: here, 1999.]
- for Ruby – as described in "The Unofficial Ruby Usage Guide" [Ian Macdonald. The unofficial ruby usage guide. online: here.]
Below you will find set of suggestions mostly related to Java development, some of them may also be applied to Ruby.
- Imported classes should always be listed explicitly. Prohibit ”*” in import statements
- This gives you more control at the expense of more import statements, and IDEs easily organise imports
- In Java class variables should never be declared public. Use getter/setter convention if you have to expose content of given variable
- Avoid complex conditional expressions. Presence of complex if statements is a clear sign that code needs to be redesigned
- Avoid using magic numbers in the code. Instead declare numbers as named constants
- Logical units within a block of code should be separated by one blank line
- Use left-hand comparison style with constants or expressions, e.g. if (”example”.equals(str)), if str is null, the expression will return false instead of raising a null-pointer exception.
- Use properly configured code formatters before committing code into source code repository. This would help to avoid conflicts.
- Use tools like Findbugs and PMD often, this should help to keep your code clean
Class and Interface declarations should be organised in the following order:
-
Class/Interface documentation.
-
Class or interface statement
-
Class (static) variables in the order public, protected, package (no access modifier), private.
-
Instance variables in the order public, protected, package (no access modifier), private.
-
Constructors.
-
Methods (no specific order).
Comments in the source code
- Comments should be in English
- Avoid any comments that are likely to become outdated as the code evolves
- If a comment no longer applies, you should modify or remove it
- Avoid replicating information that is obvious from the code
- Rather than commenting everything, consider if you could rewrite the code to make it clearer
- When using static variables you should describe why they are declared static
- Code that has been ”commented out” should be explained or removed
- All class files should contain formally required comments, as copyright header or author name
- Comments in the beginning of the class should clearly state about role and responsibility of given class
- All classes, interfaces and, public and non-trivial internal methods should contain a descriptive documentation
Exception handling and logging
Most of the remarks presented in this section refers to Java development.
- Do not use null or similar value as an indicator of error. Instead of doing so, appropriate exception should be thrown.
- Avoid ambiguous use of try-catch blocks, catch specific exception (not general once like java.lang.Exception) and handle them appropriately.
- Catch block should not both log and throw another exception, because this doubles the log.
- Do not use System.out or System.err (especially in web applications), use appropriate logging facility, e.g., log4j or java.util.logging.
More examples on exception handling are also described by McCune [Tim McCune. Exception-handling antipatterns. online: here, 2006.]. As it was mentioned all caught exception should be properly handled and logged. All available logging systems introduce several levels of logging. It is important to understand the meaning of each of those levels. The most important are described below.
FATAL – Serious errors that are likely to lead to premature application termination, e.g., lack of memory, lost database connection.
ERROR – Errors in the regular operation of the system which prevent normal program execution but are likely to allow the application to continue running.
WARN – Should be used to record transient problems or undesirable, unexpected or potentially harmful situations that are not necessarily errors.
INFO – Describes interesting runtime events, like startup, shutdown, receipt of user request. These messages should inform on the progress of the application at coarse-grained level during its normal operation.
DEBUG – These messages are produced by code added to debug an application for tracing its flow or internal data.
There are several Java libraries which offer logging features, including: Log4J, Apache Commons Logging and java.util.logging. We recommend using Log4J as a logging facility in project's implementation as this is the most widely used and flexible library.
The Gn3 software developer best practice guide [Marek Lewandowski Antoine Delvaux Tihana Zuljevic Candido Rodriguez Rade Martinovic Spass Kostov Ognjen Blagojevic Branko Marovic, Marcin Wrzos and Waldemar Zurowski. Gn3 software developer best practice guide 2.0. online: here, 2010.] contains several recommendations regarding logging practice:
- When logging, related data should be logged in a single message this help to understand what is happening during debugging.
- Logging system should be configured to inform not only about error message and stack trace. Log needs to contain information about date and time of the event.
- Log relevant and meaningful information only.
- Avoid logging at frequently or iteratively executed spots.
- Direct messages to different loggers according to purpose.
- Wrap time-consuming log messages in conditional statements e.g. if (logger.isDebugEnabled())