How does “loosely coupled” components control complexity?

The “loosely coupled” component based software development process partitions the application into “loosely coupled” parts, each of which usually should not require no more than 9 lines of coupling code and on average needs 5 line of coupling code.

Please review how we can setup the supply chain of "loosely coupled" components as shown in the figure#1. One must be able to physically separate each of the “loosely coupled” components by deleting the few lines of the coupling code. When a “loosely coupled” component is separated/removed, all its code and code for subcomponents must be removed from the application code with out leaving any traces. 

Each “loosely coupled” component (referred to as 'AC') must be custom designed to satisfy unique needs of the application. (Hence main design objective is NOT "reuse", but to encapsulate all its code and subcomponents in a physical container). Each “loosely coupled” component supports one or more simple well-defined interfaces (e.g. functions) to access its services. All the other components must interact with each of the component through its predefined interfaces. Hence, it is possible to remove or replace the component by removing about 5 lines of coupling code.

It is possible to limit the size of the code for each “loosely coupled” component's class to between 250 to 500 lines of code. If any of the “loosely coupled” component is too large for average developer to comprehend in less than few hours, we must partition this again into “loosely coupled” parts, each of which usually should require about 5 lines of coupling code. This process must be repeated until code for each “loosely coupled” component in not too complex, so that an average developer can comprehend the code in few hours.

Each “loosely coupled” component is designed by tightly coupling few Objects (e.g. business logic and presentation logic) and/or assembling few “loosely coupled” subcomponents. The total code for the component-factory (or CF) should be less than 500 lines, so that an average developer can comprehend the design in few hours. We must limit the knowledge one needs to refine or replace such “loosely coupled”.

It is absolutely essential that one must be able to remove any component in minutes with little or even no “peripheral knowledge”. Then he should be able to refine that component in full isolation. All he needs to comprehend is only the following:

  1. The features, design and implementation of the component’s 500 line of code.

  2. The service interfaces of the “loosely-coupled” component, through which this component collaborate or communicate with other components.

  3. We often use other Objects and subcomponents to build parts of the component, hence we must also comprehend the simple one or two services of each of the subcomponents and interfaces of each of the Objects (e.g. GUI or EJB etc).

The developer should only need to know the interfaces of the Objects and subcomponents used for building the component. He should not need to have any knowledge of internal implementation of subcomponents or Objects used in building the component. If he needs to acquire any knowledge about their internal design, it is impossible to limit the complexity to the component's 500 lines or less code. 

For example, if one needs to replace a car-battery, he certainly don't need to comprehend chemical process of how the car battery stores and supplies power. All he must know is  about its interfaces (e.g. to get its services). Please refer to the reference given at the bottom of this web page. Mr. Brad Cox, gave an excellent illustration to says: "encapsulated complexity is no longer complexity at all". 

In the developer's perceptive, complexity of any object/subcomponent is limited to it's interfaces. Just needs to comprehend is how to use each Object/subcomponent in building the component. For example, if he uses a reusable GUI Class to present a Pie chart with 3D-filters, he needs to know its methods to input data and no need to know primitive graphics, trigonometric calculations, implementation and 3D-filter etc.

Please notice that the reusable GUI Classes are often not “loosely coupled” components, because each requires dozens of lines of coupling code (since they are designed for reuse, to be generic and customizable with money pieces of config-data ).

Furthermore it is highly desirable to employ generic automated CASE-tools to define the service-interfaces of each "loosely coupled" component and detect broken interfaces between any two components. This would help redesign and test each component in isolation. If it is required to redesign one of the subcomponent, it must be done in isolation for example by a separate developer or on a different day. Please remember that these service-interfaces can be custom designed in advance to meet unique needs of the application. Then we can use automated CASE-tools to refine the interface and to detect broken interfaces. This allows developers to refine each component in complete isolation from rest of the application.

Since any “loosely coupled” component in the application can be taken out by removing about 5-lines of code, the developer needs almost no “peripheral knowledge” to refine the component. Also the size of the code is limited to 250 to 500-lines, hence one can gain sufficient knowledge about its internal design and implementation in few hours to refine the component to meet new business requirements.

If you carefully study any large applications, you will readily identify many components, which do not collaborate with any other components, hence need no coupling code. You can also learn that, most components can be designed with two or less service-interfaces. These methods allow us to partition the application into nothing but a collection of “loosely coupled” components, each of which can be refined even by a new recruit in isolation with almost no “peripheral knowledge”.

In the OOP, it is nearly impossible to trace these dependencies and isolate large components, if the component is build by using many Objects. In OOP, each large part is build by using many Objects and the Objects are spread across many files and mixed with other Objects that are used for building other parts of the application. Since code of multiple parts are mixed and placed in same set of files, all the parts are in effect tightly coupled to each other. Hence it is nearly impossible to remove any part, even if the part is not communicating with any other part and needs no REAL coupling code.

In the OOP, the basic building block is the Object, which often are tightly coupled with each other. Hence one must remove each Object at a time, to remove most such large components. Please remember each Object usually have numerous interfaces and tightly coupled to other Objects. It is nearly impossible to comprehend all the interdependencies between the Objects. It requires huge “peripheral knowledge” to remove such “tightly coupled’ objects. These factors make it nearly impossible to remove a large subsystem. 

Software is complex, not because of its individual parts are complex. These parts are usually very simple.  But complexity explodes because of the countless untraceable nearly impossible to comprehend irrational interdependencies between the parts.

In OOP, it is nearly impossible to encapsulate all the Objects used in building each component into a physical container and maintain physical separation of the container from other such component containers  in the application, even if it doesn’t communicate with any other components. Hence to remove the component, we must undertake painstaking error prone complex expedition to remove each tightly coupled Object used for building the component. You must understand this encapsulation of “loosely coupled” components into a handler and the ability to physically separate in minutes. This would allow us to refine the component in isolation with little or no “peripheral knowledge” and again takes minutes to incorporate the component.

