All Articles

Keep Calm and Hide Your Code

When abstraction leaves us, encapsulation comes to the rescue. Abstraction says: “You can view the object from a general point of view.” The encapsulation adds: “Moreover, you cannot view the object from a different point of view.”

cat-encapsulation

Lets stick to this analogy (and put aside the fact that I’m not that good at the feline-biology): encapsulation allows you to look at the cat and to pat it - to use by it’s purpose, but does not let you come close enough to find out what the cat’s paw is made of. If cat is well made than it is none of your business. Encapsulation lets you know about the existence of a paw, whether it with claws out or not, but you cannot know what it is made of (fur, happiness, magic sparkles, or other cat’s material), and you can’t see individual fur fibers.

Encapsulation helps manage complexity by blocking access to it.

Hide Your Secrets - Information hiding concept

Information hiding is one of the basic principles of both structured and object-oriented programming designs. When it comes to the first case, hiding information underlies the idea of ​​“black box”. In the second, it is associated with the concept of abstraction and gives rise to the concepts of encapsulation and modularity. Information hiding is one of the most constructive ideas in the world of software development, and now we will look at it in more detail.

For the first time, the idea of information concealment was presented to the public in 1972 by David Parnas in his article On the Criteria to Be Used in Decomposing Systems Into Modules. The term of information hiding is closely related to the idea of ​​“secrets” - design and implementation decisions that a software developer hides in one place from the rest of a program. Please mind this term till the end of the article, when I refer to the “secret” I do not mean companies business logic hidden in code or your dirty laundry.

frodo

Secrets - design and implementation decisions that a software developer hides in one place from the rest of a program. © David Parnas

During my studies regarding information hiding was adopted to turn to 20th Anniversary edition of The Mythical Man Month book, where Fred Brooks concluded that criticism of information hiding was one of the mistakes he made in the first edition of the book. “Parnas was right about concealing information, and I was wrong” he admitted (Brooks, 1995). According to Barry Bom hiding information it is a powerful method of getting rid of repetitive work, and indicated that it is particularly effective in incremental environments with a high level of change (Boehm, 1987).

In the context of the Main Technical Imperative of Software Development, information hiding turns out to be a particularly powerful heuristic principle, since all its aspects and even the name itself underscore the hiding of complexity.

Long story short Information Hiding is a concept that can be use for hiding data from external world. And that can be achieved using Encapsulation and Abstraction. I do believe that pretty much it for books and references advertising, let’s get to business!

Secrets and the right for privacy

When hiding information, each class (package, method) is characterized by aspects of design or construction that it hides from other classes. The secret may be the source of the probable change, the file format, the implementation of the data type, or the area whose isolation is required to minimize the damage from possible errors. The class must hide this information and protect its right to “privacy”. Small system changes can affect several class methods, but should not be distributed beyond its interface.

Classes with interfaces have to be complete and minimal (or close to minimal) by design © Scott Meyers

One of the most important aspects of class design is deciding which properties to make available outside the class and which to keep secret. A class can include 25 methods, providing access to only five of them and using the remaining 20 internally. A class can use several data types without disclosing information about them. This aspect of class design is called “visibility,” since it determines which class properties are “visible” or “accessible” from the outside.

The class interface should report as little as possible about the internal work of the class itself. From this point of view the class is in many ways similar to an iceberg or a glacier, most of which is hidden under water.

iceberg Look at this silly cat. He thinks he is Frederick Fleet

Show me what you got! - Improving your interfaces

Look. It is all great in theory and I appreciate that you wrote for me all this sentence of clever guys in single article…but where is the profit for my code?

Suppose you have a program in which considered a class for representing dates. One design approach would be to use integers for the date parameters (e.g. months, days) and to store them like so assigned so far in variables called like so - month, days etc. What could go wrong with that?

As soon as I trying to draw my blog around web-development context - let’s stick to TypeScript for this example. This class constructor might be declared as:

class Date {
  public day: number;

  public month: number;

  public year: number;

