Ch. 5 The Structure of a Service Project
In the previous chapter, we generated four service projects and one system project. These two categories of projects have slightly different project structures. We’ll explore the project structure of each category below.
Structure of Service Project
We’ll start by exploring the project for the SoftwareRequestService
. This project can be found in the directory named
com.helpco.helpdesk.softwarerequestservice
. If we look inside this directory, we’ll see the following structure:
Structure of a service project
- com.helpco.helpdesk.softwarerequestservice.distribution/
- com.helpco.helpdesk.softwarerequestservice.domain/
- com.helpco.helpdesk.softwarerequestservice.impl/
- com.helpco.helpdesk.softwarerequestservice.tests/
- generated-projects/
- gradle/
- build.gradle
- gradlew
- gradlew.bat
- README.md
- settings.gradle
We’ll explore the contents of each of these files and directories below.
The README.md
file is used to describe the contents of the project. By default, this file is empty. Users are encouraged
to update this file to contain a simple description of the project and instructions about how to build it. This file is
written using Markdown.
Gradle Configuration
Generated service projects build with Gradle. The gradle
directory contains the necessary files to run the Gradle
wrapper. As discussed in Ch. 1, the
wrapper makes it possible to automatically download and install Gradle if a user has never ran Gradle before.
The entire contents of com.helpco.helpdesk.softwarerequestservice
forms a single root project. Each of the
directories that start with “com.helpco.helpdesk” as well as the directories within generated-projects
contain
subprojects. The entire root project can be built by running the following command from the directory that contains
the root project:
Building a service project
$> ./gradlew clean build -x test
Note that a freshly generated service project has failing unit tests (since the service has not been implemented yet).
Therefore, we need to use -x test
to tell Gradle to skip execution of the unit tests and complete the build. When we
run the build for the root project, Gradle builds each sub-project.
We can also build sub-projects directly. For example, we could build the sub-project
com.helpco.helpdesk.softwarerequestservice.tests
by moving to that directory and running the command
../gradlew clean build
. This will build only that particular sub-project.
The top level build.gradle
and settings.gradle
files contain the build configuration for the entire project. The
settings.gradle
file declares which sub-projects make up the root project. Only a single settings.gradle
file is
declared for an entire project. The top level build.gradle
file contains build logic used by the entire system. It
also contains build logic applied to each sub-project and defines the version number for commonly used dependencies.
Note that each sub-project also contains its own build.gradle
file. These files contain build logic that is specific
to each sub-project. See the
Gradle documentation for more information about
Gradle and multi-project builds.
Stubbed Sub-projects
The following sub-projects were stubbed by Jellyfish:
com.helpco.helpdesk.softwarerequestservice.distribution
com.helpco.helpdesk.softwarerequestservice.domain
com.helpco.helpdesk.softwarerequestservice.impl
com.helpco.helpdesk.softwarerequestservice.tests
These projects are considered stubs because Jellyfish initially generates the structure of these projects as part of the
create-java-service-project
command. However, these projects are edited and maintained directly by the product team.
Jellyfish will never again attempt to generate or modify any of these sub-projects.
Each of the sub-projects serves a specific purpose:
com.helpco.helpdesk.softwarerequestservice.impl
: This sub-project contains the actual implementation of theSoftwareRequestService
. This is usually where a product team will spend the bulk of their time. This sub-project contains a class that is ready to be implemented by the team. Teams are free to implement the service using any approach the want.com.helpco.helpdesk.softwarerequestservice.distribution
: This sub-project does not contain executable code. Instead, it contains the runtime resources needed to run the actual service. This might include runtime configuration files, etc. This project also contains scripts that can be used to start the service. When./gradlew build
is run for this sub-project, a ZIP file will be created that is called a distribution of the project. This ZIP file contains everything necessary to run the service. This includes JAR files, start scripts, runtime configuration, etc.com.helpco.helpdesk.softwarerequestservice.tests
: This sub-project is used to perform black-box-testing of the service with Cucumber. It references the feature files included with the model. This project builds a separate, standalone application that runs a separate process from the actual service. More information about testing is covered in the next chapter.com.helpco.helpdesk.softwarerequestservice.domain
: This sub-project contains domain models. Domain models are POJOs (plain old Java objects) that are used to model data that flows within the service. This sub-project is used for complex services that may want to layout information using different data structures. Teams are free to change these data structures to layout the data in any way that is most convenient for them. Domain objects are private to a service and are not exposed to other services. Not all services will use this sub-project. Simple services, such as ourSoftwareRequestService
, can completely ignore this project.
Generated Sub-projects
More sub-projects can be found under the generated-projects
directory. These sub-projects are fully generated by
Jellyfish and should not be modified.
com.helpco.helpdesk.softwarerequestservice.base
: Contains the interface, API, and base classes for the service itself. Teams may extend the classes contained in this sub-project but that is not required.com.helpco.helpdesk.softwarerequestservice.config
: Contains transport configuration and other configuration used to configure the service.com.helpco.helpdesk.softwarerequestservice.connector
: Contains the component that performs serialization and interacts with the transport layer.com.helpco.helpdesk.softwarerequestservice.events
: Contains the inputs and the service. These types are identical to the contents of the messages project but are serialization agnostic. These types are used throughout the service.com.helpco.helpdesk.softwarerequestservice.messages
: Contains the messages that the services receives or publishes. These messages are specific to serialization techniques and expose details related to that serialization.com.helpco.helpdesk.softwarerequestservice.pubsubbridge
: Contains logic necessary to allow the service to swap pub/sub for request/response or vice versa.com.helpco.helpdesk.softwarerequestservice.testsconfig
: Contains the transport configuration necessary to run the tests for the service. This configuration is only used by the tests and not by the rest of the service.
Running the Service
We can run the service by first performing a build of the root project. Run ./gradlew clean build
from the root
project directory to build the entire project. Use -x test
to skip unit tests, if necessary. Once the build
completes, the com.helpco.helpdesk.softwarerequestservice.distribution
sub-project will contain a build/distribution/
directory. This directory contains a ZIP and another directory that is the unarchived ZIP. This ZIP
contains everything needed to run the application. Run the start script inside the bin/
directory to start the
service.
The Other Services
The remaining services have a very similar project structure. Each project will vary slightly based on each model, but they are built and executed the same way.
Structure of a System Project
The final project is the com.helpco.helpdesk.softwarestore
project. This project represents the entire
SoftwareStore
system. Note this project contains no code that is executed as part of the system. The system is
fully realized by running the individual services. The directory structure of a system looks like this:
Structure of a system project
- com.helpco.helpdesk.softwarestore.distribution/
- com.helpco.helpdesk.softwarestore.tests/
- generated-projects/
- gradle/
- build.gradle
- gradlew
- gradlew.bat
- README.md
- settings.gradle
Like services, this project has a README file and various Gradle files.
Gradle Configuration
The Gradle configuration for the system mirrors the configuration for services. It, too, consists of a root project which contains sub-projects.
The system project can be built by running the command ./gradlew clean build
from the directory of the root project.
Note that system projects require some extra configuration to get them up and running out of the box. The
build.gradle
of the root project must be updated before it is possible to build a distribution of the entire system.
The generated build.gradle
file contains two sections that require updates. The first is the section that declares
the versions of the service projects to use. This can be found in the ext
section of the script.
Configuring the versions of the services in the system’s build.gradle
ext {
logger.error "Not implemented: you need specify the versions for the distributions of this system's parts"
// TODO: Add versions for these distributions
// softwareRequestServiceDistributionVersion = '1.2.3'
// licenseServiceDistributionVersion = '1.2.3'
// pcManagementServiceDistributionVersion = '1.2.3'
// emailServiceDistributionVersion = '1.2.3'
}
In our example, all of the services start at version 1.0.0-SNAPSHOT, so we can update the configuration as follows:
Configuring the versions of the services in the system’s build.gradle
ext {
softwareRequestServiceDistributionVersion = '1.0.0-SNAPSHOT'
licenseServiceDistributionVersion = '1.0.0-SNAPSHOT'
pcManagementServiceDistributionVersion = '1.0.0-SNAPSHOT'
emailServiceDistributionVersion = '1.0.0-SNAPSHOT'
}
Now that we have declared versions, we can update the systemDescriptor
section of the build.gradle
:
Configure the services in the system’s build.gradle
systemDescriptor {
project = 'com.ngc.seaside:helpdesk.descriptor:1.0.0-SNAPSHOT'
model = 'com.helpco.helpdesk.SoftwareStore'
deploymentModel = 'com.helpco.helpdesk.LocalSoftwareStore'
part {
model = 'com.helpco.helpdesk.SoftwareRequestService'
distribution = "com.helpco.helpdesk:srs.distribution:$softwareRequestServiceDistributionVersion@zip"
}
part {
model = 'com.helpco.helpdesk.LicenseService'
distribution = "com.helpco.helpdesk:ls.distribution:$licenseServiceDistributionVersion@zip"
}
part {
model = 'com.helpco.helpdesk.PcManagementService'
distribution = "com.helpco.helpdesk:pcms.distribution:$pcManagementServiceDistributionVersion@zip"
}
part {
model = 'com.helpco.helpdesk.EmailService'
distribution = "com.helpco.helpdesk:es.distribution:$emailServiceDistributionVersion@zip"
}
}
Stubbed Sub-projects
A system only contains two sub-projects that are stubs:
com.helpco.helpdesk.softwarestore.distribution
: This sub-project contains a single distribution that will contain all of the services that make up the system.com.helpco.helpdesk.softwarestore.tests
: This sub-project contains a black box test for testing the entire system. This test will require all of the services in the system to be running. This test is implemented in a similar way as the tests for services (IE, they both use Cucumber). The test runs as a separate application and this sub-project will produce a runnable application for the tests.
Generated Sub-projects
Like services, the generated-projects
directory contains sub-projects that are entirely generated by Jellyfish and
should not be edited.
com.helpco.helpdesk.softwarestore.base
: Contains transport topics used by the tests.com.helpco.helpdesk.softwarestore.messages
: Like services, this sub-project contains the messages for the entire system. These are used by the tests.com.helpco.helpdesk.softwarestore.testsconfig
: Contains the transport configuration for the tests.
Running the System
The com.helpco.helpdesk.softwarestore.distribution
sub-project is provided for convenience to make it easy to run the
entire system. Before building the system’s distribution, it is necessary to build and “install” the service
projects that make up the system. This means running the command ./gradlew build publishToMavenLocal
for each of
the services described above. Once complete, the command ./gradlew clean build
can be run for the root project of the
system.
The build will produce a ZIP that can be found in the build
directory of the
com.helpco.helpdesk.softwarestore.distribution
sub-project. This ZIP contains all of the services and a single
start script that will start all four services as different processes. This is primarily used for testing on a single
host and such a script might not be useful for services that deploy on separate hosts.
Conclusion
This chapter provided a detailed break-down of the services that Jellyfish generates. The next chapter will cover testing both services and systems.