A modular primer

We can define the term modular as a type of design or construction, in our context, of computer software. This type of software design involves a set of modules that collectively comprise the whole. A house, for example, can be built as a single structure or in a modular fashion where each room is constructed independently and joined to create a home. With this analogy, you could selectively add or not add modules in the creation of your home.

The collection of modules, in our analogy, becomes the design of your home. Your design does not need to use every module, only the ones you want. So, for example, if there are basement and bonus room modules and your design does not include those modular rooms, those modules are not used to build your home. The alternative would be that every home would include every room, not just the ones that are used. This, of course, would be wasteful. Let's see how that correlates to software.

This concept can be applied to computer architecture and software systems. Our systems can be comprised of several components instead of one behemoth system. As you can probably imagine, this provides us with some specific benefits:

  • We should be able to scale our Java applications to run on small devices
  • Our Java applications will be smaller
  • Our modular code can be more targeted
  • Increased use of the object-oriented programming model
  • There are additional opportunities for encapsulation
  • Our code will be more efficient
  • Java applications will have increased performance
  • The overall system complexity is reduced
  • Testing and debugging is easier
  • Code maintenance is easier

The shift to a modular system for Java was necessary for several reasons. Here are the primary conditions of the Java platform prior to Java 9 that led to the creation of the modular system in the current Java platform:

  • The Java Development Kit (JDK) was simply too big. This made it difficult to support small devices. Even with the compact profiles discussed in the next section, supporting some small devices was difficult at best and, in some cases, not possible. 
  • Due to the oversized JDK, it was difficult to support truly optimized performance with our Java applications. In this case, smaller is better. 
  • The Java Runtime Environment (JRE) was too large to efficiently test and maintain our Java applications. This results in time-consuming, inefficient testing, and maintenance operations. 
  • The Java ARchive (JAR) files were also too large. This made supporting small devices problematic. 
  • Because the JDK and JRE were all-encompassing, security was of great concern. Internal APIs, for example, that were not used by the Java application, were still available due to the nature of the public access modifier. 
  • Finally, our Java applications were unnecessarily large.

Modular systems have the following requirements:

  • There must be a common interface to permit interoperability among all connected modules
  • Isolated and connected testing must be supported
  • Compile time operations must be able to identify which modules are in use
  • There must be runtime support for modules

The module concept was first introduced in Java 9; it is a named collection of data and code. Specifically, Java modules are a collection of the following:

  • Packages
  • Classes
  • Interfaces
  • Code
  • Data
  • Resources

Key to successful implementation, a module is self-described in its modular declaration. Module names must be unique and typically use the reverse domain name schema. Here is an example declaration:

module com.three19.irisScan { }

Module declarations are contained in a module-info.java file that should be in the module's root folder. As one might expect, this file is compiled into a module-info.class file and will be placed in the appropriate output directory. These output directories are established in the module source code. 

In the next sections, we will look at specific changes to the Java platform in regards to modularity.