Tech Pioneers

David Parnas: The Pioneer of Information Hiding Who Taught the World How to Build Software That Lasts

David Parnas: The Pioneer of Information Hiding Who Taught the World How to Build Software That Lasts

In 1972, while most computer scientists were still wrestling with the chaos of monolithic programs and spaghetti code, a young professor at Carnegie Mellon University published a paper that would fundamentally reshape how humanity builds software. David Lorge Parnas, in just twelve pages, introduced the concept of information hiding — an idea so powerful that it became the intellectual foundation for object-oriented programming, microservices architecture, and virtually every modern software design pattern we use today. The paper, “On the Criteria To Be Used in Decomposing Systems into Modules,” didn’t just propose a technique. It proposed a way of thinking. And five decades later, that way of thinking still separates well-engineered software from the fragile, unmaintainable systems that cost organizations billions of dollars each year.

From Hamilton to Pittsburgh: The Making of a Software Thinker

David Lorge Parnas was born on February 10, 1941, in Plattsburgh, New York, though he spent his formative years in various locations as his family moved. He studied electrical engineering at Carnegie Institute of Technology (now Carnegie Mellon University), earning his bachelor’s degree in 1961. He then pursued graduate studies at the same institution, completing his Ph.D. in electrical engineering in 1965 under the supervision of Alan Perlis — one of the first recipients of the Turing Award and a towering figure in computer science.

The intellectual environment at Carnegie Mellon during the 1960s was electrifying. Computing was transitioning from a craft practiced by a handful of specialists to an engineering discipline that demanded rigor and methodology. Parnas absorbed this atmosphere and began asking questions that few were asking at the time: What makes a software system maintainable? How should we decide where to draw the boundaries between components? Why do some systems gracefully accommodate change while others shatter at the first modification?

After completing his doctorate, Parnas held faculty positions at the University of Maryland, Carnegie Mellon University, the University of North Carolina at Chapel Hill, the Technische Hochschule Darmstadt in Germany, Queen’s University in Canada, and McMaster University in Canada. Each position deepened his thinking about software design, but it was his time at Carnegie Mellon in the early 1970s that produced his most influential work.

The 1972 Paper That Changed Everything

Before Parnas published “On the Criteria To Be Used in Decomposing Systems into Modules” in the Communications of the ACM in December 1972, the dominant approach to system decomposition was based on flowcharts. Programmers would analyze the processing steps required by a system, draw a flowchart, and then assign each major step to a separate module. This seemed logical — after all, each module handled a distinct phase of processing.

Parnas demonstrated that this approach was fundamentally flawed. Using a concrete example — a KWIC (Key Word in Context) indexing system — he showed two different decompositions of the same problem. The first followed the conventional flowchart approach. The second used his proposed criterion: each module should hide a design decision that was likely to change.

The difference was transformative. In the conventional decomposition, a change to the data storage format would ripple through nearly every module. In Parnas’s decomposition, such a change would be confined to a single module. The system’s external behavior remained identical, but its internal structure made it dramatically easier to modify, test, and reason about.

The Principle of Information Hiding

The core of Parnas’s insight was deceptively simple: every module should hide a secret. That secret might be a data structure, an algorithm, a hardware characteristic, or any design decision that could conceivably change. The module’s interface should expose only what other modules need to know, and nothing more.

This principle — information hiding — stands in contrast to the naive intuition that modules should be organized around processing steps. Parnas argued that the key criterion for decomposition is not “what does this module do?” but rather “what does this module know?” A module’s responsibility is defined not by the computations it performs, but by the design decisions it encapsulates.

To illustrate this with a modern example, consider a module that manages user authentication. Under the information hiding principle, this module hides the specific authentication mechanism — whether it uses JWT tokens, session cookies, OAuth, or biometric verification. Other modules only know that they can ask “is this user authenticated?” and receive an answer. The authentication strategy is the module’s secret.

