Skip to content

Contributing

JP edited this page Jul 7, 2022 · 7 revisions

Licensing

All contributions to the CQF Ruler will be licensed under Apache 2.0

Branch Policy

All new development takes place on <feature> branches off master. Once feature development on the branch is complete, the feature branch is submitted to master as a PR. The PR is reviewed by maintainers and regression testing by the CI build occurs.

Changes to the master branch must be done through an approved PR. Delete branches after merging to keep the repository clean.

See Release Process for related information.

Coding Conventions

Extensions

If you're using VS Code, the cqf-ruler repo suggests a list of Java extensions for static and style analysis. Please enable these recommended extensions, as they help detect issues with contributions prior to committing them or opening a PR.

Style

The CQF Project has adopted an over-arching goal to contribute back to HAPI. To this end the CQF Ruler project has adopted the HAPI Coding Conventions: https://github.com/hapifhir/hapi-fhir/wiki/Contributing

The CQF Ruler repository contains an .editorconfig file and a Checkstyle Maven plugin to enforce some of these conventions. This will cause a build failure in the event of a Checkstyle error.

Results of Checkstyle errors can be found in the corresponding checkstyle-result.xml file.

Best Practices

Code should generally follow Java best-practices as outlined in Effective Java 3rd Edition.

If using VS Code, the Sonarlint plugin will be suggested to help detect issues early on.

Testing

The cqf-ruler-test project provides scaffolding for unit and integration tests. Contributed code should generally have good test coverage, though a formal standard has not yet been established. See the example plugin for a demonstration of basic integration tests.

The extended test integration class RestIntegrationTest has database reset method with annotation @AfterAll. Similarly RestUnitTest has database reset method with annotation @AfterEach. This it could be possible that tests residing in same suite will share resources. And in circumstances when it is necessary to execute individual tests with the testing lifecycle set to PER_METHOD.

Configuration settings for integration tests should be implemented in the properties element of the SpringBootTest annotation.

Example:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { HelloWorldProviderIT.class,
  HelloWorldConfig.class }, properties = {
    "hapi.fhir.fhir_version=r4",
    "hello.world.message=Howdy"
  })

Javadoc

The CQF Project has strict checking for Javadoc enabled. This will cause a build failure in the event of a Javadoc warning. Visit https://www.oracle.com/technical-resources/articles/java/javadoc-tool.html for more info.

Results of Javadoc can be found in the output of the build.

Design Conventions

Discovery

Following conventions such as these make it easier for the next developer to find code that's already been implemented as opposed to reinventing the wheel. The utility conventions outlined below are one type, while the plugin conventions are another.

Plugins

See the plugins directory for examples of current plugins.

In general, there is one plugin per implementation guide. All supported versions of FHIR are included in the same plugin. The plugin artifact should be named cqf-ruler-<implementation-guide-abbreviation>, while the directory in which it's contained should be simply cqf-ruler-<implementation-guide-abbreviation> For example, the Clinical Reasoning module is implemented in the plugins/cr folder, which builds an artifact called cqf-ruler-cr. In the event there's a conflict, use the name of the implementation guide in lower case and hyphenated. For example, cqf-ruler-case-reporting.

To make contribution back to the HAPI FHIR Server easier, configuration keys for plugins should generally use a prefix of hapi.fhir.<ig-abbreviation> prefix, For example, hapi.fhir.sdc.enabled=true

Utilities

Types of Utilities

In general, reusable utilities are separated along two different dimensions, Classes and Behaviors.

Class specific utilities are functions that are associated with specific class or interface, and add functionality to that class.

Behavior specific utilities allow the reuse of behavior across many different classes.

Class Specific Utilities

Utility or Helper methods that are associated with a single class should go into a class that has the pluralized name of the associated class. For example, utilities for Client should go into the Clients class. This ensures that the utility class is focused on one class and allows for more readable code:

Clients.forUrl("test.com")

as opposed to:

ClientUtilities.createClient("test.com")

or, if you put unrelated code into the class, you might end up with something like:

Clients.parseRegex()

If the code doesn't read clearly after you've added an utility, consider that it may not be in the right place.

In general, all the functions for this type of utility should be static. No internal state should be maintained (static final, or immutable, state is ok). If you final that your utility class contains mutable state, consider an alternate design.

Examples

  • Factory functions
  • Adding behavior to a class you can't extend
Behavior Specific Utilities

If there is behavior you'd like to share across many classes, model that as an interface and use a name that follows the pattern "ThingDoer". For example, all the classes that access a database might be DatabaseReader. Use default interface implementations to write logic that can be shared many places. The interfaces themselves shouldn't have mutable state (again static final is ok). If it's necessary for the for shared logic to have access to state, model that as an method without a default implementation. For example:

interface DatabaseReader {
   Database getDb();
   default Entity read(Id id) {
      return getDb().connect().find(id);
   }
}

In the above example any class that has access to a Database can inherit the read behavior.

Examples

  • Cross-cutting concerns