I started reading a book about patterns. It constantly contains sentences like
encapsulate what changes
What does it mean to encapsulate? I understand the word
инкапсуляция as hiding data about the implementation of some parts of the code to increase the level of abstraction. But what it means to encapsulate is not completely clear … The thought comes to mind that this is a process of hiding implementation data. But my view does not always match the context from the book …
There are two similar concepts in software development – encapsulation and information hiding. Someone thinks that these are synonyms, some do not, but this is not so important.
A bit of history: David Parnas in the 70th year in the article “On the Criteria To Be Used in Decomposing Systems into Modules” for the first time introduced the concept of information hiding as a key design tool. This principle sounded like this: the decomposition of the system into modules should not be based on the analysis of block diagrams or execution flows. Instead, each module should hide some design decision inside, providing the minimum amount of information about it to its customers.
Here's a small example.
Let's say you're developing a marketing application that does something important. Any normal application usually requires some configuration: well, parameters for connecting to a database or server, and other valuable information. And so, a seasoned artichector (*), together with an equally seasoned client, are asked to read the configuration from the configuration file.
(*) this is not a typo, please don't correct it!
In the process of talking with them, you understand that no one really knows why you need to read the configuration from the file, what format it should have and what exactly should be stored there.
Now you are faced with a choice: you can spread the configuration information evenly throughout the application. Each component that needs some parameters will go into app config by itself, pull out the necessary data from there, parse xml or json and will be ready to serve. On the other hand, it is clear that the decision about where exactly the configuration is stored and in what format may change in the future. Therefore, a more sane solution would be to hide the configuration location and format information in a single module, for example using the
ConfigurationProvider classes. In this case, when (yes, exactly, “when”, not “if”) the requirements change, then only the implementation of the
ConfigurationProvider class will change, and all other users of this class or configuration will remain unchanged. Likewise, when the format changes, only the parsing process will change, not the configuration consumers.
This example seems contrived, but it is not! We encounter variability in requirements quite often, but unfortunately we use one of two approaches:
• We completely ignore the possibility of changing requirements and do everything head-on or
• We create a super complex solution with a dozen levels of indirection, which should withstand changes in requirements in any direction without changing the code at all.
The smarter approach is somewhere in the middle. Every time I start developing a feature, I think how many pieces in the code will have to be changed if the requirements or implementation details change significantly. At the same time, I'm not trying to reduce the number of changes to 1 (well, like, if we follow the SRP, then there should be only one place, in case of a change in requirements). I try to keep these places small and make the changes simple.
Actually, this is the essence of information hiding and its younger sister – encapsulation.