// Information hiding in practice: Authentication module
// The "secret" hidden by this module is the authentication mechanism.
// Callers never know whether we use JWT, sessions, or something else.

public interface Authenticator {
    AuthResult authenticate(Credentials credentials);
    boolean isSessionValid(String sessionToken);
    void invalidateSession(String sessionToken);
}

// Implementation A: JWT-based (the hidden decision)
public class JwtAuthenticator implements Authenticator {
    private final String secretKey;
    private final long expirationMs;

    public JwtAuthenticator(String secretKey, long expirationMs) {
        this.secretKey = secretKey;
        this.expirationMs = expirationMs;
    }

    @Override
    public AuthResult authenticate(Credentials credentials) {
        // Validate credentials against user store
        User user = userStore.findByUsername(credentials.getUsername());
        if (user != null && passwordHasher.verify(credentials.getPassword(), user.getHash())) {
            String token = Jwts.builder()
                .setSubject(user.getId())
                .setExpiration(new Date(System.currentTimeMillis() + expirationMs))
                .signWith(SignatureAlgorithm.HS256, secretKey)
                .compact();
            return AuthResult.success(token);
        }
        return AuthResult.failure("Invalid credentials");
    }

    @Override
    public boolean isSessionValid(String sessionToken) {
        try {
            Jwts.parser().setSigningKey(secretKey).parseClaimsJws(sessionToken);
            return true;
        } catch (JwtException e) {
            return false;
        }
    }

    @Override
    public void invalidateSession(String sessionToken) {
        revokedTokenStore.add(sessionToken);
    }
}

// Switching to Implementation B (session-based) requires
// changing ONLY this module — no other code is affected.

The Uses Relation and Software Structure

Parnas did not stop at information hiding. In a 1979 paper, “Designing Software for Ease of Extension and Contraction,” he introduced the concept of the “uses” relation — a precise way to define dependencies between programs. Unlike the vague notion of “calls” (program A calls program B), the uses relation states that program A is correct only if program B is present and correct.

This distinction matters enormously in practice. A program might call a logging function, but its correctness doesn’t depend on whether the logging function works — it’s merely a convenience. In contrast, a sorting algorithm that delegates comparisons to a comparator function genuinely uses that function; without a correct comparator, the sort produces garbage.

By mapping the uses relation across an entire system, architects could identify which components truly depended on which others. This made it possible to define subsets of the system (for different platforms or configurations) and to extend the system without triggering cascading changes — ideas that anticipated plugin architectures, feature flags, and the microservices revolution by decades.

The A-7E Aircraft: Theory Meets Practice

Parnas was never content with purely theoretical contributions. In the late 1970s and early 1980s, he led one of the most ambitious software engineering projects of the era: the redesign of the onboard flight software for the U.S. Navy’s A-7E Corsair II aircraft at the Naval Research Laboratory (NRL).

The A-7E project became a landmark case study in applied software engineering. Parnas and his team applied information hiding rigorously to decompose the avionics software into modules, each hiding a specific design decision — the hardware characteristics of specific sensors, the behavior model of the aircraft, the display formatting rules, and so on. They produced exhaustive module interface specifications that precisely defined what each module provided and required.

The project demonstrated that Parnas’s ideas were not academic abstractions. They worked in the most demanding environment imaginable: real-time, safety-critical, embedded software where failures could cost lives. The A-7E documentation became a template for software engineering in defense, aerospace, and other high-reliability domains. Techniques from this project directly influenced standards like DO-178B for airborne software certification.

This approach to safety-critical systems connects Parnas to a broader tradition of engineering rigor in computing. Edsger Dijkstra, who championed structured programming and mathematical reasoning about software, shared Parnas’s conviction that software development must be treated as a serious engineering discipline rather than an artisan craft.

Software Engineering as a Profession

Throughout his career, Parnas argued passionately that software development should be recognized as a branch of engineering, with the same professional standards, licensing requirements, and ethical obligations as civil or electrical engineering. This was not a popular position. Many programmers viewed themselves as artists or craftsmen, and the software industry resisted regulation.

