Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Monolith to Modular — Part 2: The Extract Module Use Case

DZone's Guide to

Monolith to Modular — Part 2: The Extract Module Use Case

This tutorial shows a use case of the strategy for extracting new modules from a monolithic code base to create microservices.

Free Resource

Containerized Microservices require new monitoring. Read the eBook that explores why a new APM approach is needed to even see containerized applications.

The basic use case of the monolith to modular strategy is “extract a new module from a monolithic code base.”

This is the second post in a series that will explore the challenges of migrating a monolithic code base to a modular architecture.

Series links:

  • Post 1 –Migrating from Monolith to Modular

  • Post 2 – Monolith to Modular – The Extract Module Use Case – (this post)

  • Post 3 – Monolith to Modular – Managing Violations

  • Post 4 – Monolith to Modular – Sizing and Estimating Scope

In our previous post, we introduced the strategy “Transform the monolith through incremental extraction of modules.” This post describes the basic use case of this strategy – “Extract a new module from a monolithic code base.”

There are a number of scenarios that this use case supports. In most cases, the classes cannot be moved directly into the new module because this would result in cyclic module dependencies, which are not supported by most module technologies (Eclipse, IntelliJ, Maven, Java 9, …).

In reverse order of complexity, the variants are:

  • Donor module is heavily tangled
  • Classes that will end up in the extracted module are distributed across the donor packages
  • The user wants to isolate and restrict access to an existing module via an interface module, cutting off direct access to the original module
    • The user wants to retire existing implementation in favor of a new module
  • The extracted module is created from one or more packages that are at the bottom or top levels of packaging (no cyclic dependencies)

Any of the above are further complicated when there are multiple donor modules or where multiple new modules are to be created in a single step.

In each case the fundamental usage is the same:

  1. Simulate the moving of classes into the target module
  2. Expose violating dependencies
  3. Refactor away the violating dependencies
  4. Actually move the classes to the target module

A Demonstration of Extract Module

The simplest extraction is of code that doesn’t cause a cyclic dependency when it is moved to a new module. The module code has no dependencies on anything that will remain in the monolith. The monolith will depend on the new module and the dependency structure will be a directed acyclic graph. The module can be created and the code moved without any preparatory refactoring. This reduces the use case to three steps:

  1. Simulate the moving of classes into the target module
  2. Expose violating dependencies (there shouldn’t be any)
  3. Actually move the classes to the target module

In the example below the core module is the monolith. The diagram is a layered dependency structure wherein a package is positioned above any packages on which it depends. 

Image title

Restricting the dependency arrows to just those of the nalpeiron package makes clear it does not have any dependencies on any of the other packages in core. It is dependent only on external libraries. We would expect that this package can be moved out of core into its own module without causing a cyclic dependency.

Image title

Simulating the module extraction will expose any cyclic dependencies violating the planned structure. In this simple scenario, no violations are expected and the simulation can be done in the IDE by creating the module and moving the classes.

It is recommended that package names are not changed when the code is extracted to a new module. This avoids changes to the import statements in code that references the moved classes which minimizes the size and impact of the change set.

The structure diagram below shows there are no feedback dependencies from the new nalpeiron module into core.

Image title

The changes made are captured in an Action List. This makes it clear to developers what modules and packages are to be created and which classes are to be moved. The developer tasked with the module extract has all the information necessary to go ahead and create the new module. 

Image title

A similar extraction exercise can be performed on the logging package which is at the lowest level in the com.headway package.

Image title

We can see that the util package depends on the logging package. Once logging has been extracted into its own module, util becomes the lowest level package within com.headway and can itself be extracted to a new module.

After util is extracted, then brands and foundation become candidates for module extractions.

Image title

Summary

Extracting a module from the lowest level of the dependency structure is a low-risk introduction to the extract module use case. But it may not be applicable to your code-base, which means you will have to contend with dependency violations on your first module extraction. In our next post, we discuss how to manage those violations.

You can see a worked example of Extract Module in this blog post. If you are interested in seeing how your software project looks in Structure101 Studio or Workspace, download a free trial.

Discover how to automatically manage containers and microservices with better control and performance using Instana APM. Try it for yourself today.

Topics:
microservices ,modularization ,software architecture ,tutorial ,java 9

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}