Many applications are built to serve multiple logical products from the same physical system. Often this is driven by a desire for reuse. "Hmm, consumer loans look quite similar to business loans" or "clothes are a product, so are made-to-measure curtains, how different can they be?". A major problem we come across is that superficially the products look similar but they very different when it comes to the detail.
Over time, single systems serving multiple products can become over generic, with code evolving to handle all possible combinations of all possible products. For example, for a generic system that is designed to handle n products with n changes per product the amount of testing that must be done to check all possible combinations is n factorial. That's a number that gets big quickly. It also explains why many of the applications of this type that the authors have encountered have had very little in the way of automated test coverage, instead relying on huge, often manual regression suites. It's simply not possible to test so many different codepaths.
In another example from the retail banking domain, static analysis led us to a Java class with 61 nested if statements. This led Daniel Terhorst-North to make the observation that there is no correct number of nested if statements since if you have one if statement, it's clearly OK to add another, but if you have 60 of them, what else are you going to do? Admitedly this example is a pathological one but it does illustrate how single codebases serving multiple products - loans in this case - can evolve unless we are careful.