Modular programming is a software design technique that emphasizes separating the functionality of a program into independent, interchangeable modules, such that each contains everything necessary to execute only one aspect of the desired functionality
Every modern software project makes use of modularity at some level or another. The benefits for application development include better separation of concerns, code re-usability, easier maintenance, and more. In recent years, the software industry has fully embraced this approach, with modular concepts built into all languages. Many large applications developed today make use of modern modular programming tools such as npm or architectural patterns like microservices.
The Evolution of Modularity in Programming
The modern concept of modular programming has its roots in the shift toward structured programming in the 1960s. At the time, programmers often wrote their code in an undisciplined, unorganized style that was difficult to understand or maintain. Frequent use of GOTO statements obscured the logical flow of programs and made debugging a nightmare.
In contrast, structured programming promotes the the use of clearly-defined structures such as conditional statements and loops for control flow. More importantly for our purposes, structured programming makes heavy use of subroutines and functions to encapsulate related code into separate reusable chunks.
As a straightforward example, consider a simple calculator application. A naive approach to building a calculator might include all of the functionality in a single file, class, or function. A more structured style might involve giving the different tasks such as addition, subtraction, multiplication, and division their own functions and calling them from a main function. This means that you can separately test each component. Moreover, different functions can be reused as needed for other tasks. For example, the multiplication function might make use of addition.
More recently, the trend toward modularity has changed the design of applications at an architectural level. Software projects are often broken into independent modules early in the design process, affecting the development process from day one.
NPM and Node
Node.js is a prominent example of a language built with modularity as a central concept. The package manager npm makes it especially easy to import modules into your project. Let’s say you want to make your own Discord bot. Well, there is a library tailor-made for that which you can download into your project using npm. Adding that library to your project is as simple as inserting the following line into your code:
const Discord = require('Discord.js');
However, the benefits of npm aren’t limited to third-party packages. Packages can be published privately for collaboration with your team, and local packages are perfect for building modular applications.
Why Modular Programming?
As software systems become ever more complex, modular programming is quickly becoming the standard way to develop large applications. Unlike less organized development practices, the modular approach allows for a convenient separation of responsibilities during development and scales better.
- Separate modules are easier to develop. Separating software components into discrete parts simplifies the development process for each part. It also makes it possible for developers to focus on their individual strengths as programmers.
- Teams can be split up: Each component can have its own dedicated team and development process, potentially with minimal interaction between teams. This is a huge benefit in an increasingly globalized world.
- More scalable: Unmodularized code does not easily scale. On the other hand, well-constructed modules can easily adapt to novel or larger workloads.
- Easy to integrate third-party modules: Modern software development typically makes heavy use of third-party code, usually in the form of third-party libraries and packages. A modular approach to development naturally lends itself to the use of prebuilt libraries.
- More overhead: Modular applications requires a little more work up front, since each module must be individually packaged and must provide an interface for other components of the app. In addition, you need a top layer to link the modules together. The process of integrating the different modules can have complications.
- Lack of integration between modules: In some cases, the inability of a module to access other parts of the application can be a hindrance. This means that the project’s architecture must be carefully thought out from early in the design process.
- Testing can be time-intensive: Testing separate modules can be more involved than singular programs.
Modular Programming Vs. Monolithic Applications
It’s important to understand the distinction between between modular applications and monolithic applications. A modular application takes the approach of modular programming and applies it to its whole structure. Monolithic applications take the opposite approach. A monolithic application is like a single container that has every software component that the application needs: one database, one application, one server to deploy to, and one container to share every component with every other component.
In the past, deploying and developing monolithic applications was the norm. But there were some significant problems. How well does the application scale up? What if we have a spike in traffic? What if you wanted to update a specific part of the app without breaking it? Every user had access to just one server and one application. Entire new instances of the application would have to be created for users as traffic increased, overloading the server.
Developers were having a hard time as the code in an app got increasingly complex, so people started wondering how to improve on current practices. This led to the creation of modern modular programming concepts.
Microservices are currently a popular way to implement modular architectures. This approach involves piecing together an application from multiple separately built “services” that communicate using a common interface, but can otherwise be internally independent. The services can even be built on completely different development platforms and programming languages if necessary.
Using the model of modular programming we can create a structure that will give us the best representation of a modular application. Instead of having one application, we can create several. Those modules that we separated in order to create one app can be built into their own “applications.” They can have their own databases, tables, and servers to deploy to.
Of course, this change was not just a movement from independent developers. Big companies like Google, PayPal, Capital One, and many more were pushing towards microservices. This led many other companies to follow suit and use microservices for their own applications. Notice that all these companies need to handle user registrations, transactions, and overall a huge amount of data. They pushed modular programming to its limits.
With microservices, our users can now access one server that contains the front-end, and that server will be able to request information from others. This solves most of our problems. We can now handle and access different data chunks and update functionality without testing the entirety of our application. We can also scale up or down as much as we want. When traffic spikes we just have to add more servers on that specific part of our application. This is a big improvement, but there are still some big problems to address. And one creation changed the landscape once again.
Docker Takes the Stage
Docker became available to the public in 2014, and it made a grand entrance. Microsoft announced its integration with Docker in the same year. IBM followed, as well as Google, Cisco, RedHat, and many more. All these companies needed to handle huge customer data, and so the change was big but worth it. This was one of the factors that caused this shift in architecture: “If a huge company like Google is willing to change, then maybe we should too.”
Using the modular programming approach can have its downfalls because there needs to be package installations on each app. There will also have to be maintenance on each server. This means that you will have to manually run commands. Docker was a great escape from this, and not much later Kubernetes came out. Together, they made an amazing combination.
Christian Melendez gives a great explanation of what Docker is, and how using it with Kubernetes can improve workflow:
“You’ll be able to deliver faster, but more importantly, you’ll deliver in a consistent and predictable manner. Docker containers will help you to isolate and pack your software with all its dependencies. And Kubernetes will help you to deploy and orchestrate your containers. This lets you focus on developing new features and fixing bugs more rapidly. Then you’ll notice, at some point, your deployments stop being a big ceremony.”
A docker file will share the packages with each of its containers. This erases the need to install packages on each application. Using Kubernetes, our pods will function the same as servers. They are capable of scaling up or down depending on the traffic load.
Should You Use Modular Programming?
The benefits of modular programming are obvious, but it is appropriate for everyone? Should you embrace this approach for your own projects?
Building programs with modular architectures from the ground up is especially useful for companies that handle huge amounts of data or build large, scalable applications. If you are building small or simple apps, then using a complicated modular design like a microservice architecture is probably overkill. But as mentioned previously, every well-designed app benefits from effective use of modular principles, even if only at the function level.
On the other hand, microservices and other modular techniques are popular in the industry and companies need developers that know how to use them. A professional developer who seeks to have a versatile and up-to-date skillset should be familiar with these technologies. Recent trends suggest that modular programming will continue to be an important development methodology moving forward.