Software architecture is the foundation of enterprise software, so it should be well designed and thought through. Whatever technology an enterprise selects, a few underlying principles guide the software's initial development and its evolution. In this article I present the principles I've found most useful.
Collaborate
Collaboration applies to every major activity, from organizing and executing to deployment, maintenance and operations. Collaborate with people inside the known systems and outside them, and with people who know the customer and the business.
Innovate
An environment where innovation can thrive is an important part of collaboration. Brainstorming sessions are useful when they're open and non-judgmental. Keep the sharing of ideas separate from deep analysis of them: hold one session to capture every idea, and a separate session to dig into each one. In the capture session every idea is welcome, and none is judged on the spot. One idea often leads to a chain of related ideas that ends in real solution options. Always be open to improving the architecture. In my experience, folding good ideas into it makes the foundation stronger.
Improve continually
Like collaboration, continual improvement applies to every major activity. Hold effective retrospectives at the end of each sprint or activity to keep improving the team's performance.
Organize
Organizing is often one of the hardest parts of building software, and poorly organized initiatives often end up on poor architectural foundations. At a high level:
- Research the domains inside and outside the system
- Select appropriate tools and frameworks
- Plan the execution
- Bring in stakeholders and build collaboration
- Build retrospectives into planning and execution, for a continual improvement feedback loop
- Identify unknowns and challenges early, and develop options to mitigate them
Form a vision
Form a vision of where the architecture is heading. Use the organizing phase to gather the information you need to develop the right vision for the organization, and keep refining it. Start at a high level and work your way down, then work back up to verify the integrity of the design.
Execute
When you break the initiative into tasks, make sure no task takes more than two days. If one does, break it into smaller subtasks. Organize the work into one- or two-week sprints, and hold a demo and a retrospective at the end of each sprint.
Sustain
Build out slices of functionality iteratively. Monitor progress and adherence to the architectural principles. Use code reviews to teach the development team best practices and preferred software patterns. My article Beyond Code covers many more practices that sustain software development.
Transform
If you're working with an outdated legacy system, map a realistic path to transform it. One useful framework comes from John Boyd's paper "Destruction and Creation." Break the system down into smaller pieces (destruction). Look for opportunities for synthesis and integration, and build up a new system outside the existing domain concepts (creation). Then test the new creation by verifying that you can trace each concept back to its original domain. Repeat until the validation succeeds.
Architectural characteristics
Plenty of people use terms like these for architecture goals. To actually reach the goals, you need to understand clearly what each term means at the level of the software, be able to explain it at every level of the organization from developers to the CEO, and translate it into a solid architectural foundation in code.
Modular
The program's functionality is split into independent, interchangeable modules, and each module contains everything it needs to do one job.
Scalable
The software can handle a growing amount of work, or can be expanded to handle it.
Extensible
The design allows for future growth. Extensibility measures how easily you can extend the system, whether by adding functionality or changing what's there, and how much effort that takes. The goal is to accommodate change, usually enhancements, with minimal impact on existing functions.
Maintainable
The product is easy to maintain, so you can:
- Isolate and correct defects and their causes
- Repair or replace faulty components without replacing parts that still work
- Prevent unexpected breakdowns
- Extend the product's useful life
- Improve its efficiency, reliability and safety
- Meet new requirements
- Make future maintenance easier and cope with a changed environment
Layered software approach
A layered approach is a very useful framework for organizing software into layers and choosing the right patterns for each one, which supports a modular, scalable, extensible and maintainable architecture. Derek C. Ashmore does an excellent job of explaining this approach in his book The Java EE Architect's Handbook, and his blog, The Java EE Architect's Blog, is also an excellent resource. I've tried many of the concepts in his writing and found them very effective.
REST API
Front ends change quickly. Decoupling the UX layer from the rest of the system keeps that layer extensible, and a REST API helps achieve that. If you adopt the REST architectural style, understand and honor the properties and constraints it defines.
Automated testing
The principles so far build a solid foundation for a software system. Automated testing is what lets the architecture and its modules keep evolving over the long term. On a new system, build it in from the very beginning. On a legacy system, there are many techniques for introducing it. Either way, don't overlook robust automated testing. It supports the system's ongoing quality, extension and evolution.
Additional resources
- Key Principles of Software Architecture (Microsoft)
- The Java EE Architect's Blog (Derek C. Ashmore)
First published August 9, 2016. Revised October 2026.