  constructor(day, month, year) {
    this.day = day;
    this.month = month;
    this.year = year;
  }
}

const date = new Date(29, 5, 2019);

This is a classic example of an interface that’s easy to use incorrectly. Because all three parameters are the same type, callers can easily mix up the order, an error that’s especially likely given that different cultures have different ordering conventions for a date’s month, day, and year. Furthermore, the interface allows for nonsense data to be passed in, for example, a value of -29 for a month.

Creating separate types for days, months, and years can eliminate the ordering errors, and creating a fixed set of immutable Month objects can essentially eliminate the possibility of specifying invalid months. Here’s an example in the form of a simple program:

enum Day {            // thin wrapper for Day
  D1 = 1,             // a fixed set of immutable
  D2 = 2,
  ...
  D31 = 31
}

enum Month {          // thin wrapper for Month
  Jan = 1,            // a fixed set of immutable
  Feb = 2,
  ...
  Dec = 12
}

interface Date {      // revised (safer) interface
  day: Day;
  month: Month;
  year: number >= 0;  // there is not much that typescript allows to do
}                     // with integers, even '>= 0' is an experemental feature

const date: Date = {
    day: Day.D29,
    month: Month.May,
    year: 2019
};

This example points out two important aspects to designing interfaces that obey the guideline. First, interface designers must train themselves to try to imagine all (reasonable) ways in which their interfaces could be used incorrectly. Second, they must find ways to prevent such errors from occurring.

Perhaps the most widely applicable approach to preventing errors is to define new types for use in the interface, in this case, Day, Month, and Year. It’s best if such types exhibit the usual characteristics of good type design, including proper encapsulation and well-designed interfaces, but this example demonstrates that even introducing thin wrappers such as Day and Year can prevent some kinds of errors in date specification. Now, and only now, having Date class implemented like so you may careless use it (or let someone else to) anywhere in rest of your code. It won’t let you screw things up, like it was possible before.

On the other hang, in situations like this, cunning interface designers fall back on simple encapsulation: if something is tricky or error-prone and there’s no way to get around it, they hide the tricky or error-prone code as much as possible, so as few people as possible have to deal with it. Me myself consider it as a bad practices but you may argue with me on this.

titanic

Spare Changes

To use information hiding, begin your design by listing the design secrets that you want to hide. As the example suggested from my practice, the most common kind of secret is a design decision that you think might change. Separate each design secret by assigning it to its own class or subroutine or other design unit. Then isolate–encapsulate–each design secret so that if it does change, the change doesn’t affect the rest of the program.

Some of the design areas that are most likely to change will be specific to specific projects, but I mention a few that you’ll run into others again and again in web development:

  • Input and output formats, both machine-readable and end-user readable
  • Global variables–probably never truly needed, but which always benefit from being hidden behind access routines especially in context of web-development
  • Difficult design and implementation areas, especially areas that might be developed poorly and need to be redesigned or reimplemented later
  • Use of non-standard language features and library routines
  • Complex data structures, data structures that are used by more than one class, or data structures you haven’t been able to design to your satisfaction
  • Complex logic, which is almost as likely to change as complex data structures
  • Business rules such as the laws, regulations, policies, and procedures that are embedded into a computer system
  • Data-size constraints such as array declarations and loop limits

What Should I Hide?

I think for now it is quite clear that I generally try to err on the side of encapsulation. But trying to speak unbiased - asking about what needs to be hidden supports good design decisions at all levels. It promotes the use of named constants instead of literals at the terminal implementation level. It helps in creating great subroutine and parameter names inside classes or any other structures. It guides decisions about class and subsystem decompositions and interconnections at the system or/and browser level. Get into the habit of asking, “What should I hide?” You’ll be surprised at how many difficult design decisions disappear before your eyes.

hidden-cat

Would you like to know more? Read what I read


Use of Abstract Interfaces in the Development of Software for Embedded Computer Systems. The Mythical Man-Month: Essays on Software Engineering, Anniversary Edition (2nd Edition) Software Requirements: Encapsulation, Quality, and Reuse