In one of my previous posts – YAGNI is king – I advocated the idea of not anticipating future when it comes to developing features.
I got some feedback that I want to discuss: YAGNI applies to features, not design. When designing software, you have to anticipate the future. Therefore, sometimes you have to give up on YAGNI if you want a good design.
In other words: on a pull request, when you see an extra piece of code, don’t automatically assume it violates YAGNI. Maybe it’s for design purposes.
I take the point, but also have to add something on my defense.
I understand that good design requires some degree of anticipation.
However, my concern has always been that developers overvalue this design phase and how much we can predict. There are two points I want to add to support my feeling:
- Simple Design undermines “just-in-case design”
- There isn’t a clear boundary between a feature and a design
Simple Design undermines “just-in-case design”
There’s the notion of Simple Design from Agile. I think Simple Design and YAGNI go together.
The main point of Simple Design is that design is an ongoing process. Code simplicity indicates whether or not the design is good or bad. It’s because with simple code comes simple design, and both encourage developers to upgrade the design when needed.
Historically, there was a long design phase before starting developing. Nowadays, with agile, we don’t want that. OK, there is space for some up-front designing phase at the beginning of development. But first, it should be relatively quick, and second, after that, developers should correct design on a regular basis.
There’s no space for:
- a big up-front designing phase that produces the perfect design that everybody expects to never change. There are simply too many unknowns at the beginning. It pretty much feels like “designing just in case”.
- not correcting the design as a constant process. Software design should evolve just like the software itself evolves. Developers who shirk upgrading design have no control over the codebase and/or don’t want to take responsibility for changes.
To me, Simple Design pretty much undermines the idea of “just-in-case designing”.
What’s a feature and what’s a design?
I don’t think there’s a clear answer to that question.
I only have a feeling that “the design” (or “architecture”) means something higher-level in comparison to”the feature”. Maybe “the design” is a bunch of design patterns in your Rails app (say, MVC with Service Objects using Strategy). The design, as such, doesn’t give the user any feature. It only allows for easier adding features like making orders, reading orders, changing address, etc.
But if you draw a class diagram, it there some kind of boundary that says “above me it’s design, below me it’s feature”?
There are multiple ways to write Service Objects in Rails. Designing your Service Objects feels to me like the design too.
Service Objects calls some adapters, procedures, and whatnot. Are those the part of the design too? I would say so.
The way you write your classes and methods is the design too. It’s important how they communicate, how easily they allow for adding features etc. The way how it’s written has little to do with the feature. More likely, it’s how we want to shape it for future maintainers. It applies to every class and every method.
My point is that design covers all the code from top to bottom.
This about this way. If you follow clean code principles, TDD, “make it work – make it well – make it fast”, or similar, you probably first write simple code that does the job and later clean it up. In these patterns cleanup code is an inherent part of the implementation.
“Cleaning up” phase has no limits when it comes to code hierarchy. If you find out that after writing your feature your app no longer fits Service Objects pattern, you should change it.
Writing features requires changing design and design goes all the way bottom. The design should support adding features. The design shouldn’t be your “ball and chain”.
At the end of the day, both design and features come down to the code. I don’t see the point of saying “Hey, I’ve written tons of unnecessary code because you know, design“. This is still speculation. This will make your life harder more often than not.
The bottom line is:
- it could be hard to tell feature from design
- even if we’re talking design, YAGNI should be obeyed – see Simple Desing
To embed my words in somebody else’s opinion, I’ll leave you with the conclusion of Martin Fowler’s post about YAGNI:
Having said all this, there are times when applying yagni does cause a problem, and you are faced with an expensive change when an earlier change would have been much cheaper. The tricky thing here is that these cases are hard to spot in advance, and much easier to remember than the cases where yagni saved effort . My sense is that yagni-failures are relatively rare and their costs are easily outweighed by when yagni succeeds.