After the software development lifecycle, programs experience certain evolutionary transitions. There is the moment of genesis when the initial application demonstrates capabilities in a proof of concept, but that is ultimately superceded by a succession of modifications that eventually jeopardizes the maintainability of that code.
The work of Meir Lehman in this area is significant, his observations of OS/360 should be heeded by commercial and open source developers alike.
Unlike the smaller, faster, cheaper mantra that most of the hardware vendors have enjoyed, software developers have experienced a succession of application re-writes. In fact, Lehman would argue that this kind of lifecycle is inherent to the current nature of software application development. Developers begin with a simple idea, but once successful the demand for new features becomes unwieldly in the complexity of the legacy software platform.
One of the most significant challenges for development is taking a legacy framework and trying to retrofit a new technology into the system. This has been problematic for many vendors, perhaps the archtypal example of this is Microsoft building the Windows GUI environment to support multi-tasking on the MS-DOS single-tasking operating system.
A mitigating aspect is to work at reducing the complexity of your application.More often then not, this kind of work compromises the software architecture. The Windows implementation benefited from being loosly coupled to the core operating system, thereby allowing programmers to implement features without retrofitting DOS. Imagine if DOS had been reworked to support pre-emptive multitasking, and of course these issues become even more considerable when the size of the application increases.
The object oriented approach promised to provide the kind of building-blocks that programmers can use to accommodate evolving requirements. With OOP you can certainly include some leway in your architecture, but this will never be able to address all future implementation considerations.
A mitigating aspect is to work at reducing the complexity of your application. In other words, rather than implement new product features you should actually take the time to refactor an existing codebase to minimize product complexity. This can be extremely difficult, and in fact should result in a virtual re-write of your entire system.
There are a number of other laws of software evolution, but Lehman also makes a point to observe that a key risk is the apathy of the core development group from knowing all aspects of the application architecture. By this law, the conservation of familiarity states that once the organization loses a mastery of the application they will in turn lose control over development.
Each development organization is different and the requirements for the application architecture is varied. Despite these differences, every group will reach a crossroad where the existing framework is unsuitable for further expansion. When this happens, the true indicator for success is the ability for the technical team to realize the significance of that event rather than to continue to code around it.