In this blog, Martin Fowler discusses the concept of YAGNI or “You Aren’t Gonna Need It”, which is a minimalist approach to handling software design and build. In short, his advice is to identify and eliminate presumptive features in order to improve your code. I agree – there is a measurable immediate benefit to avoiding the distraction of implementing something you don’t need right now, but I don’t fully agree.
Fowler softens his tone a bit when he says, “This doesn't mean to forego all abstractions, but it does mean any abstraction that makes it harder to understand the code for current requirements is presumed guilty.” And honestly, that’s common sense. You should always avoid writing code that is hard to read whether or not it has to do with the abstraction. I personally hate abstractions that go too deep and have my typical limit at 3 which is about where you start making leaky abstractions. For example, in DotPdf, rather than using a typical parser, I use a full RPN interpreter to execute PDF content. In implementing the RPN interpreter, I put in the notion of procsets. A procset is a collection of bindings from symbolic name to code that does the work. This abstraction was not strictly necessary and I could’ve built the RPN machine faster by tailoring it to my task at hand, but this is a useful abstraction and 8 years after I implemented it, it was used as a cornerstone for the code that can handle recovering from a damaged PDF cross reference table, a change that was enabled by a malleable procset.
Fowler also softens further by saying “Yagni only applies to capabilities built into the software to support a presumptive feature, it does not apply to effort to make the software easier to modify.” And here is a gray area that is wider than the Panama Canal (which is OK, as far as I’m concerned). I think the trick is when doing a design to know when to stop. Again, in DotPdf, there is a method for the future:
private void ReduceContentStreams(PdfGeneratedPage page, Stream stm, MLPdfDocument mldoc, MLPdfPage mlpage)
// ultimately, this area is code to run an engine that will rip the content streams and turn them into
// shapes and reduce the shapes to more complicated shapes overall.
And when I wrote this, we didn’t have this particular feature in our plan and this particular feature is probably several months of my time to do, but rather than take the time to stub out the design and create the structure for it, I just put the marker in the ground and walked away.
Minimalist design is OK, but it should be a guiding hand, rather than the goal. Experience with customer needs, especially when writing a library like DotImage and DotPdf, is necessary in making the decision for YAGNI. When looking at DotPdf, there is a class called PdfDocument that has a very simple external model: it is a class that contains a collection of abstract pages. Client code manipulates those pages (shuffle, remove, copy, add from other docs, etc.), then client code calls the Save method. When I rounded out the design, I chose to add two static methods: Separate and Combine. These methods, strictly speaking, aren’t necessary as they can be and are implemented in terms of PdfDocument. YAGNI would say that I should have left these out, but these two operations are so common that I put them in to prevent a kind of distributed DRY wherein all my customers have to implement the same code and worse than distributed DRY, my customers have correct code to do those tasks. Oddly enough, I had a prospective customer this week who called in this week asking if they could take a single PDF document, split the pages out for recombining later.
So what is my goal if it’s not YAGNI and not minimal design? My goal is to create toolsets that provide most of my customers the ability to solve their problems right out of the box and allow the remaining customers to jiggle tools the solve most of their problems. The remaining tiny proportion of customers, we will listen to and decide if what they’re asking for is in line or orthogonal to our product roadmap. If it’s the former, it becomes a feature. If it’s the latter, it becomes an apology. My former co-worker, Rick Minerich also described it that way. For an example of that, which included a fair amount of judicious YAGNI as well as some ORLY, see my article about how I went from a customer feature request to a completed feature set.
I feel that writing software is like a growing tree. Good design makes sure that there is plenty of room for logical, beautiful branches to grow. YAGNI is the guiding hand behind a set of pruning shears to cut off the branches early that would interfere with that growth. One of my favorite misquotes is Emerson’s “consistency is the hobgoblin of little minds.” The full quote is “A foolish consistency is the hobgoblin of little minds, adored by little statesmen and philosophers and divines.” (emphasis mine). And that YAGNI is something that should not be applied in a foolishly consistent manner.
About the AuthorFollow on Twitter More Content by Steve Hawley