Jeremy Voorhis recently posted a gem about heterogenous architecture:
There is something desirable about heterogenous architecture. Specialist components with clear lines of responsibility become a joy to work with, and easier to maintain. Don’t force heterogenous design, but consider it as an agile approach when you suspect your application is growing into a monolith.
I've found this to be very true, and push for solutions that use independent tools over integrated frameworky things whenever possible.
The reason why it works is simple: when two moving parts are only able to affect each other through a well-defined interface, you have a very focused set of things to think about when you need to debug or add features. Using different technologies forces the system to have a well-defined interface even if some people don't like following rules or are ignorant of best practices.
Test-driven development creates a similar effect at a smaller scale: because there's always at least two users of any given code, the test code and other production code, the developer has a strong motivation to make it easier to isolate each piece of code. The result is loosely-coupled parts that communicate across well-defined interfaces.
So right there are two ways to get to increased maintainability:
- Build heterogenous systems to force some hard boundaries between components.
- Test first, and design to make the code easy to test.
The first works anywhere. The second is more subtle and requires more cooperation from other developers, but has a deeper benefit.