- 1. Overview
- 2. Etymology
- 3. Cultural Impact
This article requires additional citations for verification . It’s astonishing, really, how much of this is just… assumed. As if the world doesn’t need proof for everything. We’ll endeavor to improve this article by adding citations to reliable sources , because frankly, unsourced material is just intellectual clutter. Material that can’t be substantiated will be challenged and, quite possibly, removed. Don’t say I didn’t warn you.
Find sources: “Modular programming” – news, newspapers, books, scholar, JSTOR. (June 2022) ( Learn how and when to remove this message )
Organizing code into modules
Modular programming is a programming paradigm . It’s not a suggestion; it’s a fundamental approach to organizing the functions within a codebase . The core idea is to break down a program into independent units, or modules. Each module is responsible for a specific aspect of the program’s overall functionality, and crucially, it doesn’t concern itself with the other aspects. Think of it like a specialized team: each member knows their job, and they don’t step on each other’s toes.
Each module exposes an interface . This interface is essentially a contract, outlining what the module provides and what it requires from other modules. These declared elements are visible to the outside world, so other modules know what they can rely on. The actual working code, the implementation , is kept separate, containing the logic that fulfills the promises made in the interface. It’s about clarity and defined boundaries.
Related
Modular programming shares common ground with, but is distinct from, several other programming paradigms:
- Structured programming : This paradigm focuses on lower-level code structures, particularly concerning control flow . It’s about making the sequence of operations clear and manageable.
- Object-oriented programming : While both modular and object-oriented programming aim to simplify software construction through decomposition , OOP takes it a step further by organizing code into objects . These objects bundle data (state) with the functions that operate on that data (behavior).
- Interface-based programming : This approach elevates the use of interfaces to a primary architectural pattern for constructing modules. It’s about defining the “what” before the “how.”
History
The concept of breaking code into reusable chunks isn’t new. Subsystems and software libraries, which are essentially forms of modules, have been around since the earliest days of software development, primarily for code reuse . However, modular programming as a distinct paradigm, with a deliberate emphasis on modularity itself, began to coalesce in the late 1960s and 1970s. It emerged as a larger-scale counterpart to the principles of structured programming , which had gained traction in the 1960s.
The term “modular programming” itself traces back at least to a National Symposium on Modular Programming held at the Information and Systems Institute in July 1968, organized by Larry Constantine . Key related concepts like information hiding (formalized in 1972) and separation of concerns (SoC, 1974) were also being developed around this time. These ideas were crucial in defining what a module should be and how it should behave.
Modules weren’t initially part of the ALGOL 68
specification (1968). However, they were quickly added as extensions in early implementations, such as ALGOL 68-R
(1970) and ALGOL 68C
(1970), and were later formally integrated. Niklaus Wirth
’s Modula
(1975), though short-lived, was one of the first languages designed from the ground up with modular programming in mind. Another influential early modular language was Mesa
(developed in the 1970s at Xerox PARC
). Wirth drew upon both Mesa and the original Modula when creating its successor, Modula-2
(1978). Modula-2, in turn, significantly influenced subsequent languages, particularly through its own successor, Modula-3
(1980s). The dot-qualified naming convention introduced in Modula, like M.a to refer to element a from module M, is now ubiquitous. You see it in languages like C++
, C#
, Dart
, Go
, Java
, OCaml
, and Python
, among many others.
Modular programming truly took hold in the 1980s. While the original Pascal (1970) lacked modules, later versions like UCSD Pascal (1978) and Turbo Pascal (1983) incorporated them as “units.” Ada (1980), a language heavily influenced by Pascal, also included modules. The Extended Pascal ISO 10206:1990 standard further solidified modular support, aligning closely with Modula-2. Standard ML (1984) boasts one of the most sophisticated module systems, featuring functors – essentially parameterized modules – for advanced module manipulation.
During the 1980s and 1990s, the rise of object-oriented programming often overshadowed and sometimes conflated with modular programming, largely due to the immense popularity of languages like C++ and Java. For instance, the C family of languages didn’t natively support modules for decades. C++ introduced objects and classes (initially as C with Classes in 1980), and Objective-C (1983) also focused on object-oriented principles. Modules only arrived in Objective-C much later, with iOS 7 in 2013, and in C++ with the C++20 standard. Java (1995), while supporting modules through packages , primarily organizes code at the class level. Python (1991), however, embraced both modules and objects from its inception, using modules as the fundamental unit of code organization and “packages” for grouping modules. Perl 5 (1994) also offered robust support for both modules and objects, with an extensive library of modules available through CPAN (1993). OCaml (1996) followed the ML tradition, providing strong module and functor support.
Today, modular programming is a standard feature in virtually all major languages developed since the 1990s. The specific implementation and the perceived importance of modules can vary. In class-based object-oriented languages, there can still be overlap and confusion between classes as units of organization and encapsulation, but modules and classes are now widely recognized as distinct, albeit complementary, concepts.
Terminology
The terminology surrounding modules can be a bit of a minefield. The term assembly is sometimes used in .NET languages like C# , F# , or Visual Basic . Similarly, package is the term in languages like Dart , Go , or Java . However, in some contexts, these are distinct concepts. For example, in Python , a package is a collection of modules. Then there’s Java 9 , which introduced the Java Platform Module System , a new concept of a module comprising a set of packages with enhanced access controls. It’s important to note that these “packages” are not the same as package manager packages, which are more about distribution.
In the context of the Java language specification, the term package serves the role of the module concept. The more recent introduction of the module in Java 9 represents a higher level of organization, a collection of packages.
Some Pascal dialects use the term unit to refer to modules.
A component is a related concept, but it typically operates at a higher level of abstraction. A component is a distinct piece of a larger system , whereas a module is a part of an individual program. The scale of the term “module” itself varies considerably. In Python, it’s quite granular – each file is a module. In contrast, Java 9 modules are large-scale, comprising multiple packages, which in turn contain multiple files.
Language support
A broad spectrum of languages formally supports the module concept. This includes: Ada , ALGOL , BlitzMax , C++ , C# , Clojure , COBOL , Common Lisp , D , Dart , eC, Erlang , Elixir , Elm , F , F# , Fortran , Go , Haskell , IBM/360 Assembler , IBM System/38 and AS/400 Control Language (CL), IBM RPG , Java , Julia , MATLAB , ML , Modula , Modula-2 , Modula-3 , Morpho, NEWP , Oberon , Oberon-2 , Objective-C , OCaml , various Pascal derivatives such as Component Pascal , Object Pascal , Turbo Pascal , and UCSD Pascal , Perl , PHP , PL/I , PureBasic , Python , R , Ruby , Rust , JavaScript , Visual Basic (.NET) , and WebDNA.
Languages that notably lacked explicit module support in their original forms include C and Pascal. C and C++ did, however, offer a degree of modularization through separate compilation and the use of header files to declare interfaces. Modules were later integrated into Objective-C with iOS 7 (2013) and into C++ with the advent of C++20 . Pascal was eventually superseded by languages like Modula and Oberon , which incorporated modules from their inception, as well as by numerous derivative languages that included this feature. JavaScript gained native module support with ECMAScript 2015. The implementation of C++ modules in C++20 also provides backward compatibility with traditional header files through “header units.” Some dialects of C, such as those supported by Clang , also offer modules for the C language, though their syntax and semantics may differ from C++ modules.
It’s entirely possible to achieve modular programming even in languages that don’t offer explicit syntactic support for named modules, such as C. This is accomplished by leveraging existing language features in conjunction with established coding conventions , programming idioms , and careful physical structuring of the code. On the IBM i platform, modules are also utilized when programming within the Integrated Language Environment (ILE).
Key aspects
The essence of modular programming lies in the separation of concerns . Modules are designed to handle distinct, logical functions, and they communicate with each other through clearly defined interfaces. Often, these modules form a directed acyclic graph (DAG). A cyclic dependency between modules is usually a red flag, indicating that those modules might be better merged into a single, more cohesive unit. When modules form a DAG, they can be organized into a hierarchy. The lowest-level modules stand alone, independent of any others, while higher-level modules depend on the ones below them. A specific program or library acts as the top-level module in its own hierarchy, but it can, in turn, be considered a lower-level module within a larger program, library, or system.
When building a modular system, the approach is to create several smaller, independent modules that are then composed together to form the complete application. This is a stark contrast to a monolithic application, where the smallest building block is the entire program. Typically, these modules are compiled separately – a process known as separate compilation – and then brought together by a linker . In some cases, a just-in-time compiler might handle some of this construction dynamically at run time .
These independent functions generally fall into two categories: program control functions, designed for a specific program, and specific task functions, which are crafted for broad applicability across various programs.
This design philosophy, when executed correctly, makes modular systems far more reusable than their traditional monolithic counterparts. The individual modules can be reused in entirely different projects without modification. It also facilitates the breakdown of large projects into smaller, more manageable sub-projects. Theoretically, a modularized software project can be developed more efficiently by large teams, as no single team member is responsible for the entire system or even needs to grasp its full scope. They can concentrate solely on their assigned, smaller task.
See also
- Architecture description language – A standardized language for describing software architecture.
- Cohesion (computer science) – Measures how well the elements within a module belong together.
- Component-based software engineering – An engineering discipline focused on building software from reusable components.
- Conway’s law – An adage that links organizational structure to system architecture.
- Coupling (computer science) – The degree of interdependence between software modules. Pages displaying short descriptions of redirect targets.
- Cross-cutting concern – A concept in aspect-oriented software development that applies across multiple modules.
- David Parnas – A pioneering Canadian software engineer known for his work on modularity and information hiding.
- Information hiding – A principle in computer program design that conceals the internal details of a module.
- Library (computing) – A collection of resources used to develop software.
- List of system quality attributes – Non-functional requirements used to evaluate software systems.
- Modular design – A design approach that breaks down a system into independent modules.
- Plug-in (computing) – A software component that extends the functionality of existing software.
- Snippet (programming) – A small piece of source code intended for reuse.
- Structured analysis – A software engineering method focused on structured design.
References
- ^ Lindsey, Charles H. (Feb 1976). “Proposal for a Modules Facility in ALGOL 68” (PDF). ALGOL Bulletin (39): 20–29. Archived from the original (PDF) on 2016-03-03. Retrieved 2014-12-01.
- ^ David MacQueen (August 1984). “Modules for Standard ML”. Proceedings of the 1984 ACM Symposium on LISP and functional programming (LFP ‘84). pp. 198–207. doi :10.1145/800055.802036.
- ^ James Gosling ; Bill Joy ; Guy Steele ; Gilad Bracha (2005). The Java Language Specification, Third Edition. ISBN 0-321-24678-0. The introduction states, “Chapter 7 describes the structure of a program, which is organized into packages similar to the modules of Modula.” The term “module” itself holds no specific technical meaning within Java.
- ^ “class Module - Documentation for Ruby 3.5”.
- ^ ECMAScript® 2015 Language Specification, 15.2 Modules.
- ^ “N4720: Working Draft, Extensions to C++ for Modules” (PDF).
- ^ “Modules”. clang.llvm.org.
External links
- How To Decompose a System into Modules
- SMC Platform
v • t • e Programming paradigms (Comparison by language ) Imperative
Declarative
- Functional (comparison )
- Dataflow
- Logic
- Domain-specific language
(DSL)
- Algebraic modeling
- Array
- Automata-based (Action )
- Command (Spacecraft )
- Differentiable
- End-user
- Grammar-oriented
- Interface description
- Language-oriented
- List comprehension
- Low-code
- Modeling
- Natural language
- Non-English-based
- Page description
- Pipes and filters
- Probabilistic
- Quantum
- Scientific
- Scripting
- Set-theoretic
- Simulation
- Stack-based
- System
- Tactile
- Templating
- Transformation (Graph rewriting , Production , Pattern )
- Visual
Concurrent , distributed , parallel
- Actor-based
- Automatic mutual exclusion
- Choreographic programming
- Concurrent logic (Concurrent constraint logic )
- Concurrent OO
- Macroprogramming
- Multitier programming
- Organic computing
- Parallel programming models
- Partitioned global address space
- Process-oriented
- Relativistic programming
- Service-oriented
- Structured concurrency
- Attribute-oriented
- Automatic (Inductive )
- Dynamic
- Extensible
- Generic
- Homoiconicity
- Interactive
- Macro (Hygienic )
- Metalinguistic abstraction
- Multi-stage
- Program synthesis (Bayesian , by demonstration , by example , vibe coding )
- Reflective
- Self-modifying code
- Symbolic
- Template
Authority control databases National
- United States
- France
- BnF data
- Japan
- Israel Other
- Yale LUX