When talking about application flexibility, the first thing you would think of probably is dynamic typing. However, dynamic typing is evil in a way that it is too flexible to maintain correctness, safety and predictability. Defensive coding and testing may alleviate the issues to some degree. But, how much defensive code is enough? How many tests are enough? The answers are probably “never enough” or “don’t know”. Plus, defensive code is ugly!
Static typing is evil in the opposite way that it is too inflexible to adapt to changes. Static typing is infamous in its rigidity and inflexibility to changes. That should not be the case, though! With loose coupling and object decoration, static typing is readily adaptive to changes.
Loose coupling is not new and is a great idea coming out of static typing. But for some reason, it has been underused. A system initially loosely-coupled is often quickly turned into tightly-coupled due to lack of follow-throughs to support it (mentally or technologically). With the advent of object decoration, behaviors can be added at runtime to a loosely-coupled system. Loose coupling forms a basis for adding dynamic behaviors – behaviors at runtime, which effectively make a software system adapt to changes. Vice versa, putting changes in dynamic behaviors makes a software system remain loosely-coupled. Object decoration technologically makes loose coupling possible over the course of evolving of a software system.
Loose coupling is based on interface, with which a client does not need to know about the inner workings of a component in order to make use of it. By programming to interface, the client is completely decoupled from the implementation of a component. Consequently, a component can replace another (at design time or runtime) as long as the successor component implements the same interface as the initial component without breaking the system in which the component operates.
Here is how loose coupling with object decoration adapts to changes. As new requirements come in, dynamic behaviors are created for them. The dynamic behaviors are, then, attached to methods of interface at runtime as needed. There is no need to modify the existing components. It is pure client-side coding.
In case of a new release of components, they can be just dropped into the client application as long as they keep their interfaces. The client application gets the new features of the components automatically.
This way, the client evolving and component enhancement are completely separated. And best of all, the system stays loosely-coupled. With the support of dynamic behaviors, it is possible to design a truly loosely-coupled software system. In the end, the loose coupling is not just an ideal, it is a reality.
Now it is time to mentally get ready for design of loosely-coupled system. Actually, loosely-coupled design is very simple. You design client contract (interfaces), implement them in your components, and program to these interfaces in client application, then, add extra behaviors at runtime with object decoration as needed based on requirements or changes of requirements. That’s it.
The important point here is add behaviors at runtime with object decoration instead of adding behaviors at design time with classes. That is the reason why a loosely-coupled system can stay loosely-coupled. Furthermore, why do you need class if method (dynamic behavior is method) can solve the problem? And, remember that some dynamic typing languages live without class!
As final notes, I would like to say a few words on flexibility. By now, you would agree that flexibility is possible with both static typing and dynamic typing in terms of adding behaviors at runtime. However, the mechanism used by static typing is different from dynamic typing. In static typing, the flexibility is achieved by loose coupling with object decoration, therefore, safe and predictable. On the other hand, the flexibility in dynamic typing is achieved by altering object types, therefore, unsafe and unpredictable.