Maintaining Legacy systems

( Design decay of legacy System/threat of nearing end of life of legacy component )


Following are the symptions of design decay:-

Rigidity



        Every change affects too many other parts of the System. A design is rigid if it cannot be easily changed. Single change to a component in a heavily interdependent software begins a cascade of changes in dependent components.



       Change Impact Analysis can be predicted by the extent of cascading of changes in other modules that need to be done to make a simple enhancement in a module or component.

Fragility

  
       When you make a change, unexpected parts of the System break.

Immobility

        It is hard to reuse in another application because it cannot be dis tangled from the current      application.
       Expected design should be such that , the generic components in the application should be easily reusable in any other application. The domain specific components in the application should be easily reusable in any  other software of the same domain. If generic components and domain specific components are not reusable in another applications, then we can say that particular design has the immobile characteristic.




Viscosity

       Viscosity of design , Viscosity of environment.
        Expected design of software should be such that even though the developer has different ways to solve a bug or issue, the method which preserves the design should be easy to implement than the method which introduces additional dependencies. If the solution which does not preserve the design is easy to implement than the method that preserves design then we say that the design has the characteristic Viscosity.




Cause of un manageablity of Legacy Systems





  • Initial Architectural decisions(rigid design decisions considering all non functional requirements) of the legacy system not documented. Ideally, the architectural modelling(in the High level design document) of the modules should clearly mention the scope of each component, communication between local/remote components, collaboration between classes, rigid or boiler plate code in the framework that should not be altered, extensible points of the framework where developer is allowed to customize. All rigid design decisions by the architect should ideally be documented and shared with the developers.

  • Organisation of the components and communication between them (Architecture) is too complex that could not be easily understood and modified.


  • If design is not driven by the end users usability perspective. 



  • Rush to meet the schedule, developers maintaining the legacy code make easy changes that might introduce new dependencies and does not follow the initial architectural decisions.
  • If addition of new feature is the requirement, let the design be consistent with the design of other existing modules.




  • Distinguish the skeleton/framework related bugs and  the bugs in the extension points. Consider framework bugs [ which decide the lifetime of the product ], be given highest priority and addressed first.




  • During maintenance and bug fixes, introducing new interdependence of the modules within that design may result in design decay.
  • If the high level modules and low level modules have concrete contract rather than abstract contract, then the design will have all the decay smells.
  • If the modules/components/classes does not have single responsibility and well defined boundaries, then design will have all the above design smells. The responsibilities of all the layers should be well defined and communication contract should be well defined.
  • If the system is not broken down properly into generic components, domain specific components and application specific components then we can say that design has all the design smells.
  •  If appropriate design patterns are not used , then there is a chance of design decay.
  • Framework should have well identified frozen spots and flexible points.




Development Practices to  avoid design decay and ensure long life to the software




  1. Before implementing changes in the legacy system, take time to understand the existing systems framework basically how the Architect visualized the system keeping extensibility and other non functional requirements in mind.
  2. Identify the flexible/customizable/extensible points in the existing legacy systems framework and the rigid code/boilerplate code, before attempting to fix a bug or enhance the functionality.
  3. Understand the intent of  Object Modeling done by Architect & designer . Why the classes and collaboration between the classes of the legacy system modeled in that specific way. This ensures that enhancements we make to the legacy system does not violate initial architectural decisions and avoid accidental dependencies being added.
  4. When rigidity and fragility is observed, raise concern on the maintainability of the legacy module. And try redesigning that legacy module.
  5. For every enhancement , ensure there is a mapping between requirement and the implementation. Mention the requirement Id as comment for all the code changes related to that requirement and add requirement Id or Bug Id in the check-in request to the source control. Test cases Id's and Bug Id's must be mapped to the requirement Id and the pseudo code/UML diagram Id mentioned in the design document.
  6. Update the design document and modeling diagrams of the legacy module after the implementation.
  7. Always ensure, the changes are reviewed by the designer/architect , so that changes are consistent with the architects vision of extensibility, performance , future manageability of the system.