Information Hiding, Encapsulation and Modularity of Software

Understanding the motivation and history of these notions and their relationships

Shaaz Ahmed
The Software Firehose
6 min readMar 25, 2018

--

UPDATE: Since writing this, my understanding of these concepts have either changed or found enhanced clarity in certain cases. Two papers that have significantly influenced my thoughts in this area are Programming as Theory Building by Naur and Out of the Tar Pit by Moseley and Marks. I’m certain that it would be a better use of your time to skip my blog post, and read those two papers instead. I’m not removing this (rather incoherent) post.

I’ve been interested in the role of information hiding in producing good code, and the goals that information hiding tries to achieve. I’m curious about other ways in which the same goal can be achieved. We will talk about the origins of the concept of information hiding, the motivation behind it, concepts similar to it, and briefly touch upon how functional programming strives to achieve the similar goals.

Like most of the little academic knowledge of software that I’ve acquired, I first came across the concept of information hiding in the section called “The Costs of Introducing Assignment of the classic book Structure of Interpretation of Computer Programs. Information hiding, encapsulation and modularity are related concepts that are often loosely tossed around together while talking about good design principles, so let’s first examine what these words mean to the best of our ability.

Definitions of Information Hiding, Encapsulation & Modularity

Information Hiding:

Let’s begin by taking a look at the Wikipedia definition for information hiding:

[…] information hiding is the principle of segregation of the design decisions in a computer program that are most likely to change, thus protecting other parts of the program from extensive modification if the design decision is changed. […]

That sentence describes what information hiding entails, including one concrete benefit of employing information hiding.

Encapsulation:

In his book Object-Oriented Analysis and Design with Applications, Grady Booch defines encapsulation as:

the process of compartmentalizing the elements of an abstraction that constitute its structure and behavior; encapsulation serves to separate the contractual interface of an abstraction and its implementation.

The term encapsulation and information hiding are sometimes used interchangeably — however, there isn’t any unanimous agreement that they are identical. Many people try to reconcile these differences by claiming that information hiding is the principle and that encapsulation is the technique. Frankly, I was under the impression that the reverse was true — that encapsulation was the principle and information hiding was the technique. Well, it doesn’t look like we’ll get far with that chain of reasoning — it is probably more useful to look at the consequences of these two different ideas than to understand what they are.

Modularity

I believe that the goals of modularity encompasses the goals behind both encapsulation and information hiding, but seeking a definition leads us to even more nebulous notions.

Wikipedia defines modularity as ‘the degree to which a system’s components may be separated and recombined’. Other definitions may omit the ‘recombined’ aspect. However, Wikipedia also has other (but similar) definitions for modularity. It describes modular programming as ‘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’. In yet another place, it defines modularity in the context of software design as ‘a logical partitioning of the “software design” that allows complex software to be manageable for the purpose of implementation and maintenance. The logic of partitioning may be based on related functions, implementation considerations, data links, or other criteria’.

Personally, I find that a much easier way to understand modularity is by contrasting it with what seems to be its logical antonym — interdependence, or strong coupling. These distinctions between modularity and interdependence are nicely illustrated and compared on the Christensen Institute website.

Effects of Information Hiding, Encapsulation & Modularity

As Nassim Nicholas Taleb talks about in his book Antifragile, it is often easier to understand the effects of a principle than the principle itself.

To understand the effects of information hiding, one need not look further than its history.

History of Information Hiding

Information hiding was first introduced in David Parnas’ 1972 paper: “On the criteria to be used in decomposing systems into modules”. In that paper, he suggests splitting programs into different modules, and listing down and hiding within a module the ‘design decisions most likely to change’, so that you need to change just one module when one of those decisions change. On a tangential note, Parnas wrote a paper with the same name in 2002, clarifying aspects of his older paper and what he has learnt since then, including a few interesting comments on OOP and ADTs.

In the 1972 paper, Parnas cites his goal as modularity (as evident from the title of the paper). But what are the benefits of modularity?

The Upsides of Modularity

In his book Working Effectively with Legacy Code, Michael Feathers cites four reasons to change code: adding a feature, fixing a bug, improving the design and optimizing resource usage. The goal of modularity is to ease the process of changing code.

  1. Modularity allows you to swap out one implementation of a part with another, easing optimization of resource usage and also replacing parts of the code with minimal changes. This is what Parnas tried to achieve with information hiding— hide design decisions most likely to change within a module.
  2. Modularity lets other humans easily identify which parts to change and where bugs may lurk, because it establishes a conceptual barrier around a collection of things. In this respect, modularity is the practical realization of encapsulation, i.e. modules are mappings of encapsulated abstractions to real systems. If I know that I’ve strongly encapsulated my code, then I have to worry much lesser about whether change in one module mandates change in another.
  3. As an extension of point #2, modularity tries to work around the inability of human beings to keep many things in their head. In one of the most cited papers in psychology, “The Magic Number Plus or Minus Seven: Some Limits on our Capacity for Processing Information”, cognitive psychologist George Miller argues that the number of objects an average human can hold in working memory is 7 ± 2. This principle necessitates the modularity of a system for the sake of understanding the system easily, and consequently, ease of maintenance. Martin Fowler expresses this in his comment: “Any fool can write code that a computer can understand. Good programmers write code that humans can understand.”
  4. Modularity done right can lead to high reusability of the components of your code. In this context, the benefits of modularity are multiplicative — if you’re able to easily reuse a module that took you two weeks to implement with an hour’s effort, you’ve practically scaled your productivity non-linearly by saving time for both you and the people who you’re writing software for.

However, for the last point to be valid, your modules should possess certain positive traits. In Bartosz Milewski’s online series ‘Category Theory for Programmers’, he posits that modules are useful when the information required to compose them grows slower than the information required to implement them. “The idea is that, once a chunk is implemented, we can forget about the details of its implementation and concentrate on how it interacts with other chunks.” This is also what good encapsulation can help you achieve.

I’m sure I’ve missed out quite a few upsides (and potential downsides) of modularity. However, I hope the discussion has helped better understand the intertwined relationships between modularity, encapsulation and information hiding.

Functional Programming

Functional programming tries to achieve the goal of modularity in different ways. A concrete example of the reusability via modularity in functional programming is provided in the chapter of Structure and Interpretation of Computer Programs called “Modularity of Functional Programs and Modularity of Objects”. If I were to read only two things on modularity, it would be that chapter and the previous one mentioned in the introduction to this post.

However, that chapter does illustrate that functional programming does not magically take away the issues software raises.

Another seminal paper that outlines the differences in approach of functional programming is Out of the Tarpit. It illustrates how reasoning about state is much harder than reasoning about pure transformations, and consequently reducing ease of changing code and identifying bugs. It also raises some interesting points, such as the fact that long-living code is often written once and read many times (to simply grossly). This means that optimizing for readability may have higher pay offs in the future than optimizing for immediate ‘write-ability’ of the code.

--

--

Shaaz Ahmed
The Software Firehose

Every reader should ask himself periodically “Toward what end, toward what end?” — but do not ask it too often lest you pass up the fun of programming. — Perlis