Tuesday, March 22, 2011

YAGNI Abuse

Have you ever proposed a code change or a course of action in a project for the purpose of improving the stability and maintainability of the code base, only to have someone dispute the need on the basis of YAGNI? I was flummoxed the first time this happened to me. Since then I've learned that it's not at all rare, and in fact may even be common.

The YAGNI principle is a wonderful thing. Used properly, it can have a huge beneficial impact on your productivity, your schedule, and on the maintainability of your product. But like so many other important ideas in the history of software development, YAGNI has become a poorly understood and misused victim of its fame. Through constant abuse it has become difficult to communicate the sentiment that it was intended for without a thorough explanation. And I can't count the number of times I've heard YAGNI cited in a completely incorrect or even dangerous way.

The term "YAGNI" has fallen prey to a similar disease as "agile". People often invoke it as an excuse not to do something that they don't want to do. Unfortunately, this quite often includes things that they should do. Things that have long constituted good design, and good software engineering practice. A few examples of things that I have personally been horrified to hear disputed on YAGNI grounds include:

These are all activities that are strongly valued and diligently practiced in the most productive, successful, and small-A-agile software development organizations and communities. For myself and many of you out there, it's patently obvious that this is a subversion and abuse of the YAGNI strategy. Your first instinct in response to this kind of misuse is to say, with no little conviction, "that's not what YAGNI means."

This, of course, will not convince anyone who has actually attempted to use the YAGNI defense to avoid good engineering practices. But to refute them, you needn't rely solely on the forceful recitation of the principle as they do. Fortunately for us, YAGNI is not an elemental, indivisible tenet of software engineering. It did not spring fully-formed from Ron Jeffries' head. Rather it is based in experience, observation, and analysis.

It is clear from reading Jeffries' post on the XP page that the key to sensible use of the YAGNI principle is remembering that it tells you not to add something that you think you might or probably will need, or even certainly will need, in the future. YAGNI is a response to the urge to add complexity that is not bringing you closer to the immediate goal. Particularly common instances of true YAGNI center on features that haven't been identified as either crucial or wanted, such as configurability, alternative logging mechanisms, or remote notifications.

Looking at my original list, it is clear that none of these things truly add complexity in this way. A very naive metric of complexity such as "number of code entities" may seem to indicate the opposite. But these are actually all established and reliable methods for controlling complexity. What these techniques all have in common is that they restrict the ways in which parts of your program are allowed to interact with other parts of your program. The interaction graph is the most dangerous place for complexity to manifest in a program because it compounds the difficulty of changing any one part of the application without affecting the rest of it like a row of dominoes. The practices I identified above, which are so often refuted as "adding complexity", are some of the many ways to guide your application toward this:


And away from this:


There is a multitude practices, patterns, and design principles that help keep your modules small, their scopes limited, and their boundaries well-defined. YAGNI is one of them, but not the only one. Claiming YAGNI to avoid this kind of work is "not even wrong". Not only are you gonna need it, but you do need it, right from day one. Working without these tools is seeding the ground of your project with the thorns and weeds of complexity. They provide you with a way to keep your code garden weed-free. In this way they are kin to YAGNI, not its enemy. Claiming otherwise reveals either a disrespect for, or a lack of understanding of, the benefits of good design and engineering practices in a general sense. So next time someone sets up this contradiction in front of you, don't let them get away with it. Show your knowledge, and stand up for quality and craft.

3 comments:

Nate Schneider said...

Chris, great post!

It's interesting that I can say that, because the point of your post is actually quite the opposite of what I've been feeling/saying a lot lately. Unlike you (as it seems), instead of being around anti-design people, I find myself around people who feel the need to add 5 layers of abstraction for the simplest, one-off features, to which I've adopted "SYAGNI" (Seriously, you aren't gonna need it).

It is interesting how one's surroundings and co-workers at opposite ends of the spectrum can shape opposite opinions on the same topic (too much or not enough YAGNI)...and still agree on its meaning and its importance.

Here are few more links I love to reference when talking YAGNI:
* YouArentGonnaNeedIt
* DoTheSimplestThingThatCouldPossiblyWork
* BuildForTodayDesignForTomorrow

Cheers!
-Nate

Chris Ammerman said...

Thanks for sharing your own experience on the topic. I definitely understand where you're coming from, and I can believe that you are really facing YAGNI scenarios. There's a big difference between an architecture astronaut and someone who is just trying to isolate things and make them testable.

I want to stress again that it's not YAGNI that I have a problem with. You can't really ever have too much YAGNI. Either you need something right now, or you don't. And if you don't, there's no reason to implement or prepare for it.

But I do very strongly believe that it's important to respect that proper testing legitimately imposes some needs. You aren't gonna need to offer 3 different implementation of algorithm X. But if you're unit testing, you ARE gonna need to test that the things that use X are using it properly, without having to jump through hoops to set up scenarios that will play nice with the real X. You aren't gonna need to support 3 alternative notification mechanisms. But you ARE gonna need to test the things that call those mechanisms, so that you can run your test suite without firing off emails to everyone.

Doing TDD and test-first development really helps to draw a clear and well-defined boundary between which abstractions are "because in the future we'll need X", and which are "because I need to reliably and reproducibly test Y right now."

Nate Schneider said...

Completely agreed