Rational & Irrational Dependencies between the Components

Most software design processes subdivide a large system into many subsystems or “parts”, in order to build each part autonomously and compose the parts to build fully functional system. Hence, any large system usually comprise of many “parts” (e.g. Objects in the OOP or the “AC” in our CBSDF). The large subsystems are further subdivide into subcomponents, and so on.

As we know, in most systems, each part or component needs to collaborate with one or more other parts. This forces us to create coupling (or dependency) between them, so that they can collaborate with each other. For example, in an automobile, the CD-player needs power, which is a real dependency. We resolve that dependency by connecting the CD-player to the 12V DC car battery. Here the 12V DC is a predefined standardized interface, which is an artificial dependency.

Likewise, two components in an application need to collaborate usually by exchanging data. The data exchange is real dependency. Also the data must be in a predetermined or agreed upon form (e.g. a Data-structure, Object or an XML Schema), in order to understand and properly consume the data. The data must conform to a predefined format to be useful, which is an artificial dependency. Hence, both (i.e. real and artificial) are rational dependencies.

In an ideal component based system, the developer must be concerned with only rational-dependencies, for example, to remove, replace or refine a component. An ideal framework must have simple processes for the designers to partition the system into loosely coupled components, which have only rational dependencies (i.e. real and artificial dependencies). Such dependencies can be simple to find, maintain and update, for example, to remove or replace a component. Also, software vendors could sell tools and processes, which automate: finding and resolving the dependencies etc.

However, applications developed using traditional paradigms, such as the OOP, forces us to spend lot of time resolving irrational dependencies, which exists even between two objects that do not collaborate or exchange data. There is no process to rationalize the dependencies, hence it is very complex to find and resolve all the dependencies, during update or maintenance cycles of the system.

Consider a large Book-library: we catalog and index the books, so that we can find them easily. Looking through the index/catalog, to find a book is a rational-dependency. However, if the books are not organized and have no catalog, searching entire library is an irrational-dependency. Also, if we break apart each book (e.g. component) into many chapters (e.g. Objects) and spread in many floors of the library building, it would be definitely categorized as gross irrational process.

