YAGNI: You Ain’t Gonna Need It.
Sound bites are great – short, sweet, clear, and simple. Just like real life, right?
Seductive simple certainty is what makes slogans so problematic. Uncertainty and ambiguity occur far more frequently in the real world. Context and nuance add complexity, but not all complexity can be avoided. In fact, removing essential complexity risks misapplication of otherwise valid principles.
Under the right circumstances, YAGNI makes perfect sense. Features added on the basis of speculation (“we might want to do this someday down the road”) carry costs and risks. Flexibility typically comes at the cost of complexity, which brings with it the risk of increased defects and more difficult maintenance. Even when perfectly implemented, this complexity poses the risk of making your code harder to use by its consumers due to the proliferation of options. Where the work meets a real need, as opposed to just a potential one, the costs and benefits can be assessed in a rational manner.
Where YAGNI runs into trouble is when it’s taken purely at face value. A naive application of the principle leads to design that ignores known needs that are not part of the immediate work at hand, trusting that a coherent architecture will “emerge” from implementing the simplest thing that could possibly work and then refactoring the results. As the scale of the application increases, the ability to do this across the entire application becomes more and more unlikely. One reason for employing abstraction is the difficulty in reasoning in detail about a large number of things, which you would need to do in order to refactor across an entire codebase. Another weakness of taking this principle beyond its realm of relevance is both the cost and difficulty of attempting to inject and/or modify cross-cutting architectural concerns (e.g. security, scalability, auditability, etc.) on an ad hoc basis. Snap decisions about pervasive aspects of a system ratchets up the risk level.
One argument for YAGNI (per the Wikipedia article) is that each new feature imposes constraints on the system, a position I agree with. When starting from scratch, form can follow function. However, as a system evolves, strategy tends to follow structure. Obviously, unnecessary constraints are undesirable. That being said, constraints which provide stability and consistency serve a purpose. The key is to be able to determine which is which and commit when appropriate.
In “Simplicity in Software Design: KISS, YAGNI and Occam’s Razor”, Hayim Makabee captures an important point – simple is not the same as simplistic. Adding unnecessary complexity adds risk without any attendant benefits. One good way to avoid the unnecessary that he lists is “…as possible avoid basing our design on assumptions”. At the same time, he cautions that we should avoid focusing only on the present.
It should be obvious at this point that I dislike the term YAGNI, even as I agree with it in principle. This has everything to do with the way some misuse it. My philosophy of design can be summed up as “the most important question for an architect is ‘why?'”. Relying on slogans gets in the way of a deliberate, well-considered design.
25 thoughts on “Bumper Sticker Philosophy”
Well stated, Gene.
I think the key underlying “why” here is whether the change being contemplated is feature vs. challenge.
Features, in the traditional sense, add capabilities or functions to a system.
Challenges represent constraints, uncertainties or variabilities that obstruct the system’s ability to provide either current or future value.
IMHO, it is possible to defer features (until you know that the system definitely needs them and you know precisely what they look like).
On the other hand, delaying addressing of challenges is a game of Russian Roulette. If something is significant enough to obstruct value in a system, there’s a very high risk that ignoring it will lead to the Fram Oil Filter “pay me now or pay me later” syndrome.
Thanks, Charlie. You’re dead on with the “pay me now or pay me later” – some cans grow larger as you kick them down the road. It’s a form of technical debt that’s taken on without thought and those are the bills that break the budget when they come due.
So what is the key insight that allows one to differentiate between concerns that:
a) Must not be “kicked down the road”, to avoid the risk of an overwhelming future cost vs.
b) Can be safely ignored or deferred (i.e. YAGNI mode)
Rules “a good architect just knows” or “past experience” are evidence of an ad hoc architecture process — effective from time to time, but not very repeatable.
Martin Fowler’s advice to “look for the things that are difficult to change” is a useful rule, but:
> Not all things that are difficult to change are worth the time/expense
> For those that are, how do I systematically differentiate difficult to change from not?
Experience tells me that there is a systematic way to think about this.
I definitely agree that “a good architect just knows” is a non-answer (circular as well – I’d imagine knowing is how you determine who the good architects are). At the same time, I’m leery of drawing too bright a line as it feels like something that is too context-dependent for that.
Pervasiveness is one measure. The more widely something is used, the more risk applies to a change. Likelihood is another. Something that might be wanted someday is a clear candidate for being ignored while something already queued up for the next sprint should probably be looked at.
My post on architectural drivers captures what I look at from a holistic standpoint. All in all, I think it comes down to costs, benefits, and priorities.
Sorry! Last word disease 🙂
>> At the same time, I’m leery of drawing too bright a line as it feels like something that is
>> *too context-dependent* for that.
This is why I am also convinced that any systematic approach *must* be context-sensitive at its core.
The AESSA book chapter that I shared with you a few months back (that you liked, as I recall) describes a process for defining architecture strategy for a system that is centered around contexts and challenges. Premises:
1. Systems are designed with the intent of creating value.
2. Value is perceived subjectively (not objectively) and is strongly influenced by:
a) goals (and expectations around different levels of realization)
b) priorities (between goals as well as between fulfillment levels within a goal), and
c) uncontrollable forces (challenges) that impede the realization of these goals
3) Contexts are formed from:
a) Likeminded stakeholders = similar sets of goals. fulfillment levels and priorities
b) Exposed to similar forces/challenges = impact both in space and time
Challenges, by definition, are identifies *within* a context, because a clear context is essential to correctly understanding the value impact and relative priority of a challenge. By implication, contexts are essential to evaluating any alternative solution to that challenge.
Finally, once you have identified a set of challenges and associated them with their contexts, you have a built-in mechanism to compare them for:
> Variabilities across contexts (which challenges and how they are prioritized)
> Identifying commonalities across contexts,
> Understanding interdependencies between challenges
> Assessing how interdependencies and challenges collide (e.g. SUV rollover problem)
If you are interested, http://msdn.microsoft.com/en-us/architecture/ff476942.aspx is an article that Microsoft Architecture Journal published in 2010 that explores this in more detail.
Charlie, No worries…comments are enabled because I want to spur discussion, especially discussion of this caliber. I think that both the AESSA chapter and the MSDN Architecture Journal article you linked to provide excellent insight into translating the architecture of the problem into the architecture of the solution. That’s a level of concern where the reflexive YAGNI attitude is even less appropriate. My prior comment was from a more tactical viewpoint (one pitfall of the wide range of concerns that can fall under the category of architecture).
Thanks, Gene. Nothing with “intensity” intended at all in my reply. I was only following up on my previous post, which I had intentionally ended with an open-ended question. My intent here was just to observe that processes (albeit obscure) already exist to make the solution to the YAGNI problem be more rigorous than ad hoc.
BTW, I also realize that YAGNI was not the primary thrust of you post, just one prominent example of a more general problem – the tendency to over-simplify (and de-contextualize) decision making about difficult problems.
On that note, I’d like to add that Design Patterns (at least the Christopher Alexander and the original Go4 patterns) were rooted in “pattern = solution to a problem in a context”. Somehow the “in a context” part has fallen off of the proverbial turnip truck, and pattern has become “the preferred solution to a problem in all contexts” (as in, “this looks like a job for the Visitor pattern”).
So, sometimes you get the YAGNI effect in spite of best intentions to to contrary. Because all too often, people under time pressure are looking for *any* solution, and the idea of having design meet the evaluation of tradeoffs and risks for multiple alternatives has fallen out of fashion.
Not a problem, I definitely appreciate what you’ve contributed here.
Once again, you’re dead on re: the point I wanted to make. A formulaic approach to design is a definite non-starter in my book. If it were that simple, it would have been automated a long time ago.
As I read this post, I was thinking on Hayim’s post on adaptable design up front: http://effectivesoftwaredesign.com/2013/07/29/iasa-israel-meeting-hayim-makabee-on-adaptable-design-up-front/
It resonates with the same KISS principle (BTW, I grow to prefer Keep It Simple, Sweetheart, being less judgemental, IMO): It is OK to say KISS on everything, alas, some things truly are not simple.
The same goes for other principles, e.g. Stop Starting, Start Finishing: this is a really good principle. Individuals and teams should work on fewer things, in order to become more productive. Of course, context is paramount here:
– A team working on 20 things in parallel cannot change at once to work on one or two things. The best that can happen is that productivity will remain the same.
– A team of 20 members will find it extremely difficult to work on one or two things together as a team.
The principle is still right. For example, a team of 5 individuals, highly committed to the same goal, should strive to work on one thing at a time as a team.
Is this the one single version of the truth? Hell no! They should work together on as few things they can, considering a vast array of parameters.
Yes, I also like witty bumper stickers. If real life was so simple, books like Zen and the Art of Motorcycle Maintenance would not have become bestsellers – they would be far too long to read (as would this comment also).
Hayim’s recent posts (as well as discussion around them on LinkedIn) have helped inspire a couple of my recent posts, including this one. He’s one of those that I definitely pay attention to.
Regarding simplicity, I’m particularly fond of the Einstein quote Hayim used in the post I link to above: “Keep it simple, as simple as possible, but not simpler.” That captures the essence in a concise, but complete manner (simple, but not simplistic, so it’s a bumper sticker I can get behind).
Great point re: “Stop Starting, Start Finishing”. Aside from the fact that I heartily agree that focus is critical for teams, it illustrates that processes are systems much the same way that software is. Context is key to a good fit and the design of the process will have a profound effect on the design of the software.
Pingback: Not All Gold Glitters | Form Follows Function
Pingback: Technical Debt – What it is and what to do about it | Form Follows Function
Pingback: Architecture – Finding Simple Solutions Over a Lifetime of Problems | Form Follows Function
It seems like the fundamental principle of business is “do as little as you can and still get paid.” Ideally, a business would just print money. But, people would not find that to be a satisfying career! Maybe the principle should be: “It is fine to be a curious monkey, but know when to pull your hand out of the coconut.”
Well, I tried to add my own generalizations to the discussion. It is an interesting problem.
Pingback: Software Development, Coding, Forests and Trees | Form Follows Function
Pingback: Fixing IT – Products, Not Projects Revisited | Form Follows Function
Pingback: Bumper Sticker Philosophy | Iasa Global
Pingback: Technical Debt – What it is and what to do about it | Iasa Global
Pingback: Technical Debt – Why not just do the work better? | Form Follows Function
Pingback: Quick Fixes That Last a Lifetime | Form Follows Function
Pingback: Design? Security and Privacy? YAGNI | IasaGlobal
Pingback: Laziness as a Virtue in Software Architecture | Form Follows Function
Pingback: Who Needs Architects? Because YAGNI Doesn’t Scale | Form Follows Function
Pingback: Laziness as a Virtue in Software Architecture | IasaGlobal
Pingback: Technical Debt – What it is and what to do about it – IasaGlobal