We dare say that the software industry moved from one extreme to the other. Decades ago, writing software was inspired by the slogan “model first, code later.” This led to considerable efforts to have a big comprehensive design up front. There’s nothing wrong with an upfront design, except that it is like walking on water. It’s definitely possible if requirements, like water, are frozen.
Maybe because of global warming, requirements hardly ever freeze these days. Subsequently, whomever embarks in an upfront design risks sinking after only a few steps.
Mindful of failures of upfront design, architects and developers moved in the opposite direction: code first, model later. This philosophy, although it is awkward, moves things ahead. It just works, in the end. Adopting this approach makes it hard to fix things and evolve, but it delivers working solutions as soon as possible, and if something was wrong, it will be fixed next. Like it or not, this model works. As our friend Greg Young used to write in his old posts, you should never underestimate the value of working software.
What we’re trying to say, however, is that some middle ground exists, and you get there by crunching knowledge and deeply understanding the domain. Understanding the domain leads to discovering an appropriate architecture. However, it doesn’t have to be a single, top-level architecture for the entire application. As you recognize subdomains, you can model each to subapplications, each coded with the most effective architecture. If it still sounds hard to believe, consider that it’s nothing more than the old motto Divide-et-Impera that—historians report—helped Julius Caesar and Napoleon to rule the world.