Science and programming use the common concept called “black box”. This is one of the main principles of abstracting. We abstract away from internal details and consider an object from a behavioral point of view only. It allows us to fight with complexity. We split a complex task into simpler sub-tasks. Then we implement each task and assign a name to it. After that, we abstract ourselves from the internal details of each task and use the name of each sub-task as a black box.

The same way we use 3rd party software libraries. Nowadays it is absolutely unreal to write a more or less complex system from scratch. For example, we need a black box abstracting us away from particular hardware. Such a black box we call an operating system. Also, we need a lot of other black boxes which we call libraries. We consider them as black boxes even not because their source code is closed but it is impossible to analyze each line of code for which a million human-hours were spent to write.

But what are these software black boxes in reality? What do we know about them? Even those that have documentation - contain a rather brief description of the behavior of each component in different situations. Some do not contain any documentation at all. In such cases, we have to rely on the names of methods / functions / classes, etc. But a name is almost always quite vague and ambiguous. Such is the nature of any human language. Everyone can understand by the same name completely different things. And, therefore, build completely different assumptions about their behavior and purpose.

Again, even if some component contains a detailed description, it cannot reflect all the details. The description cannot be a strong confirmation of what is happening in the component. I have never seen documentation containing descriptions of algorithmic complexity, the complexity of memory usage, function definition area, side effects (interaction with external objects), etc. Also, the more detailed the documentation, the more difficult is to keep it in sync with code. In fact, after each modification of code, a programmer will have to modify related documentation to reflect every aspect, and this will, on the one hand, be very time-consuming, and on the other, will not give any guarantee that a loose text correctly reflects the behavior of related code.

Therefore, using these black software boxes, we can never be sure of what they really are. Are they who they claim to be, or they are just pretending. And this is a very serious problem. After all, we are creating more and more pretending boxes, composing them from other similar boxes. Ultimately, no one can guarantee how the program will behave in a given situation. And in fact, nothing can be guaranteed at all. I think that this is the main reason that all mass-use software products have a license, which explicitly and unambiguously warns that the developers do not guarantee anything and are not responsible for anything that may happen.

Tests do not help in this situation at all. They can only guarantee that a pretender returns a strictly defined result for a strictly specified input. And this is in the case when code does not interact implicitly with other components. But even in the case of a pure function, we have no guarantees. A test cannot verify the correspondence of all possible input-to-output combinations due to a combinatorial explosion. If you don’t believe me then consider how would you test a function which must sum up two numbers. How would you guarantee that it returns the correct result for all possible combinations of input? You can easily try to do it using any language and any testing framework. You will see very quickly that in practice it is impossible to make an exhaustive search of all combinations, even for simple addition. What then can be said about more complex functions?

That is why the only way modern software is being stabilized is through millions of hours of using the same piece of code. And, the more a software component is being used, the more likely it is that all errors will be found. But again any complex component has such a huge number of different combinations of input states that even hundreds of years of usage by millions of users may not reveal different subtle bugs. And such a bug can wait for decades, sitting inside some library, on the foundation of which stand almost all modern programs, until on some fine day it will lead to devastating consequences …

Therefore, I believe that it is time for us to stop relying on black pretenders, but develop a mechanism that will allow us to create truly honest black boxes for which we can have guarantees sufficient for each specific case. I think it is clear that there is no point in wasting the resources of mankind on components that are being used rearely and when errors do not lead to critical consequences. But there are the components on which many other systems depend and for them, we must be able to set and confirm guarantees of behavior. Otherwise, one fine day we will face the complete collapse of the whole modern software development process.