Code Review Checklist V0.3 Author Vaibhav Pandey
Code Review Checklist V0.3 Author Vaibhav Pandey
Version V0.3
Author Vaibhav Pandey
Coding Best Practice
CBP.1
CBP.2
CBP.3
CBP.4
CBP.5
CBP.6
CBP.7
CBP.8.1
CBP.8.2
CBP.9
CBP.10
CBP.11
CBP.12
UT
UT.1
UT.2
UT.3
UT.4
UT.5
UT.6
UT.7
UT.8
UT.9
UT.10
CT
CT.1
CT.2
CT.3
CT.4
CT.5
CT.6
CT.7
Loging
LG.1
LG.2
LG.3
LG.4
Pull Request
PR.1
PR.2
PR.3
PR.4
PR.5
Code Structure
CS.1
CS.2
CS.3
CS.4
CS.5
CS.6
CS.7
ER.2
Quality Measurement Keys:
NA
NA
NA
Description
All Class names must be descriptive nouns (XYZController, XYZService etc) and methods to use
verbNoun paradigm (getSomething,
addSomething, readSomething etc)
All classes and all public methods must be fully covered in positive and negative unit tests in
corresponding unit test classes. One
external class = one unit test class.
Component tests are to be implemented to prove overall workflow across all known scenarios. All
external resource behaviour are
to be mocked in their expectations using mockito.
Isolate complex or repeated logic by using helper utility functions and suppliers that can be tested
in isolation.
Be consistent for date and time handling. Make sure all date times are in UTC TimeZone. No ifs or
buts. This must be proved with
test cases to ensure robustness.
Make sure all service entry and exit points are logged using log.info and important events in the
service workflow. This is to show
descriptive information about service flow using information on key Ids (account Ids etc). Logging
Must be compliant to PII
restrictions. Make sure all exceptions when thrown are descriptive with the exception describing
where and what the underlying
exception cause and stacktrace is.
Use full Swagger and Json annotation and validation on restful service interfaces.
For model ValueObject classes, use Lombok annotations for correct construction, getters/setters.
Ideally all value objects are to be
immutable with all data passed in through constructor.
For data persistence service then there are two preferred options.
If the data model is complex then use JPA annotations on Data Model to translate model objects to
data-persist objects. For
simple cases where the data write is simple – please use DAO components with embedded Spring
JDBC Template
methodology to write the objects using simple JDBC techniques.
All services that are required to be CRUD services with external datasource are to be tested and set
with correct ACID transaction
context at service or component end points. So if the service fails no dirty data is persisted. This
must be fully tested for database
operations. In simple terms guarantee and test that if a data write service fails – any intermediary
data is rolled back – and no dirty
data is left.
Do not pass or return null references. Use optional paradigm to handle non mandatory data
handling and use validation to ensure
contract on mandatory data. Where it is not known whether a data object is mandatory then use
Optionals for passing in or
returning from methods.
For code maintenance make sure the run config, for Docker pods and K8s only contains what is
necessary and is to standard.
Make sure gradle build files comply to 10x build patterns, cover the whole life cycle and do not have
any unnecessary dependencies
As the bottom layer of the testing period, we should have an extensive number (~1000s) of
coherent, accurate and relevant unit tests that
document how a class behaves and its scope. The following is a list of expectations from our unit
testing
PowerMock is a code smell - We should consider refactoring production code if Mockito is
insufficient
Mocking should be accurate - The usage on "any()" should be avoided wherever possible and
Argument Captor only used for
verification
Tests should cover negative and positive scenarios, for example, an IF statement needs a minimum
of 2 unit tests.
Our target is to have complete line and condition coverage
Unit tests descriptions should be explicit and describe the exact behaviour and scenario
A unit test should test one thing and one thing only
Test should not share state (variables) they should be independent
Test Libraries - Favour consistency over library. Aim to use either Hamcrest or AssertJ instead of
Junit and if possible move to
Junit5
Unit tests should complete in milliseconds
A test should never be ignored, it either has value and should be fixed or it should be removed
As the centre layer of the testing period, we should have a large number (~100s) of coherent,
accurate and relevant component tests that
document how a service behaves and interacts with downstreams dependencies including
databases and other microservices. The
following is a list of expectations from our component testing:
Leverage embedded libraries wherever possible. There is an embedded Cockroach library available
for databases and Wiremock
should be used for downstream rest calls (and schema registry if you prefer).
When testing REST APIs Component tests should avoid marshalling requests and responses.
Wherever possible we should send
String values and asserting against String values to avoid leveraging production code libraries such
as Jackson
Component tests should start the service under test only once running any data migrations, tested
against and then brought down.
Tests therefore need to be independent and not share state
Tests should cover negative and positive scenarios
Tests descriptions should be explicit and describe the exact behaviour and scenario
Our target is to have complete condition coverage
A test should never be ignored, it either has value and should be fixed or it should be removed
Logging is an essential part of developing features and should assist at all levels through testing and
debugging issues. The following is a
list of best practices and expectations for logging:
Logging should be at an appropriate level
It should not include any PII data
It should be added as part of the delivery of a story and be reviewed as part of the production code
Logging should have an identifier so that it can be traced through the logs, for example a
Transaction Correlation Id or Request Id if
available
When a developer has completed a feature or bug and a pull request is raised the following should
be done before requesting a review from
their peers:
All unit and component tests have been written as per the standards above and are passing
The branch has an appropriate name including the Jira reference - feature/DEV-
99999_make_payment_api
Any config that is required for a feature has its PR against the platform configuration with as many
environments setup as possible
Should have appropriate titles starting with the Jira reference - DEV-99999: Make New Payment API
Pull requests should be associated to a build and that build should pass before merging
Our services should be structured in accordance to best practices and code theory that is
researched from our peers and wider readings.
Our service structure will differ depending on the requirements and suspect that an "Adapter" vs a
"Manager" will benefit from subtle
differences but should align to one another. Below are some principles that should be considered
and leveraged when designing the code:
A service should have a clear Immutable Domain Model
Business logic is only resides within the Domain Services and Models
There is clean separation between the primary adapter layer (REST / Kafka) the domain layer and
the secondary adapter (RDS). This
enables services to change quickly to newer technologies when required inbound and outbound
and keep the business logic in the
heart of the service.
A class should do one thing and should have only the necessary complexity
A class should split when it becomes too large (over 250)
Methods should be pure. An argument should be not be manipulated unless its returned
(Immutability prevents this anyway)
Code should only be present if its used including imports and classes
Our services should be as fault tolerant as possible in line with technical best practices and business
requirements. Errors should also be
raised and and handled appropriately. Our services should not start if they are unable to perform
their function and leverage Kubernetes
liveness and readiness probes or Spring Actuator when possible. Below are some principles that we
should follow:
Logging is not error handling
Exception handling should be graceful and consistent. A recommendation is to have technical and
business exception separation
High - The code is well formed, performant, easy to read, thorough and precise. Errors are handled
appropriately and tests are complete to
very high line and condition coverage
Medium - The code is structured but with issues. Code is difficult to follow easily but possible. Tests
exist and cover the key features with
some value but no edge cases.
Low - The code has no standard structure, there is unused code and is not readable with prior
explanation or comments. There are little to
no tests and of those written have little value.
Mandatory? Self Reviewed Peer Review
Column1
existing config
existing config
needs clarification
Column2
101314
1/1/2019
1/2/2019