Java 9 Modular Programming Concept is a powerful feature which is introduced in JDK 1.9. Modularity specifies the interrelation and intercommunication between the parts that comprise a software system. Modular programming outline a concept called the module. Modules are software components that contain data (attributes) and functions (operations or methods). Integrated with other modules, together they form a unitary software system. Modular programming provides a technique to decompose an entire system into independent software modules. Modularity plays a crucial role in modern software architecture. It divides a big software system into separate entities and helps reduce the complexity of software applications while simultaneously decreasing the development effort.
Two most important dimension of modularity are maintainability and reusability, both of which bring great benefits. If you are familiar with
Maintainability : Maintainability refers to the degree to which a software system is upgraded or modified after its first delivery to production environment. A big, monolithic software system is hard to maintain, especially if it has many dependencies inside the code.
Reusability : Object-oriented programming can be used to obtain reusability, especially via inheritance. In order to reuse the functionality encapsulated in an object, a second object must inherit the first object.
The Definition of a Module
An application (or system or software) module is an independent and deployable software body of a larger system that interacts with other modules and hides its inner implementation. It has an interface that allows inter-modular communication. The interface defines which components it provides for external use and which components it requires for internal use. A module determines a boundary by specifying which part of the source code is inside the module. It also provides flexibility and increases the reusability of the software system.
Modules can be discovered starting from compile-time. A module can expose some of its classes to outside or can encapsulate them in order to prevent external access. Figure 1-1 illustrates this concept with an example of a module containing classes that are exposed to outside (classes in green color) and classes that are not exposed to outside (classes in red color). A module can also be viewed as a black box. It has an input and an output and performs a specific function. It takes the input, applies some business logic on it, and returns an output.
A software module is reusable, testable, manageable, and deployable. Multiple modules can be combined together to form a new module. Modular programming is the key to reducing the number of bugs in complex software systems to a minimum. By dividing the application into very small modules, each modules will have fewer defects because its functionality is not complex. Assembling these less error-prone modules results in an application with fewer errors.
Characteristics of a module
A change performed on a specific module should not have an impact on other modules. Additionally, it should be possible to add a new module to the core system without breaking the system. Because only the interface of a module is visible from outside the module, it should be possible for developers to change the module’s internal implementation without breaking the code in the application. The structure of a modular software application is basically defined by the connections and correlations between modules. Some of the characteristics of a module include the following:
- A module must define interfaces for communication with other modules.
- A module defines a separation between the module interface and the module implementation.
- A module should present a set of properties that contain information.
- Two or more modules can be nested together.
- A module should have a clear, defined responsibility. Each function should be implemented by only one module.
- A module must be able to be tested independently from other modules.
- An error in a module should not propagate to other modules.
Let’s give a short example. If we have two Jigsaw modules called M01 and M02 and one package in module
M02 called Pkg02 that we want to be accessible in module M01, then the following conditions have to be met:
- Module M01 should depend on module M02, module M01 should specify in its declaration that it “requires” module M02.
- Module M02 should export the package Pkg2 in order to make it available to the modules that depend on it. In our case, in the declaration of the module M02 we should specify that it “exports” package Pkg2
Foundation of Modular application
Four concepts that build the foundation of a modular application:
- Strong encapsulation
- Explicit interfaces
- High module cohesion
- Low module coupling
Strong Encapsulation : Encapsulation defines the process of preventing data access from outside by allowing a component to declare which of its public types are available to other components and which aren’t. Encapsulation
improves code reusability and diminishes the number of software defects. It helps obtain modularity by decoupling the internal behavior of each object from the other elements of the software application
Explicit Interfaces : The interfaces of a modular system should be as small as possible. If an interface is too big, it should be divided into several smaller interfaces. An interface should make available to a module only the methods
that the module really needs in order to be able to fulfill its business requirements. A modular system typically provides module management and configuration management. Module management refers to the capacity to install, uninstall, and deploy a module. The installation could be done from a module repository, for example. In some cases, a module could be deployed instantly without requiring that the system is restarted. Configuration management specifies the capacity to dynamically configure modules and specify the dependencies between them.
High Module Cohesion : Cohesion measures how the elements of a module are residing together. Module cohesion denotes the module’s integrality and coherence in regard to its internal structure. It expresses the rate to which the module’s items are defining only one functionality.
Low Module Coupling : Coupling specifies the level of interdependence between modules. Module coupling refers to the dependency between modules and the way they interact. The objective is to reduce module coupling as
much as possible, and this is achieved by specifying interfaces for the inter-modular communication. The interfaces have the role of hiding the module implementation. The resulting modules are independent and can be modified or swapped without fear of breaking other modules—or worse, breaking the entire application.
Tight Coupling vs. Loose Coupling
Tight and loose coupling can refer to classes or modules. Tight coupling between classes is when a class uses
logic from another class. It basically uses another class, instantiates an object of it, and then calls the object
to access methods or instance variables. Loose coupling is encountered when a class doesn’t directly use an instance of another class but uses an intermediate layer that primarily defines the object to be injected. One framework that defines loose coupling is the Spring framework, where the dependency objects are being injected by the container
into another object. Loosely coupled modules can be altered with less effort. Loose coupling is generally
accomplished by using small or medium-sized modules. Replacing a module won’t affect the system if the
new module has the same interface as the module being replaced. Tight coupling means classes are dependent on other classes and it doesn’t allow a module to be replaced so easily because it has dependencies on the implementation of other modules.