Parnas pushed back relentlessly. He argued that when software controls aircraft, medical devices, nuclear power plants, and financial systems, the people who build it bear a professional responsibility to the public. He advocated for rigorous education in mathematics and engineering fundamentals, professional licensing examinations, and continuing education requirements for practicing software engineers.

His efforts contributed to the establishment of software engineering as a licensed profession in parts of Canada, where the Professional Engineers Ontario (PEO) began certifying software engineers. While the debate about software engineering licensure continues worldwide, Parnas’s arguments laid the intellectual groundwork for treating software development as a discipline with genuine professional obligations.

The SDI Controversy: Ethics in Computing

In 1985, Parnas made international headlines when he resigned from the Strategic Defense Initiative Organization (SDIO) advisory panel, better known as “Star Wars.” His resignation was not merely a political gesture — it was a detailed technical argument.

Parnas published a series of eight papers explaining why the software required for SDI could not be made reliable enough to justify deployment. His arguments centered on the fundamental impossibility of testing the system under realistic conditions. Unlike most software, which can be tested incrementally and refined through experience, a missile defense system would need to work perfectly the first time it was used in actual combat — a scenario that could never be rehearsed.

He pointed out that the system would need to process sensor data from thousands of sources, distinguish real warheads from decoys, calculate intercept trajectories, and coordinate thousands of defensive weapons — all in real time, all under conditions of electronic warfare, and all without any opportunity for debugging. No software engineering methodology, he argued, could guarantee the reliability needed for such a system.

The SDI controversy cemented Parnas’s reputation as a scientist willing to speak truth to power. It also established an important precedent: computer scientists have a professional obligation to provide honest assessments of technical feasibility, even when those assessments are politically inconvenient. His stance resonated with the growing awareness that technology and ethics cannot be separated — a theme that has only become more urgent in the age of artificial intelligence and autonomous weapons.

Tabular Expressions and Mathematical Documentation

Parnas made significant contributions to the practice of software documentation through his development of tabular expressions — a mathematical notation for specifying software behavior using tables rather than conventional prose or nested conditional logic.

The insight was that much of what software does can be described as a function from conditions to results. Rather than expressing this as a chain of if-else statements (which quickly becomes unreadable), Parnas proposed organizing the specification as a table where rows represent conditions and columns represent outcomes. This format makes it trivially easy to verify completeness (every combination of conditions has a defined result) and consistency (no combination leads to contradictory results).

/* Tabular expression for a traffic light controller
 * Parnas advocated tables over nested conditionals for clarity.
 *
 * This table specifies the next state based on current state + sensor input.
 * Each row covers one condition; together they cover ALL possible inputs.
 *
 * | Current State | Timer Expired | Emergency Vehicle | → Next State    |
 * |---------------|---------------|-------------------|-----------------|
 * | GREEN         | false         | false             | GREEN           |
 * | GREEN         | true          | false             | YELLOW          |
 * | GREEN         | *             | true              | EMERGENCY_RED   |
 * | YELLOW        | false         | false             | YELLOW          |
 * | YELLOW        | true          | false             | RED             |
 * | YELLOW        | *             | true              | EMERGENCY_RED   |
 * | RED           | false         | false             | RED             |
 * | RED           | true          | false             | GREEN           |
 * | RED           | *             | true              | EMERGENCY_RED   |
 * | EMERGENCY_RED | false         | true              | EMERGENCY_RED   |
 * | EMERGENCY_RED | *             | false             | previous_state  |
 */

// Implementation derived from the tabular specification
typedef enum { GREEN, YELLOW, RED, EMERGENCY_RED } LightState;

typedef struct {
    bool timer_expired;
    bool emergency_vehicle_detected;
} SensorInput;

typedef struct {
    LightState current;
    LightState previous;  // remembered for emergency recovery
} ControllerState;

