Amr Elssamadisy has an essay on InfoQ titled "Are Agile Development Practices Detrimental to Architecture and Design?" In it, he asks,
Is iterative and incremental development à la Agile practices--where one builds only what is required per iteration--detrimental to good design? Does Scrum encourage ignoring architectural issues? Can design and architecture evolve effectively without the technical Agile practices? Does test-first development lead to good design? Or does the red-green-refactor loop stall at local-minima?
The responses so far seem to indicate that many using Scrum have this problem even teams that write tests and refactor regularly.
I agree--there is an agile engineering shortfall out there. Agile methods use aggressively short planning horizons: plans are changed every week or two, or at least every month. Because the plans will change, it's a bad idea to make design decisions that anticipate any further in advance then the next planning meeting. As a result, your design can easily be made up of short-term decisions that lack cohesion.
This looks like a pretty serious deficiency, and it would be... if there wasn't a way around it. The biggest strength of Extreme Programming (XP) is that it provides specific agile engineering practices that address this problem. In our upcoming book, Shane and I say a lot about this topic. Here's an excerpt:
When TDD is done well, the design of individual classes and methods is beautiful: they're simple, elegant, and easy to use. This isn't enough. Without attention to the interaction between classes, the overall system design will be muddy and confusing.
During TDD, the navigator should also consider a wider scope. Are there similarities between the code you're implementing and other code in the system? Are class responsibilities clearly defined and concepts clearly represented? How well does this class interact with other classes?
When you see a problem, jot it down on your card. During one of the refactoring steps of TDD--usually, when you're not in the middle of something else--bring up the issue that you saw. Discuss solutions with your partner and refactor. If you feel that your design change will significantly affect other members of the team, take a quick break to discuss it around a whiteboard.
Incremental design requires simple design and constant improvement. Don't try to use incremental design without a commitment to continuous daily improvement (in XP terms, merciless refactoring.) This requires self-discipline and a strong desire for high-quality code from at least one team member; because nobody feels that way all of the time, pair programming, collective code ownership, energized work, and slack are important support mechanisms.
Test-driven development is also important for incremental design. Its explicit refactoring step, repeated every few minutes, gives pairs the continual opportunities to stop and make design improvements. Pair programming helps in this area, too, by making sure that half of the team's programmers, as navigators, always have an opportunity to consider design improvements.
Be sure that your team sits together and communicates well if you're using incremental design. Without constant communication about class and architectural refactorings, your design will fragment and diverge. Agree on coding standards so that everyone follows the same patterns.
As you can see, there are a lot of practices that come together to support incremental design: simple design, refactoring, test-driven development, pair programming, collective code ownership, energized work, slack, sitting together, and coding standards.
There is an agile engineering shortfall. Short planning horizons necessitate alternative engineering practices. The problem isn't with the practices, though--good agile engineering practices exist and work well. The problem is with agile methods that don't provide agile engineering practices, and with teams that adopt a small subset of the agile engineering practices (typically, just TDD). It's unfortunate, but no surprise, that they run into trouble as a result.