Unfortunately, the OOP process creates grossly irrational dependencies (Also notice  Fig#5). The objects used to build each functional component, are usually spread across many files and mixed with the objects of other components. Hence, it is very hard to rationalize the dependencies between the components. Furthermore, a large functional component may contain many subcomponents, which are spread across many files and mixed with subcomponents of other components. Hence, we are breaking each large book (i.e. a component, which could be encapsulated into a single physical swappable module) into many parts (i.e. chapters or sections) and spread them across many floors in the library (and no useful indexing to find them).

Note: One of the influential paper "No silver bullet", says the complexity is essence of the software and removing the complexity removes the essence of the software. We respectfully disagree and offer a proof  to clearly show that there is a "Silver Bullet". The complexity of finding all Shakespearean works in the above unorganized Book library is "Essential" or "Accidental". Does any attempt to remove the complexity (e.g. by using computers for indexing and organizing) for quickly finding his works remove essence in the Shakespearean works?

Likewise, the CBSDF just organizes the code into hierarchies of replaceable loosely-coupled components as shown in Fig#3. This organization help developers to find dependencies of each and every part accurately and readily. Otherwise isn't it like finding few needles in a haystack? How does the organization of code into hierarchies of replaceable components remove 'essence' from the application?

Accurately: Finding all the dependencies without misses or slipups through cracks
Readily: Finding them with in few minutes without any trial and error (or guesswork)

Also review an example for CF-Component Factory and pictorial over view of CBSDF. Our ambition is to eliminate even the couple of lines of dependency for each CF!

Note: Please recall the figures for the Rational-Dependencies (figure#6, Fig#8) and the Irrational-Dependencies (Fig#5 and Fig#7) in one of the previous web page: Component level abstraction Verses Object level abstraction. Most large applications contain hundreds of components (e.g. hundred times Figure#7); just imagine the ill-cataloged and not-indexed random (i.e. irrational) dependencies of the vast network of tangled spaghetti code.

Software developers are drowning in the sea of irrational dependencies. We (software engineers) are quickly lost in the complex tangled maze of spaghetti code, which is resulting from the irrational dependencies.

What a Tangled Web we weave........?

Pioneer-soft strongly believes that, "Raju's Component Process" (or "RCP") can eliminate one of the biggest causes for the “Software Crisis (Useful proof)” by eliminating the tangled web of irrational dependencies.

Note: Some one might argue that the OOP allows application to partition into parts and the parts are further subdivided into sub-parts and so on. Of course it may be 'virtually' true, but OOP do not offer a "Unified Handle" to each container-part, as computer parts such as hard-drive, CD-drive or Graphics card does. The partitioning of the Objects is only ‘virtual’. As you can see, most large parts (or sub-system) use many Objects, hence it takes considerable effort to find all the Objects, their numerous dependencies, which require painstaking error prone steps to chip away each of the Objects. The RCP physically encapsulates the subcomponents (even large sub-systems containing many parts), which can be referenced through a variable.

If there is no "unified handle" for the Loosely coupled components (Fig#3, Fig#4), the tightly coupled parts (i.e. Objects) of each component (Fig#6, Fig#8) are mixed and spread all over (in many source files as in Fig#5, Fig#7). This forces us to understand and track the interactions between large number of tightly coupled Objects of many components. The irrational dependencies between objects across component boundaries offer no advantage, except adding complexity.

 

Additional Reading: Summary

The software applications are complex NOT because individual Parts (e.g. Objects or subsystems) are complex, but the interactions between them are nearly impossible to track, document or comprehend. These untraceable inter-dependencies grow exponentially with size of the software application and they are nearly impossible to comprehend, hence increases the complexity exponentially.

Usually each Object interacts with or depends on 2 or 3 other Objects. Therefore average Object depends on less than 1% of the rest of the Objects in the application. But if we cannot "readily and accurately identify" these dependencies, it takes lot of effort to know which 1% of the Objects need to be modified or effected (for example, if we need to refine or replace the Object). Therefore, we need great deal of peripheral knowledge and undertake a complex error-prone or risky expedition to remove a subsystem containing multiple Objects.

If an application is build by hierarchically assembling swappable modules (Very Important Construct), each module can be removed by removing "readily identifiable" five to seven lines of simple intuitive coupling code, which needs almost no guessing. It is extremely useful, because it eliminates guesswork and bugs, if we are absolutely certain about the dependencies.

If one needs employ trail and error or guessing to trace direct or indirect dependencies, which leads to bugs. Please consider the work needed to remove a comparable part in the OOP. For example, if a small module contains 10 to 12 objects and spread across 5 files. These Objects end up with hundreds of very hard to trace dependencies. If one cannot be certain about the dependencies, it takes 10 times more to trace and resolve both direct and indirect dependencies; then test the software to ascertain that we didn’t miss any indirect dependencies. Redesign and quick local fixes often leads to degradation of the code structure.

In a loosely-coupled component based systems, each “loosely-coupled” component offers one or two services and each of the service can be accessed through it’s interface. To remove, refine or replace one need to concern about only its "unified handle" and these simple service-interfaces. Even a complex subsystem/module with hundred subcomponents would have only about 5 to 9 lines of well documented dependency.

Take any complex software application built using OOP, no one can tell dependencies of over 90% of large Objects/subsystems in the application. It is nearly impossible to track the interactions of each Object, since Object-interaction code constitutes nearly 50% of the total software and any effort to document the dependencies would end up far less helpful than debugging the software itself. It is a nightmare to maintain such documentation, if the software needed to be updated frequently to meet evolving business needs.

Each “loosely coupled” component localizes the complexity for the parts that must be tightly couple. For example, if a “loosely coupled” part is build by using three Objects and two subcomponents, we need limited "peripheral knowledge" only about how these parts interact with each other to refine or replace some of the Objects. On the other hand, this kind of localization is nearly impossible for most “large-parts” in today’s large Object-oriented applications. Since we cannot remove each “large-part” by removing just five-lines, many "large parts" need complex error-prone expedition to remove.

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