LightState compute_next_state(ControllerState *state, SensorInput input) {
    // Emergency vehicle override — applies regardless of timer
    // (rows with * in Timer Expired column)
    if (input.emergency_vehicle_detected) {
        if (state->current != EMERGENCY_RED) {
            state->previous = state->current;
        }
        return EMERGENCY_RED;
    }

    // Emergency recovery — no emergency vehicle present
    if (state->current == EMERGENCY_RED) {
        return state->previous;
    }

    // Normal operation — timer-based transitions
    if (!input.timer_expired) {
        return state->current;  // stay in current state
    }

    // Timer expired, normal transitions
    switch (state->current) {
        case GREEN:  return YELLOW;
        case YELLOW: return RED;
        case RED:    return GREEN;
        default:     return RED;  // defensive fallback
    }
}

/* The table guarantees completeness: every (state, input) pair
 * maps to exactly one next state. No ambiguity. No missing cases.
 * This is the engineering rigor Parnas demanded. */

Tabular expressions have been adopted in safety-critical industries where specifications must be precise and verifiable. They represent Parnas’s broader commitment to mathematical rigor in software engineering — the conviction that software specifications should be as precise as engineering blueprints.

Influence on Object-Oriented Programming

Although Parnas did not create any object-oriented programming language, his information hiding principle is widely recognized as one of the key intellectual foundations of the object-oriented paradigm. When Bjarne Stroustrup designed C++ and when James Gosling created Java, they built language-level support for encapsulation — the enforcement of information hiding through access modifiers like private, protected, and public.

The connection between Parnas’s ideas and OOP is direct and acknowledged. Alan Kay, who coined the term “object-oriented programming” and created Smalltalk, drew on similar intuitions about message-passing and encapsulation. While Kay and Parnas approached the problem from different angles — Kay from the perspective of biological metaphors and message passing, Parnas from the perspective of engineering change management — they converged on the same fundamental insight: the internal details of a component should be hidden from the outside world.

Parnas’s influence extends beyond OOP into virtually every modern software architecture pattern. The single responsibility principle, the open-closed principle, dependency inversion, and the entire SOLID framework can be traced back to information hiding. When a contemporary software architect designs a microservice with a clean API and private internal state, they are applying Parnas’s 1972 principle, whether they know it or not.

The Concept of Program Families

Another significant contribution was Parnas’s concept of “program families” — the idea that software systems should be designed not as single programs but as families of related programs that share a common structure but differ in specific design decisions. This concept, introduced in a 1976 paper, anticipated product line engineering and software framework design.

The key insight was that most software systems exist in multiple variations: different operating systems, different hardware platforms, different customer configurations, different feature sets. If the common parts are separated from the variable parts through information hiding, then generating a new family member requires changing only the modules that encapsulate the variable decisions.

This idea is now so deeply embedded in software practice that it seems obvious. But in the 1970s, it was revolutionary. Today, when teams at companies use feature flags to deploy different configurations, when Niklaus Wirth’s influence on structured program families echoes through modern framework design, and when platform-specific code is isolated behind abstraction layers, they are all working within the intellectual framework Parnas established. Project management tools like Taskee help engineering teams coordinate the complexity of maintaining and deploying these program families across different environments and customer configurations.

Legacy of Software Documentation

Parnas was a fierce advocate for rigorous software documentation — and equally fierce in his criticism of how documentation was typically done. He argued that most software documentation was useless because it was either written after the fact (and therefore inaccurate), organized around the code structure (and therefore incomprehensible to users), or written in imprecise natural language (and therefore ambiguous).

Instead, Parnas proposed that documentation should be written before implementation, organized around the information needs of different readers (users, maintainers, testers, designers), and expressed with mathematical precision where possible. His concept of “faking it” — writing documentation for an idealized system and then implementing the system to match — was a precursor to behavior-driven development and the documentation-first approach advocated by many modern API designers.

