Domanda

Assume you have a library in which every function is public. Sooner or later developers who use your library will come up with a stable pattern of usage. In that terms external information of how developers are using you library already defines the public interface.

If your function is dealing with only inner context of library user will not use it. User will feel that in the library there are some other functions that allow him to do his task in a more convenient manner. Why should a user use an internal function if this function doesn't touch his context?

If the user of the library want to call the internal function that touches his context but this function is encapsulated who said that it was a right decision to make it encapsulated. User context “knows” better what should be encapsulated.

Even if the user of the library is messing with internals who said that it will lead to unmaintainability. On the next iteration developer will refactor the code and will come up with the proper maintainable call. For example if you have age field and getAge() method I will use getAge() because I understand that using age field is not maintainable. By the way that doesn’t mean that getAge() is maintainable. May be operating with the field is more simple and clean than with the getAge() method.

All of this stuff you can’t predict because you look at your library inside(internally) and not externally (just because you have no information of usage). If you write your own library that doesn’t mean that you know better how to use it. If you make something private that means that you define a pattern of usage (you say to developers: “Use this, not this”). But how you can define a pattern of usage if you don’t have enough information about user needs and context? Who said that some private function should be private?

Interface of the library should be defined by a user not by the creator. And user defines it by pattern of usage. Why can't you make everything public and let the user define what should be used and how and what should not? User context “knows” better what should be encapsulated and user code already “encapsulates” your library by the practice of using.

So what's the purpose of explicit encapsulation?

È stato utile?

Soluzione

The main purpose of encapsulation is to hide complexity from the user of a class to make his life easier. This implies that there is such internal information that is irrelevant to the user.

While this is probably not always the case in practice, I do believe that there are such things as good abstractions where the user can be freed from dealing with the internals, or to put it differently, the interface is easier to understand and use than the whole thing. This can even be proven by contradiction:

If it would not be the case, development of non trivial software would be an absolutely hopeless untertaking because all developers would have to understand the whole code base. Obviously there are projects with multiple millions lines of code where this is far from being realistic.

I like to add that classes are not the only construct that provides encapsulation. Plain functions are often superior.

Altri suggerimenti

Interface of the library should be defined by a user not by the creator. And user defines it by pattern of usage.

Exactly the opposite is true. The library provider has the job of understanding the domain of the library to the maximum extent possible, with every minute detail possible, and to form it into a coherent, logically structured, easy to use, hard to misuse set of objects.

The key here is, that I, as the library user should have to understand only a tiny fraction of what the domain actually includes. Any knowledge that is pushed to the user just causes more cognitive load, which uses a finite resource (our brain).

Let's take an easy example, a logging library. Instead of giving me access to files or socket connections, most libraries just offer debug(), warn(), error(), etc. methods. How that gets written to some backend is not generally accessible, as it shouldn't be. Whether those methods write asynchronously, how they format a message, or what backend they use is also hidden from me as a user. That's what I expect.

If you feel you need to access implementation details of the library, then either the library has wrong abstractions, it's badly written, or you just have a slightly different use-case and need to look for a different library, or write something yourself.

If you accept this line of reasoning, it will become clear why abstraction and encapsulation is of utmost importance.

A smaller public interface is inherently better, as it makes it easier to implement alternative implementations.

If you add methods which are specific to an implementation then you are effectively 'breaking' that interface.

We should remember that making things private doesnt really stop a determined developer calling them. It's just a flag to help you program.

Most people find using access modifiers helpful, rather than a hiderance. Intelisense, compiler warnings and errors, code analysis etc these things make your life easy in the long run. Even if it seems fiddly to make things private, use properties over fields, interfaces etc etc

In addition to Frank Puffer's answer.

Hiding complexity is not the only reason why we make some details unreachable. We also want as much decoupling as possible. In consequence, we make our public interface thin. The thinner is the public interface of the API, the lesser coupling will be between the consumers of the API and the API itself.

But, we don't do this because we are good samaritans. It's not like we care about the consumer' source code. We do it because it allows us to change the implementation details of the API with a higher degree of backward compatibility. If consumers are too bound to the innards of the API, the backward compatibility is going to be hard (if possible). Backward compatibility might seem irrelevant at first glance, but it's not. Even if we are the only consumers of the API. You know, changes happen and you never know when or in which form they will appear.

APIs with poor backward compatibility make us refactor our own code oftener than desired (keeping dependencies up-to-date is important), what impacts our estimations and hence the plannings. We usually have more important things to think about than poor encapsulated APIs that causes too much coupling and constraints our productivity. Not to mention, we usually won't adopt APIs that are hard to implement because they are meant to make our work easier, not harder.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
scroll top