Usually software projects are never designed perfectly at the beginning of the implementation and often need to deviate from initial design as problems uncovered. Also even after release, we need to redesign the application frequently to meat evolving business needs. Due to the time pressures or if you are new, it is nearly impossible to replace a large-part. We often forced to add more code and/or make suboptimal changes to the existing code to satisfy new needs. This lives many chunks of awkward and even dead (i.e. unused) code. This process quickly degrades the software into spaghetti code. Since he doesn’t know what the dead code is doing, it adds to the complexity and takes considerable time for new recruits to understand the historical perspective.

On the other hand, in the “loosely coupled” systems, any mistakes are localized to each “loosely coupled” component. Since each component contains no more than 500 lines of code, which can be comprehended easily and any suboptimal improvements can be quickly identified and fixed in isolation. 

I don’t have to show that it substantially cuts the complexity, if one can deal with small chunks of code one part at a time in complete isolation. It is quite obvious to any one in any other engineering discipline and probably laughs at me, if I try to explain this simple fact. Unfortunately I am learning that it is quite complex task to convince this simple fact to the software experts. Why should I need to defend this simple fact, when all I need is just show that it is possible to partition even the software into “loosely coupled” parts? Really I am not able to understand what I am doing wrong?

Let me leave with a thought: have you ever seen subcomponents of hard-drive included in the graphics-card and subcomponents of graphics-card in the hard-drive? Why do they need to physically encapsulate subcomponents? Now look at your application. Can you encapsulate all the subcomponents of each component in a physical-container and physically separate such containers in minutes. Why not?

Note: All other component-based systems strive for elusive “reuse”. We believe each part is unique, so there is a limit for reuse that can be met by reusable GUI-API and Templates. The CF/AC never designed for reuse, instead each CF is designed for:
(1). 
Physical-encapsulation of the component's code and its subcomponents; and
(2). 
Minimize the component's dependency to about 5 lines of coupling code.

Few simple guidelines for the “interface contracts” between components

Please remember that, we must custom design these service-interfaces to minimize the dependencies for each component. The main objective is adoptable to changing needs and most certainly not code reuse. To be easily adoptable to changing needs, each component must be designed, so that, it require minimum coupling code to include in the application or to isolate from the application for refining/replacing .

Also the interfaces must be easily extensible to meet changing needs. Usually components interact with each other by exchanging messages. Hence to be adoptable to evolving needs the messages can be designed using easily extensible data format, such as XML. It is highly desirable to reduce coupling for each component. So we need to minimize the number of interface-functions, which often can be accomplished by passing more data in the function-parameters or including more pieces of data in the XML-message string.

Also we should use generic automated CASE-tools to detect the broken interfaces. For example, when a service-interface (e.g. message content) of a component is modified, the tool must detect, if any of the other component that requesting the service is inadvertently not updated to process the new message. For example, we may employ versioning or XML-schema for the message format. Before consuming the data, the tool can be used to compare interface version-number or more elaborate method to detect incompatible XML-schemas for which each of the interacting components are designed.

The CBSDF alleviates the "software crisis"  by cutting the complexity of the software development and long term maintenance, because:

  1. Over 90% of your application can be partitioned into “parts”, each is no larger than 500 lines of code. Maintenance of each  “part” is not complex, since the changes can be done in isolation and needs very little or no “peripheral knowledge”. 

  2. Each part requires about five lines of integration code (or coupling code). By removing the coupling code, one can remove each “part” from the application. Integrating the refined or a new "part" needs five lines of coupling code. One could employ simple tools to detect any broken interfaces.

If the automobile were to be designed to provide this kind of "service-access" to each "part", how many people still need a mechanic? As soon as he opens the hood, each "part" is clearly marked and visible at the top. It takes about few minutes to replace. For example, how long it takes to replace 'top-level-part' such as car-battery? It warns, if he installs an incompatible part. But to replace a piston today, for example, one needs to remove many other parts to get to the engine. Then he must disassemble the engine to replace the piston.

One must have experience and lot of "peripheral-knowledge" to replace a subcomponent-of-a-subcomponent of a component. In the CBSDF even the deepest subcomponent is clearly visible at the top and needs five-lines of code to replace.

This is an Very Important point, one must always keep in mind!

Just put your imagination-cap and visualize the possibilities. For example, the deepest 'parts' give fine-grained control and flexibility, while often being the simplest and most effective place to fix problems. Furthermore, it is possible to build IDE/CASE tools, so that, we need to custom design and manually-code only these 'parts' and employ the tools to automate rest of the development.

Note: Please refer to the above figure#1. If one needs to remove AC-15, he removes about five lines of code in CF#19, which instantiates CF#15 to generate AC-15 and integrates the AC-15. Likewise, if one needs remove a deepest subcomponent AC-09, he removes five lines of code in CF#12. Unlike automobile parts, the depth of a part really doesn't add any complexity in the software systems.   ...   Isn't it Cool?

Please click here for a proof that there is a "Silver Bullet"

References

[1] Dr. Brad Cox, "No Silver Bullet Revisited", American Programmer Journal, November 1995

Dr. Cox Says: What does is realizing that encapsulated complexity is no longer complexity at all. Its gone, buried forever in somebody else's problem. This shifts the focus to the human systems that manage complexity successfully versus those that don't. The productive question is "How do wooden pencil makers encapsulate complexity so successfully that the rest of us have the luxury of forgetting that complexity is even there?"

Miscellaneous Documents Privacy Policy | Site Map | Services
Designed By SINDHU SYNERGY
Copy Right © 2006 Pioneer Soft, LLC. All Rights Reserved.