Currently the layout of the modules in platform is slightly different to the layout in the modules of services. We already defined a lot of best practices in services and it would be great if we can have a common pattern for all modules. This epic defines the general structure that a module should have.
Since our project is using Gradle as build tool all our modules are Gradle modules. Next to this mostly all modules are
Java modules.
Gradle module description
Each module needs a build.gradle.kts file that describes the module.
General best practices for all our (Java) modules are defined in custom plugins that can be found
under buildSrc/src/main/kotlin. For a Java module the com.hedera.hashgraph.javaConventions plugin should be used.
Next to this each module should have a description. Since nothing else is needed for a minimal module the most simple
build.gradle.kts looks like this:
plugins {
id("com.hedera.hashgraph.javaConventions")
}
description = "A minimal module without any dependecies"
The group, name and version of the module should not be added here. The group is the same for all modules on the
repository (com.hedera.hashgraph) and its definition can be found in the com.hedera.hashgraph.conventions plugin.
For the version we use a global definition, too. The current version is defined in the gradle.properties file in
the root folder of the project. The name of a module is simple created based on the folder name of the module.
Project sources sets
For a Java module all sources must be placed under src/main/java and src/main/resources while src/main/java must
contain all the Java files that should be compiled. All other files must be placed under src/main/resources. Since all
our Java based modules are full JPMS modules a module-info.java file must be placed directly under src/main/java.
All modules can have different types of tests. The com.hedera.hashgraph.javaConventions plugin provides direct support
for unit test, integration tests, and end-to-end tests. Next to this the test fixtures functionality of Gradle is
supported.
For the unit test set the src/test/java and src/test/resources folders must be used. Unit tests will be executed on
the Java classpath and therefore no module-info.java is needed. This has the big benefit that unit tests can have the
same base package as the module sources, access package private and use functionally that is not exported by the module-info.java under src/main/java.
For the integration test set the src/itest/java and src/itest/resources folders must be used. All integration tests
will be executed on the module path to be as near to the real usage as possible. Based on that a module-info.java file
is needed. The name for the module and the base package is based on the name of the source module
plus the 'itest' suffix. Since the test fixtures JPMS module will only be used in tests it should be
fully opened. This makes the content of the module-info.java much more readable since no individual opens
statements need to be added.
For the end-to-end test set the src/eet/java and src/eet/resources folders must be used. TODO: Module path or class path?
A module can define test-fixtures that helps to create clean and readable unit tests. All Java sources for the test fixtures must be placed under src/testFixtures/java. Additional resources that should be shared for tests can be placed under src/testFixtures/resources. Like for the source set of a project the test fixtures sets are defined as full JPMS modules, too. Based on that a module-info.java file must be placed directly under src/testFixtures/java if at least one Java file is present.
The name of the test fixtures module should be based on the name of the source module and add a testfixtures suffix. Since the test fixtures JPMS module will only be used in tests it should be fully opened. This makes the content of the module-info.java much more readable since no individual opens statements need to be added.
Next to tests JMH benchmarks can be part of a module to test the performance of critical components within the module. All benchmarks must be based on JMH and the src/jmh/java and src/jmh/resources folders must be used. TODO: Module path or class path?
Based on the given definitions a module folder in the project looks like this:
Currently the layout of the modules in platform is slightly different to the layout in the modules of services. We already defined a lot of best practices in services and it would be great if we can have a common pattern for all modules. This epic defines the general structure that a module should have.
Information: for services a short documentation about the layout of modules already exists that is sadly not up to date: https://github.com/hashgraph/hedera-services/blob/develop/hedera-node/docs/design/modules.md
Internal structure of a module
Since our project is using Gradle as build tool all our modules are Gradle modules. Next to this mostly all modules are Java modules.
Gradle module description
Each module needs a
build.gradle.kts
file that describes the module.General best practices for all our (Java) modules are defined in custom plugins that can be found under
buildSrc/src/main/kotlin
. For a Java module thecom.hedera.hashgraph.javaConventions
plugin should be used. Next to this each module should have a description. Since nothing else is needed for a minimal module the most simplebuild.gradle.kts
looks like this:The
group
,name
andversion
of the module should not be added here. Thegroup
is the same for all modules on the repository (com.hedera.hashgraph
) and its definition can be found in thecom.hedera.hashgraph.conventions
plugin. For theversion
we use a global definition, too. The currentversion
is defined in thegradle.properties
file in the root folder of the project. Thename
of a module is simple created based on the folder name of the module.Project sources sets
For a Java module all sources must be placed under
src/main/java
andsrc/main/resources
whilesrc/main/java
must contain all the Java files that should be compiled. All other files must be placed undersrc/main/resources
. Since all our Java based modules are full JPMS modules amodule-info.java
file must be placed directly undersrc/main/java
.All modules can have different types of tests. The
com.hedera.hashgraph.javaConventions
plugin provides direct support for unit test, integration tests, and end-to-end tests. Next to this the test fixtures functionality of Gradle is supported.For the unit test set the
src/test/java
andsrc/test/resources
folders must be used. Unit tests will be executed on the Java classpath and therefore nomodule-info.java
is needed. This has the big benefit that unit tests can have the same base package as the module sources, access package private and use functionally that is not exported by themodule-info.java
undersrc/main/java
.For the integration test set the
src/itest/java
andsrc/itest/resources
folders must be used. All integration tests will be executed on the module path to be as near to the real usage as possible. Based on that amodule-info.java
file is needed. The name for the module and the base package is based on the name of the source module plus the 'itest' suffix. Since the test fixtures JPMS module will only be used in tests it should be fully opened. This makes the content of themodule-info.java
much more readable since no individualopens
statements need to be added.For the end-to-end test set the
src/eet/java
andsrc/eet/resources
folders must be used. TODO: Module path or class path?A module can define test-fixtures that helps to create clean and readable unit tests. All Java sources for the test fixtures must be placed under
src/testFixtures/java
. Additional resources that should be shared for tests can be placed undersrc/testFixtures/resources
. Like for the source set of a project the test fixtures sets are defined as full JPMS modules, too. Based on that amodule-info.java
file must be placed directly undersrc/testFixtures/java
if at least one Java file is present. The name of the test fixtures module should be based on the name of the source module and add atestfixtures
suffix. Since the test fixtures JPMS module will only be used in tests it should be fully opened. This makes the content of themodule-info.java
much more readable since no individualopens
statements need to be added.Next to tests JMH benchmarks can be part of a module to test the performance of critical components within the module. All benchmarks must be based on JMH and the
src/jmh/java
andsrc/jmh/resources
folders must be used. TODO: Module path or class path?Based on the given definitions a module folder in the project looks like this: