Best Practices for Kernel code
11-Dec-2008 This work mostly refers to Kernel 1 and is being updated and integrated into Best Practices for High Quality Code by @Former user (Deleted) and @Former user (Deleted).
Information
This defines the best practices and standards for code being added to the Sakai kernel. This should include suggested best practices as well as required standards.
- 1 Minimum Requirements
- 1.1 Paging performance focused interfaces
- 1.2 All caching must use centralized caching
- 1.3 No swallowed exceptions
- 1.4 No dependencies on code outside the kernel
- 1.5 No usage of static covers
- 1.6 No lookups of components (spring beans) when they can be loaded via injection
- 1.7 Programmatic testing required
- 1.8 No data inconsistency
- 1.9 Static utils should be able to run in isolation
- 2 General Best Practices
- 3 Other resources on Best practices
Minimum Requirements
Defines the minimum requirements that must be met by code going into the Sakai kernel. These are primarily to maintain high performance and ensure that the code is maintainable and flexible.
Paging performance focused interfaces
All kernel interfaces should provide methods to retrieve large record sets in pages. For example, one should be able to retrieve a set of all users like so (where inputs of 0 and 0 would retrieve all users in the system):
List<User> getUsers(long startResult, long maxResults);
Methods which provide for limited retrieval should also include this "pagination" capacity. For example:
List<User> getUsersByEmail(String email, long startResult, long maxResults);
All caching must use centralized caching
Heavily used parts of the kernel (user lookups, authz permission checks, etc...) must be cached. The caching should be handled using a centralized cache mechanism and should NOT be handled using a collection or (even worse) a syncronized collection. Using Caching in Sakai should provide information about how this should be done.
No swallowed exceptions
All exceptions in the kernel must be handled. They should either be rethrown as a runtime exception or handled in the code according to the logic and situation. There should never be empty exception blocks with a comment in them (except in the case of a try-catch-finally-try-catch).
No dependencies on code outside the kernel
Kernel code can have absolutely no dependencies on code outside the current kernel. If packages need to be added to the kernel then this must be kept to the absolute minimum and must be approved by the technical community.
No usage of static covers
Kernel code should not make use of the static covers (also known as the "singleton" method in Java, not to be confused with the use of Spring singletons) and should instead use Spring setter injection. This makes testing and debugging easier (and possible) and also makes it easier to debug issues. It also provides for a more flexible and well defined kernel. Code which makes use of covers will be refactored.
No lookups of components (spring beans) when they can be loaded via injection
Kernel code should always use setter injection to load singleton dependencies. Loading components via lookups and methods like "getBean" makes testing virtually impossible. It also makes the bean dependency graph unpredicatable. The issues are generally the same of the ones encountered when using static covers.
Programmatic testing required
All code used in the kernel must have programmatic tests. These could be unit tests, integration tests, system tests or even validity and load tests. The important thing here is to make sure that the code is behaving the way it is designed to behave. Testing also ensures that code is more change tolerant since the tests will fail if something changes improperly.
No data inconsistency
Logically atomic database operations must be wrapped by atomic database transactions. Depending on the operation, this may involve joining an open transaction or beginning a new one. In either case, no kernel code should leave the system in an inconsistent state.
Static utils should be able to run in isolation
Utils should not use anything that is not also static (and certainly should not depend on Spring beans).
Utils should strive to have no dependencies if possible.
General Best Practices
Other resources on Best practices
Style and best practices - Guide on Java best practices from Alan Berg, NL
http://www.javapractices.com/ - Good tips on general Java development in many areas