Going into World War I, the French army had adopted a simple doctrine, attack. Attaque à outrance; attack to excess. Courage, particularly that inspired by the Poilu‘s dashing red trousers, would carry the day. Unfortunately for several million French soldiers, the plan was flawed.
It’s easy to see why this is the case in the age of machine guns and modern artillery, but it would likely have been just as ineffective without that complication. The bigger problem was that, even if the attacks had succeeded, each additional success would carry the seed of a greater defeat in the future. Each success would carry the victorious unit farther forward, making re-supply and communications that much more difficult. Each success would spread the victor that much thinner, making it more brittle to counter-attack.
Without focus, lots of little tactical successes can breed strategic defeat.
Or, as Richard Sage put it:
Lack of clarity should always be a warning sign.
It’s important to understand that while there is a relationship between goals, strategies, and tactics, there are differences as well. Seth Godin’s “Goals, strategy and tactics for change” captures both:
The Goal: Who are you trying to change? What observable actions will let you know you’ve succeeded?
The Strategy: What are the emotions you can amplify, the connections you can make that will cause someone to do something they’ve hesitated to do in the past (change)? The strategy isn’t the point, it’s the lever that helps you cause the change you seek.
The Tactics: What are the actions you take that cause the strategy to work? What are the events and interactions that, when taken together, comprise your strategy?
While he was defining the terms in the context of implementing change, the same definitions work well for software development. More than just a bag of tactics, a strategy is a set of tactics focused on attaining a goal. Just as a book is made up of words and sentences, it is also more than that. The intentional structuring of those words and sentences are what makes it a book; that is what gives it meaning. Likewise, systems are more than the sum of their parts.
A system exists via the structure and interaction of its component parts. A well designed system is one where those parts are intentionally structured so that their interaction achieves a goal effectively and efficiently. A failure to do so can impact the technical architecture of a system (taken from Tony DaSilva’s “Fragmented, Half-baked, Thoughts”):
While both System A and System B have been made to fit their context, is there any question as to which is more likely to have quality issues? Extensive refactoring, particularly at the architectural level, can become expensive. This leaves the owners of System B with a dilemma – how long can they tolerate the technical debt caused by the mismatch between the system and its context before the costs justify the work?
Failure to intentionally design can also manifest in the user experience. As Stephen Anderson tweeted:
As I noted in “Who Needs Architects? – Navigating the Fractals”, systems exist in contexts which exist in ecosystems. When designing for a particular level of abstraction, you must consider your context(s) and design your internal architecture accordingly. Likewise, you must consider the ecosystem in which the system will exist and design the external architecture accordingly. Avoiding intentional design (which I will note is neither BDUF nor over-engineering) might seem agile, but is in reality, a form of technical debt affecting quality, cohesion, and maintainability.
Tactical excellence focused on a goal is strategic excellence. Without the focus, however, tactical excellence is wasted.