Build, test, deploy
Trace-X is built using Maven and utilizes all the standard concepts of it. Test execution is part of the build process and a minimum test coverage of 80% is enforced.
The project setup contains a multi-module Maven build. Commonly used classes (like the Trace-X data model) should be extracted into a separate submodule and reused across the project. However, this is not a "one-size-fits-all" solution. New submodules should be created with care and require a review by the team.
The Maven build alone only leads up to the JAR artifact of Trace-X. To create Docker images, the Docker build feature is used. This copies all resources into a build image, builds the software and creates a final Docker image at the end that can then be deployed.
Although the Docker image can be deployed in various ways, the standard solution is to use the provided Helm charts, which describe the required components as well.
Code generation
There are two methods of code generation in Trace-X:
Lombok
The Lombok library is heavily used to generate boilerplate code (like constructors, getters, setters, builders…). This way, code can be written faster and this boilerplate code is excluded from test coverage, which keeps the test base lean.
Swagger / OpenAPI
The API uses OpenAPI annotations to describe the endpoints with all necessary information. The annotations are then used to automatically generate the OpenAPI specification file, which can be viewed in the Swagger UI that is deployed with the application.
The generated OpenAPI specification file is automatically compared to a fixed, stored version of it to avoid unwanted changes of the API.
Migration
Data migration is handled by Flyway.
Configurability
Trace-X utilizes the configuration mechanism provided by Spring Boot.
Configuration properties can be defined in the file src/main/resources/application.yml
Other profiles should be avoided. Instead, the configuration can be overwritten using Spring’s external configuration mechanism (see https://docs.spring.io/spring-boot/docs/2.1.9.RELEASE/reference/html/boot-features-external-config.html). The operator must have total control over the configuration of Trace-X.
Java style guide
We generally follow the Google Java style guide.
API guide
We generally follow the OpenAPI specification.
Documentation style guide
We generally follow the Google developer documentation style guide.
Unit and functional testing
General unit testing
-
Code coverage >= 80%
-
Writing methods which provide a response to be better testable (avoid void if feasible).
-
Naming of unit tests are as follows:
-
Use the given / when / then pattern for unit test structuring. E.g:
Integration testing
Each public API should have at least two integration tests (positive / negative).
For integration testing, the file tx-backend/src/main/resources/application-integration.yml
is used.
Additionally, you need to have a local Docker environment running.
For this, we recommend Rancher Desktop.
Clean code
We follow the rules and behaviour of: https://clean-code-developer.com/.
Secure coding standards
As there is no other guideline of C-X, we fix any vulnerabilities, exposures, flaws detected by one of our SAST, DAST, pen testing tools which are higher than "Very Low".
Trace-X technical class responsibilities
Controller
-
Has only one dependency to a facade or a service or a validator annotation
-
Has no own logic
-
Includes the Swagger documentation annotations
-
Has an integration test class
-
Uses a static mapper to transform a domain model into the response model
-
Returns a ResponseEntity<T>
Response object
-
Should be a public version of the domain object
-
Is a result of the transformation which will be done in the facade
-
Is not necessary if the domain object can be fully public
-
Is not allowed to be implemented in a repository or a DAO
Facade
-
Should have multiple service classes injected
-
Can be implemented in a controller
ServiceImpl
-
Responsible for retrieving data from storage
-
Performs business logic
-
Can be a http client
-
Returns a jpaEntity → domain object
-
Should only be implemented in a controller through an interface
Repository
-
Represents an interface to the underlying repository implementation which then uses the spring repository
Domain object
-
Mapped from an entity or from received external data
-
Will be used as a working model until it will finally be transformed to a response object or another domain which will be persisted later on
Config object
-
Should have the suffix .config at the end of the class
-
Includes beans which are automatically created by app startup
Constructing objects
-
Using builder pattern
-
Currently, we are using the constructor to create objects in our application. Main reason is to provide immutable objects.
-
As the handling with big loaded constructors is not easy and error-prone, it’s recommended to use the builder pattern to have a clear understanding about what we are creating at the point of implementation.
-
-
Using lombok for annotation processing