Software In-dependence: Liberating Your Codebase
A Tale of Enslaved Software
Walter, head of IT at a large and successful legal firm, is facing an acute challenge. The firm, Osman & Associates, has used a vendor legal informatics application for many years. This application was built on proprietary database technology owned by the vendor. The license allowed the firm to use the same database for other applications that they developed in-house. The vendor, Lightspeed Legal Informatics (LLI), had supplied a non-standard Java database driver to allow applications to communicate with the database.
LLI has recently shared with Walter their technology road map featuring the next version of their legal informatics platform. The new platform is based on an off the shelf database product with standard JDBC (Java Database Connectivity) drivers. To optimise their maintenance and support, they plan to decommission their legacy platform including their proprietary database product. And to retain existing customers and support contracts, they are offering to migrate their existing customers to the new platform for free.
For Walter, this means modifying all the applications developed in-house to start using JDBC drivers. However, the challenge is compounded by the fact that most in-house applications were rapidly developed. There is no separation between the domain logic and the database access. Database driver components were referenced directly where ever data access was required.
This migration is staring at Walter as a wholesale technology renovation. To achieve this renovation along with the planned technology change, technology budget will have to be increased. Without an increased budget the planned technology change aimed at giving the firm a competitive business advantage will be disrupted. The opportunity costs alone are substantial.
This is a classic case of software enslaved through tightly coupled dependencies.
Achieving In-dependence
Any useful software will depend on some infrastructure (databases, networks, displays etc.) or specialised libraries (graphics, numerical processing, etc.). Software drivers using standardised interfaces allow simplified interfacing with such infrastructure and mask vendor specific details from applications. Standardisation of interfaces between software components provides a level of indirection that supports independence from the specifics of corresponding dependencies. Thus, components behind these interfaces can be swapped and dependent applications will still function as long as the swapped components have equivalent functionality.
Further independence can be achieved by abstracting the infrastructure or other library dependencies behind interfaces. These interfaces interact with the application via the domain model. A comprehensive domain model implementation can support multiple applications. Changes to the dependencies only involves changes to the implementation of interfaces between the dependencies and the domain model. Risk of changes to the applications or the domain model due to changes to the infrastructure or other libraries is minimal.
In-dependence through SOLIDification
The acronym SOLID represents the five principles of object oriented design and programming. These principles help software engineers achieve systems that can be maintained and extended efficiently and economically. SOLID stands for,
- Single responsibility principle: A class should have a single responsibility.
- Open/closed principle: Software entities should be open for extension but closed for modification.
- Liskov substitution principle: Objects in a program can be replaced by instances of their subtypes without altering the correctness of the program.
- Interface segregation principle: Avoid large general purpose interfaces in favour of smaller focused interfaces.
- Dependency inversion principle: Depend on abstractions and not on concrete implementations.
In a nutshell, SOLID helps develop software components that are cohesive and loosely couple. Cohesion eliminates side effects which results in components being more reliable, maintainable and testable. Loose coupling enables substitutability which is essential not only for extensibility but also testability.
Thus SOLID components are inherently independent of the specifics of their dependencies. Applications built using SOLID components evolve better with business requirements and technological developments. Monolithic services built using SOLID components can be more conveniently segregated into microservices which result in more flexible server-side ecosystems.
The Way Forward
Software independence is achieved through decoupling dependencies, pushing them to the periphery of the system and composing the system in terms of domain abstraction. This essentially enhances system's testability, maintainability and extensibility. Better testability improves implementation quality which reduces support effort and costs. Extensibility and maintainability makes future modifications and extensions easier and less expensive thus enhancing system's longevity.
Thus, Walter has been able to argue that the short term costs of this renovation will yield long term value in terms of lower technology costs as well as greater ability to react to emerging business opportunities.
A common scenario described using fictional events.
This problem is well known to thoes of us who have to deal with it. The trick is to get it recognised outside the IT industry so systems can be set up like this.
yes, but you've hit 2 BIG items that caused this/future problems: " However, the challenge is compounded by the fact that most in-house applications were rapidly developed. There is no separation between the domain logic and the database access. Database driver components were referenced directly where ever data access was required." (1) the rapid development technique with minimal review, evidently, which would have shown a spotlight on #2 (2) no attempt to isolate "your" software from the dependency. these can and will bite you. In the example, even the JDBC bridge has undergone changes, but if you write your OWN interface routines, and your software calls them, and THEN calls JDBC routines, then you only need make changes/updates to your intermediate calls. Yes, it's another layer, and yes a little slower execution.
The challenge is to ensure that development teams have the space and time needed to build quality solutions. The idea of modular, independant software is difficult to communicate outside of the IT world. It will always be tempting for some people to focus on new functionality rather than quality. The best way to avoid accumulating technical debt is to empower the technical teams and to 'bake-in' quality to development using things like automated code quality checks and a comprehensive review process (pair programming, peer review and technical audits). Coding and design standards also help, particularly in the area of software independance.