This year, 2009, is the 200th anniversary of Charles Darwin‘s birth and the 150th anniversary of the first publication of On the Origin of Species. In this famous publication Darwin launched his notion of how species’ survival is dictated by their ability to make the most efficient use of the available resources in their environment, how they adapt to increase that efficiency and how the combination of increased procreation and targeted adaptation mean that the most adapted and adaptable species survive longest.
Much like species of plants and animals, the software we build for our customers (and the software built by our predecessors) lives in an ever-changing environment. Business needs change and expand, fashions change, economic booms, lulls and the occasional crisis follow one another in an endless tide. Software systems face their own survival challenges, dealing with all these changes. And much like their biological counterparts it is their adaptability that rules their survival.
Much like biological species, software systems’ survival depends on their level of integration with their environment. That integration of course comes in two forms:
Functional integration, also known as business relevance
Technical integration, or ease with which a system interacts with the rest of the business’ environment
Now, if a business system loses its relevance to the business, there is nothing that can save it. Extinction (replacement and deactivation) is inevitable. And this is a good thing (even though it may be a little painful to some), since continuing irrelevant systems hurts the business as a whole.
As long as a system has business relevance, though, its continuation is most likely valuable. In fact, it might be vital: the effort or cost of replacing a system may be so huge that it is not an option. However, even in this situation a system can find its survival threatened if its technical nature means that it does not fit well in its environment — or cannot evolve with its environment.
As an example, consider two systems from the airline customer I’ve been working for. The first is the backend system used to create and manage bookings. It runs on a Transaction Processing Facility (TPF) and can handle the large traffic volumes the airline sees every day. It consists of blocks of code, each focussed on a single backend task, plus a number of specialized databases. The system is also equipped with a number of different access layers and as a consequence can handle requests from all sorts of different sources (terminals, software systems using web service access). This system has been online close to forty years.
A few years ago this same airline decided to build up a serious web presence, which included a rather extensive front-end system. This system (a web application) was not designed quite as well as the TPF system. It was designed and built by a combination of overreaching architects, inexperienced developers and managers and business stakeholders with more focus on the bottom line than on quality. The result was an old-style J2EE application which incorporated every mistake possible: unfocussed code, huge classes mixing many responsibilities, an unclear domain model and about half the application built into EJBs and JSPs (i.e. into the infrastructure elements) instead of maintaining a clear separation between business logic and infrastructure code. After a humongous run of five years this application was replaced by a new application, built completely from the ground up in a two-year project, at great expense. Simply because the original application had become inflexible and unmaintainable.
The above example is one of a medium-sized system, but the same thing can happen in systems of every scale. For example, everybody who has ever started building JEE applications has followed tutorial examples and built a Type-I application with business logic in a JSP. And even that is an example of a mistake. Mixing the infrastructure with the application core makes the application inflexible.
There is some good news though: maintaining flexibility and adaptability of the application and ensuring that it can have a long lifespan requires nothing more than applying the lessons from software engineering, especially from domain-driven design. If you think about it, a software system consists of two parts that mirror the integration styles mentioned above:
First of all, there is the application core, the part of the application that offers real business value. This is the part of the application that the business will want to last (even if business people don’t really realize it).
Second, there are the peripheral subsystems. These are the subsystems that allow the core application to connect to the outside environment for access to dependency systems (e.g. databases) and that allow access to the core application.
The peripheral subsystems are often the product of the “flavor du jour”. Sometimes some sort of web application will be the popular option, the next day it will be a SOAP web service, a RESTful service the day after and a messaging interface based on JMS by the end of the week. For that reason it is essential to the survival of a system to keep infrastructure clearly separated from the application core: it allows the application core to expand and migrate as business needs change without major rework or rebuilding of business logic. To put it differently: ensuring a long lifetime means maintaining focus on what is important in software systems development and resisting the temptation of the cool framework of the day.
So how do you maintain such a separation? Through abstraction. Through a programatically accessed service layer that exposes the business functionality of the application. In other words: make sure that the core application is accessed through an infrastructure-independent API and in no other way.
There is added benefit to this strategy, by the way: the flexibility that comes from an API rather than a fully controlled user interface. For more complex systems having an API often means that the system functionality can be combined in ways not originally foreseen by the system designers. This allows for easy (or easier) introduction of new business processes, either using only the existing system or by combining with functionality provided by other systems. Either way it means the core system can more easily adapt to its environment, which is what keeps systems alive.
One of the things that continues to amaze me as I learn more about software engineering, is that the solution to every new problem is a bit of old wisdom. The solution above, for example, is just an application of separation of concerns. For some reason we seem doomed always to forget what our predecessors knew….
In that spirit I would like to share an amazing tidbit with you that I picked up recently in the April 2009 edition of the Jerusalem Report:
“Animals engage in a struggle for existence; for resources, to avoid being eaten and to breed. Environmental factors influence organisms to develop new characteristics to ensure survival, thus transforming into new species. Animals that survive to breed can pass on their successful characteristics to offspring.”
You may recognize this as a very succinct summary of On the Origin of Species (or of software engineering as the case may be). Very fitting for Darwin’s double anniversary year. But it is in fact a quote from the Book of Animals, a text by the Arabic zoologist Al-Jahiz.
And he lived 1000 years before Darwin did.