Best Practices for Kernel code

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.

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