The emphasis on documentation as an engineering artifact rather than a bureaucratic afterthought connects Parnas to Donald Knuth, whose literate programming philosophy similarly insisted that software and its documentation should be developed as a unified whole. While Knuth focused on embedding documentation within code, Parnas focused on the mathematical precision of interface specifications — complementary approaches to the same underlying problem.

Key Writings and Academic Legacy

Parnas was a prolific writer whose papers remain essential reading for software engineers. Beyond the 1972 modules paper, his most influential works include:

  • “Designing Software for Ease of Extension and Contraction” (1979) — introduced the uses relation and the concept of designing for families of systems.
  • “Software Aging” (2001) — a keynote paper arguing that software deteriorates over time not from physical wear but from accumulated changes that violate the original design assumptions, and from failure to adapt to changing environments.
  • “A Rational Design Process: How and Why to Fake It” (1986) — co-authored with Paul Clements, this paper argued that while a perfectly rational design process is impossible, documenting the design as if it followed a rational process produces better outcomes than ad-hoc approaches.
  • “Software Engineering Programmes Are Not Computer Science Programmes” (1999) — a sharp argument for the distinction between computer science and software engineering education, advocating for engineering-style curricula that include professional responsibility, project management, and domain-specific knowledge.

Parnas supervised dozens of doctoral students and influenced hundreds more through his teaching. His academic family tree includes researchers who went on to lead major software engineering groups at universities and companies around the world. The rigor and clarity he demanded from students became a hallmark of the software engineering programs he built.

Parnas in the Context of Modern Software Engineering

The relevance of Parnas’s ideas in 2025 is, if anything, greater than when they were first proposed. As software systems grow more complex — spanning distributed clouds, embedded devices, and AI components — the need for principled decomposition becomes more urgent.

Microservices architectures are essentially information hiding at the system level. Each service hides its data store, its implementation technology, and its internal processing logic behind an API. When done well, this allows teams to independently develop, deploy, and scale individual services. When done poorly — when services leak implementation details across boundaries — the result is a distributed monolith that combines the complexity of both approaches.

Similarly, the current emphasis on API design, domain-driven design, and clean architecture all trace their intellectual lineage to Parnas. Eric Evans’s “bounded contexts” in domain-driven design are information hiding applied to business domains. Robert C. Martin’s “clean architecture” organizes systems so that business rules are hidden from delivery mechanisms and infrastructure. These modern methodologies are sophisticated elaborations of the principle Parnas articulated in 1972.

For teams building complex digital products, managing the boundaries between components is one of the hardest ongoing challenges. Agencies and development teams working on large-scale web projects — including those using platforms like Toimi for client collaboration — constantly grapple with the question Parnas first formalized: where do you draw the line between what a module reveals and what it hides?

The rise of AI and machine learning adds yet another dimension. When a system uses a neural network as a component, the traditional approach of specifying module behavior through precise preconditions and postconditions becomes extraordinarily difficult. Parnas’s insistence on mathematical specification faces its greatest challenge when the module’s behavior is learned from data rather than designed by engineers. How do we apply information hiding to components whose internal logic is, in some sense, unknowable? This is an open question that researchers are actively working on, and Parnas’s framework provides the vocabulary for asking it clearly.

Awards and Recognition

Parnas’s contributions have been recognized with numerous awards. He received the ACM Best Paper Award for the 1972 modules paper, and in 1998 he received the ACM SIGSOFT Outstanding Research Award for his contributions to software engineering. In 2001, he was awarded an honorary doctorate from the ETH Zurich, Niklaus Wirth’s home institution. He is a Fellow of the ACM, the IEEE, the Royal Society of Canada, and the Gesellschaft für Informatik (German Informatics Society). He also received the IEEE Computer Society’s 60th Anniversary Award in 2007 for his foundational contributions to software engineering.

These honors reflect the breadth of Parnas’s influence — spanning theory, practice, education, ethics, and professional standards. Few computer scientists have contributed so significantly across so many dimensions of the field.

A Lasting Philosophy

