Skip to content

Latest commit

 

History

History
87 lines (74 loc) · 4.75 KB

CONTRIBUTING.md

File metadata and controls

87 lines (74 loc) · 4.75 KB

GoodData Java SDK - Contribution guide

Below are few rules, recommendations and best practices we try to follow when developing the GoodData Java SDK.

Paperwork

Committer

  • The commit message:
    • must be written in the imperative mood
    • must clearly explain rationale behind this change (describe why you are doing the change rather than what you are changing)
  • The pull request:
  • Add usage examples of new high level functionality to documentation.

Reviewer

Ensure pull request and issues are

  • properly labeled (trivial/bug/enhancement/backward incompatible/...)
  • marked with exactly one milestone version

Design

Structure

  • Package names for DTOs and services should be named in the same manner as REST API.
  • Don't create single implementation interfaces for services.

DTOs

  • All DTOs which can be updated should be mutable. Please keep mutable only the fields which are subject of change, the rest should be immutable.
  • Create method named String getUri() to provide URI string to self.
  • Introduce constant with URI:
    • public static final String URI = "/gdc/someresource/{resource-id}";
    • If you need also constants with UriTemplate, do not put them into DTOs not to drag Spring dependency into model module.
  • Put Jackson annotations on getters rather then on fields.
  • Consider the visibility - use package protected when DTO is not intended for SDK user, but is needed in related service.
  • Test all DTOs using JsonUnit.
  • Naming:
    • Uri for URI string of some resource
    • Link for structure containing at least category (e.g. "self") and URI string (can contain also others like title, summary, etc.)

Enums

  • Use enums sparingly, because they don't work with REST API changes (eg. new value added on the backend) never use them when deserializing.
  • Where make sense, use overloaded methods with an enum argument as well as String argument.

Services

  • When programming client for some polling return FutureResult to enable user asynchronous call.
  • Create custom GoodDataException when you feel the case is specific enough.
  • Prefer DTOs to String or primitive arguments.
  • Method naming:
    • get*() when searching form single object (throw exception when no or multiple objects are found, never return null)
    • find*() when searching for multiple objects (collection of objects, never return null)
    • list*() when listing whole or paged collection of objects (return collection or collection wrapped by DTO)
    • remove*() (i.e. remove(Project project)) instead od delete*()
  • In addition to unit tests, write also integration tests and acceptance tests if possible. See "What to test where" in "Best practices" below.
  • Update documentation with usage examples.

Best practices

  • What to test where:
    • *Test = unit tests
      • focus on verifying bussiness logic, corner cases, various input combinations, etc.
      • avoid service tests using mocked RestTemplate - use integration tests with mocked API responses instead
    • *IT = integration tests
      • focus on verifying all possible outcomes of API calls
      • see common ancestor AbstractGoodDataIT setting up Jadler for API mocking
    • *AT = acceptance tests
      • focus on verifying the happy path against the real backend (so we're sure mocks in ITs are correct)
      • see common ancestor AbstractGoodDataAT setting up GoodData endpoint based on passed environment variables
  • Everything public should be documented using javadoc.
  • When you need some utility code, look for handy utilities in used libraries first (e.g. Spring has its StreamUtils, FileCopyUtils, ...). When you decide to create new utility class, use abstract utility class pattern.

Release candidates

We're using branches like "3.0.0-RC" for development of new major releases containing backward incompatible changes. Such RC branch is forked from master branch and has to be kept in sync later, when something is committed into master so RC can be merged to master when new major version is ready.

Do not use cherry-picks to keep branches in sync! Always use merge from master to RC.