-
Notifications
You must be signed in to change notification settings - Fork 157
Style Guide
The LinuxForHealth FHIR Server has been written by many individuals over many years. Formatting has not been strictly enforced, but we'd like to improve it over time, so please consider the following points as you change the code.
This section provides both a Style and a Code Review Guide for FHIR (and Java projects in general). It also includes tips on where to focus attention to find common bugs. Code reviews should not only look for defects present in the current code, but also be aware how the current implementation might be prone to regression in the future.
This guide does not describe the formal review process, nor any official project documentation associated with such a review.
Leave the code better than you found it.
Branch-naming convention:
issue-<#number>
Commit message convention:
short description #<number>
long description
- Catch defects early
We could use a long list here to describe the various goals of effective code review and consistent styling...but really Catch defects early says it all. Everything else (for example "improve product quality") just comes under this one umbrella.
-
Follow secure coding best practices.
-
Write tests. Pull Requests should include necessary updates to unit tests (src/test/java of the corresponding project) and integration tests (in the fhir-server-test project).
-
Use comments. Preferably javadoc.
Comment all types and methods.
Each member should be preceded by a one line comment.
It is acceptable to use one comment for a group of related members if their purpose is obvious from their names.
-
Separation of concerns. Apply OO principles of information hiding, loose coupling and high cohesion.
-
Keep the documentation up-to-date. Project documentation exists under the docs directory. We have a Conformance page for documenting conformance to the specification, a User Guide for FHIR Server administrators, and a number of other guides / module READMEs.
-
Indentation: 4 spaces, not tabs. For this we have a checkstyle rule which will fail the build if you're using tabs. We also prefer spaces over tabs in JSON and XML, but its not strictly enforced.
-
All members should be placed before the first method.
-
All constructors should be placed before methods.
-
Members almost always should be final when initialized in the constructor.
-
Members almost always should be private. Use getters and setters.
-
Hide implementation details inside the class.
-
Do not return modifiable collections.
-
Do not use synchronized methods. Keep synchronization internal.
-
Remove unused imports
-
Remove warnings
-
If TODOs are committed, they should be associated with an issue
-
Always use blocks
// DO: if (test) { x++; doSomething(); } else { doSomethingElse(); } // DON'T: if (test) x++; doSomething();
-
Use try-with-resource instead of finally.
Implement Autocloseable when creating your own resources.
-
Never rely on the finalizer to free resources - it is not guaranteed that the finalizer runs
-
Override toString() to provide single-line descriptions of the class content.
-
Always obfuscate passwords and other sensitive credentials when logging/writing program output.
-
Keep log entries to single-lines where possible
This benefits downstream log processing tools.
-
Use consistent try-catch formatting
try { doSomething(); } catch (SpecificException x) { cleanUpTheMess(); } catch (MoreGeneralException x) { cleanUpSomeMore(); } finally { logger.exiting("foo"); }
-
Only catch an exception if you can do something about it...or need to
-
Use java.util.logging
-
Always use nanoTime for measuring elapsed times, never currentTimeMillis which is subject to wall clock changes.
Avoid other logging frameworks if possible. java.util.logging works well, and is supported by Liberty Profile.
-
Quote strings when printing log messages - for easier detection of whitespace issues:
"Parsing of environment variable '" + KUB_EVENTSTREAMS_BINDING + "' has failed." // do this "Parsing of environment variable " + KUB_EVENTSTREAMS_BINDING + " has failed.` // not this
Ideally, this should be made into a utility function.
-
Don't add @author to class
/** * @author myname */ public class MyClass {
-
Don't add @override comments
/* (non-Javadoc) * @see com.ibm.fhir.database.utils.api.IDatabaseTarget#runStatement(java.lang.String) */
-
Write tests. Pull Requests should include necessary updates to unit tests (src/test/java of the corresponding project) and integration tests (in the fhir-server-test project)
-
Keep the documentation up-to-date. Project documentation exists under the fhir-docs repo and we have a CHANGELOG for tracking user-visible changes, a Conformance page for documenting conformance to the specification, and a User Guide for FHIR Server administrators.
-
Use good indentation.
-
Use spaces (not tabs) in java source. For this we have a checkstyle rule which will fail the build if you're using tabs. We also prefer spaces over tabs in JSON and XML, but its not strictly enforced.
-
Use spaces after control flow keywords (they're not function calls!) if/for/while blocks must always have { }
- Unit-tests?
- Do the unit-tests cover boundary conditions?
- Do the unit-tests cover concurrency?
- Is the code commented?
- Are the comments helpful and, most importantly, accurate?
- Loose coupling and high cohesion
- equals and ==
- hashCode and equals
- compareTo
- Always use { ... }
- Resource leakage - try-with-resource
- Logging
- Barriers around debug logging (avoiding expensive String construction)
- Concurrency control - synchronization/lock etc
- Lock leakage - finally unlock?
- Over-synchronization
- Double-checked locking (DCL) errors
- Singleton initialization - does it follow our chosen pattern?
- Unit tests with edge cases
- Algorithms - e.g. linear searches, loop nesting, joining in Java
- Unbounded recursion
- Use of Patterns
- Clone/Deep copy
- Assumptions on order (e.g. iterating over HashMap)
- Use of Vector
- Charset for IO operations
- Reading files into memory
- Streaming compression/JSON processing
- Correct data type usage (int instead of boolean)
- Random vs. SecureRandom
- Exception handling
- Use of StringBuilder instead of StringBuffer
- Multiple loop or routine exits
- Switch statement construction
- Default return values
- Method/block size
- Mixing app-server time with database time.
- Timezone handling (DST transition handling if non-UTC)
- Java SQL date/timestamp conversion
- Avoid SELECT * FROM unless the framework handles column changes
- Instrumentation - timing operations
- Implementation leakage (e.g. propagating SQLException beyond the data access layer
Original Author is the FHIR Team
FHIR® is the registered trademark of HL7 and is used with the permission of HL7. Use of the FHIR trademark does not constitute endorsement of this product by HL7.
IBM and the IBM logo are trademarks of International Business Machines Corporation, registered in many jurisdictions worldwide. Other product and service names might be trademarks of IBM or other companies. A current list of IBM trademarks is available on ibm.com/trademark.