Perhaps Parnas’s most enduring contribution is not any single paper or concept, but a philosophy of software development. That philosophy holds that software engineering is, first and foremost, an exercise in managing complexity. Humans cannot hold entire systems in their heads, so systems must be decomposed into pieces that can be understood, implemented, and modified independently. The quality of that decomposition — determined by what each piece hides from the others — is the single most important factor in determining whether a system will endure or collapse under the weight of its own complexity.

This philosophy connects Parnas to the broader tradition of engineering thought. Just as Brian Kernighan and his colleagues at Bell Labs emphasized simplicity and composability in Unix, Parnas emphasized that the hardest part of software design is deciding what not to expose. The discipline of keeping secrets — of resisting the temptation to let modules peek behind each other’s curtains — is what separates systems that evolve gracefully from systems that fossilize.

In an industry that relentlessly chases the new — new languages, new frameworks, new paradigms — Parnas’s work is a reminder that the deepest problems in software engineering are timeless. The question of how to decompose a system into modules is the same whether you are writing Fortran in 1972 or deploying Kubernetes in 2025. And the answer Parnas gave — hide the decisions that are most likely to change — remains the best answer anyone has found.

Frequently Asked Questions

What is information hiding in software engineering?

Information hiding is a design principle introduced by David Parnas in 1972 that states each module in a software system should hide (encapsulate) a specific design decision — such as a data structure, algorithm, or hardware dependency — behind a well-defined interface. Other modules interact with it only through that interface, without knowing internal implementation details. This makes systems easier to modify, test, and maintain because changes to hidden decisions affect only the module that owns them. Information hiding is the intellectual foundation for encapsulation in object-oriented programming, API design, and microservices architecture.

How did David Parnas influence object-oriented programming?

Although Parnas did not create an object-oriented language, his information hiding principle directly inspired the concept of encapsulation that is central to OOP. Languages like C++, Java, and C# implement information hiding through access modifiers (private, protected, public) that control which parts of a class are visible to other code. The SOLID design principles, widely taught in software engineering education, are all elaborations of ideas that trace back to Parnas’s 1972 paper. His work provided the theoretical justification for why objects should have private state and public interfaces.

What was David Parnas’s role in the SDI controversy?

In 1985, Parnas resigned from the advisory panel for the Strategic Defense Initiative (SDI, or “Star Wars”), a proposed missile defense system. He published eight detailed papers arguing that the software required for SDI could not be made reliable enough for deployment. His central argument was that the system could never be tested under realistic conditions — it would need to work perfectly in its first real use, which is an impossibility for complex software. His resignation became a landmark moment in the history of computing ethics, establishing the precedent that computer scientists have a professional obligation to provide honest technical assessments even when politically inconvenient.

What is the difference between information hiding and abstraction?

Abstraction and information hiding are related but distinct concepts. Abstraction is the process of identifying the essential characteristics of something while ignoring irrelevant details — it is about what a module does. Information hiding is a design strategy for deciding what a module should conceal from the rest of the system — it is about what a module knows but does not reveal. A well-designed module typically uses both: it presents an abstract interface (what it does) while hiding the implementation decisions behind that interface (how it does it). Parnas’s specific contribution was establishing information hiding as the primary criterion for decomposing systems into modules, rather than using functional decomposition (organizing by processing steps).

Why is David Parnas considered a pioneer of software engineering?

David Parnas is considered a pioneer of software engineering for several interconnected reasons. First, his 1972 paper on information hiding provided the foundational design principle that underlies modern software architecture. Second, his work on the A-7E aircraft demonstrated that rigorous software engineering methods could be applied to real-world, safety-critical systems. Third, he was among the first to argue that software development should be a licensed profession with ethical obligations. Fourth, his contributions to mathematical documentation (tabular expressions) and software specification raised the standard for precision in describing software behavior. Finally, his willingness to take principled stands on issues like SDI established that computer scientists bear moral responsibility for the systems they build. Taken together, these contributions shaped both the theory and the practice of software engineering as we know it today.