
Yagni (2015) - mooreds
https://martinfowler.com/bliki/Yagni.html
======
nvarsj
Like any generalization, it's not always true.

Boss decides to add y,x,z options "just in case"? - YAGNI

Engineer wants to get the datamodel correct up front to avoid costly rework
and data migration in the future? - Not YAGNI

Fowler fortunately states this distinction: "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."

~~~
Silhouette
That's a bit of a cop-out, though. How much software development _isn 't_
either implementing the actual features or making the software easier to
modify?

This one is a bit like the TDD advocacy that says you shouldn't need to do
much design work up-front because you can let the tests drive the design along
with everything else.*

*Except for the part where you refactor your code, which by definition shouldn't be changing its behaviour and therefore can't be driven by adding tests to your test suite, where exactly the same design issues will immediately arise.

~~~
plasticchris
I always thought tests were supposed to make refactoring easy since they
ensure correctness. In practice I've only seen that a couple of times since
the tests usually end up tightly coupled to the implementation.

~~~
hinkley
It's easy for tests to pick up structural artifacts from the code, creating
friction for making changes instead of reducing it.

At the end of the day it's a matter of the quality of the tests. Bad tests can
be worse than none (because at least you know to be afraid).

------
bastawhiz
The problem I've seen when yagni is applied is _not_ building something now
leads to a costly data migration down the road when you actually do need it.

I run a site that stores audio files. For the first half of its life, it
simply stored the URL of the file on S3. I could have used objects
representing audio assets with metadata to store the reference, but I didn't
think I'd need it. When I was building another feature that _did_ need that
functionality, the migration took far longer to write, test, and run than the
process of building the asset objects feature and the feature I needed them
for combined.

Additionally, the new system made it easier to debug customer issues. I didn't
know that I actually needed this feature the whole time.

~~~
kstenerud
The only exceptions are APIs and data serialization/storage. Your cost of
change on these are huge, so better to eat some extra cost now to future
proof.

~~~
mmt
I'm pretty sure the original rule recognizes no exceptions, and certainly not
on something so broad as an entire category. It may be that much narrower
exceptions could exist, but future-proofing sounds like it could simply be
justified as a feature actually needed now, if not just good overall coding
practice [1].

The danger of allowing such a broad exception is that it doesn't take a huge
leap to imagine a situation where it's used as permission to do something like
a custom implementation of ACID in the app backed by a NoSQL key-value store
(or "sharded" MySQL, before NoSQL was a thing).

[1] YAGNI isn't a standalone rule but one of many in the "XP" collection. Any
one of them, out of context, in complete isolation, could just as (if not
more) easily require a long list of caveats/exceptions to make sense in the
general case.

------
OliverJones
Yup. There's also the cost of inventory -- of software costs tied up in
feattures that are not (yet) useful. Check out this article by Joel Spolsky.
[https://www.joelonsoftware.com/2012/07/09/software-
inventory...](https://www.joelonsoftware.com/2012/07/09/software-inventory/)

~~~
jeffreybezos
Excellent article, particularly about triaging bugs, too.

------
wsy
YAGNI is a sad example of the state of software engineering: our field follows
rules of thumb, based on anecdotes as evidence. When will experimental
validation become best practice, like in the other engineering disciplines?

~~~
ternaryoperator
There is a whole field of study--what was originally called software
engineering--that does quantitative, empirical analysis of software
development. Its practitioners are often called by managers entering into
large projects that have tight quality requirements so that the optimal
choices can be made in terms of tooling and techniques. (For example, large-
scale automotive software, where there is far less tolerance for error than in
IT.)

~~~
wsy
Do you have some pointers to important papers of this field of study?

~~~
ternaryoperator
[1] Article from Dr. Dobb's gives a very high-level overview of the kind of
data that is available.

[2] is one of the foundational books in this area. Its analysis of testing
effectiveness is fascinating because it's so revealing. For example, comparing
defect rates in projects that use TDD vs. non-TDD; the effectiveness of static
analysis; etc.

[1] [http://www.drdobbs.com/225701139](http://www.drdobbs.com/225701139) [2]
[https://www.amazon.com/dp/0132582201/](https://www.amazon.com/dp/0132582201/)

~~~
wsy
Thanks a lot!

~~~
wsy
After having read a bit, I'm a bit disappointed. While the intent goes in the
direction I would like to see, the actual execution does not follow scientific
principles. "Consultant collects some data, derives conclusions, and writes a
book" is actually again only anecdotal. You need to think about your sample
before collecting the data, otherwise your outcome is biased by who gave you a
consulting gig.

Consequently, the work has never been published as peer-reviewed paper with
experiment and/or real-world data, so that someone else could validate or
reproduce results. Is that assessment correct, or did I overlook scientific
papers?

~~~
andrewbinstock
> the actual execution does not follow scientific principles.

It can't really. The practitioners are generally brought into a project under
heavy non-disclosure and generally allowed to keep stats on the project as
long as it is completely anonymized. This makes it hard to publish data in a
scientific research mode, because it's hard to reproduce or validate
independently.

Most of the time the practitioners are called in (hypothetical example) b/c a
manager says, "I have the requirements for this project, I have 11 developers
on the team, and we need to produce a working model of X by January, which is
sufficiently defect free that we can put it in autos for initial test without
losing a lot of cars." Thresholds are identified. Then the practitioner goes
to his/her database of similar projects and says, "OK, when using these tools,
we found you can get this level of defects on projects of x LOCs within the
time frame you're going for. However, if you forgo Y, you can get higher
levels in 10% less time. Etc." That can be valuable information, rather than
just throwing developers at a project and hoping for the best.

The books that you dismiss as consultants just publishing their anecdotal info
are often the product of hundreds of projects. Sure, the data is empirical,
but it doesn't mean it's not rigorous. You'll note that the numbers in books
and articles are often presented as ranges, which is due to the sensitivity of
one factor to the presence of other factors (size of project being a
particularly prominent factor).

Going to your original point, all established practitioners agree on the
leading causes of defects. And this is where I fault most developers today--
they plain don't know what those are. They'll guess, but they don't know.
Which is what I think I hear you lamenting at the top of this thread.

Disclaimer: I'm not a specialist in this field nor a consultant, but I find
its research interesting and have spoken to practitioners.

~~~
wsy
Thank you for taking the time to explain the background.

I totally agree that consultants working from quantitative data about past
projects are much better than the usual cargo cults.

However, there are a lot of dangers in the process:

\- If you are a consultant in automotive embedded software, you will be
contracted for these projects, so your data will be quite useless to guide
startup Web application development (for example, LOC can make sense for
embedded C, but not for languages like Scala or Haskell, where you can
implement the same feature elegantly in 100 lines or clumsily in 1000).

\- As consultant, you want to generate revenue. So there is a strong incentive
to oversell how solid your insights are. There is no counter-force in place to
balance that bias out.

\- While scientific publication is somewhat broken, it is (in CS) a quite good
quality control with respect to scientific method. The book did not undergo
any quality control by other experts. So now it becomes a matter of personal
trust towards the author.

Summarized, I think that practitioner's data collections and their personal
reports about them are useful in some cases, but cannot replace scientific
empiric research.

------
zmmmmm
> 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. Yagni is only a viable strategy if the code is easy to change, so
> expending effort on refactoring isn't a violation of yagni

This is doesn't concord with my understanding of this term. My YAGNI
encounters are MUCH more often around technical design decisions that will
theoretically make software easier to modify down the track but in practice we
have no idea if the design will look the same by then and hence whether the
benefits will be realised is almost impossible to estimate.

Things like "It would be better if this configuration was stored in a database
table than a text file" or "these modules should be refactored implement the
same interface so they can share code" etc.

------
snapspans
I would argue there is another important benefit than the takeaway suggested
in the second sentence of [1], that is the attention to architecture choices
that allow for simple or complex (costly) refactoring later can engender more
forward-looking awareness in the team's culture.

[1] "One approach I use when mentoring developers in this situation is to ask
them to imagine the refactoring they would have to do later to introduce the
capability when it's needed. Often that thought experiment is enough to
convince them that it won't be significantly more expensive to add it later."

------
keithnz
YAGNI is very useful. But :-

It's mostly useful in a situation where problems that YAGNI was trying to help
with are happening. Namely, when people are trying to ask for anything that is
possibly needed upfront because if you change your mind later it will cost a
lot more to get it. For developers it was to try and get them to think
vertically through software rather than horizontally and to stop designing
large layers of goop instead of focusing on working software which you build
out incrementally which means a HUGE focus on composable modular software.

It's also not a justification by itself. Lisa: "Lets do X" Bart: "YAGNI"

There needs to be a bunch of thought about things and YAGNIs purpose is really
to just challenge what it is that is going to get built.

Most of the criticism of YAGNI is mostly YAGNIing something that was actually
needed, or using YAGNI to compromise a software design. But that's not a fault
of YAGNI, that's either because you let YAGNI hold too much power over your
decision making because you felt its pressure to stop you doing something, or
you just weren't capable at decision making time to work out what you really
needed. YAGNI is just a focusing tool to work out what you are going to need
and it's as strong or as weak as the people making the decisions.

------
InclinedPlane
YAGNI is no excuse to design shitty systems, however. Make your systems as
modular and componentized as is sensible. It'll pay off immediately as well as
down the road when you inevitably need to make modifications. However, it is
wise to avoid adding in too many features that you merely think are a good
idea but don't actually have proof are useful in practice.

One thing to be aware of is that YAGNI can often be the cry of someone who
doesn't want to admit they are accumulating mountains of technical debt. And
it's very possible to go effectively "technically bankrupt". Rewrites are
expensive and take a long time, in order to do them properly it usually
requires launching projects in parallel so that the rewrite can get done while
the old stuff is still keeping the lights on, and so that the rewrite can
attain the same level of operational maturity. You see this even at multi-
billion dollar companies, changing architectures is a difficult process. But
what happens if you are stuck with a mess of bad code and a business that is
only sufficiently profitable to continue supporting the old code but couldn't
afford doing a parallel rewrite? Well, then you could very easily find your
company stuck riding that bad code forever. Given the dynamic nature of tech
businesses, being unable to respond to market changes because you are mired in
technical debt is a huge competitive disadvantage and likely to lead to a much
shorter lifespan for your company.

So be careful making too many short-term decisions. YAGNIs add up and up and
up, you don't want to get to a point where when you do "need it" it's now
effectively impossible (due to requiring an exorbitant budget to implement
it).

------
bgongfu
Everyone likes to pretend they can predict the future for a while, to the
point where they will stop at nothing to make it conform to their predictions.
Then comes the part where they will defend their choices to death, no matter
how much evidence to the contrary is piling up. Once you start seeing the
entire chain of consequences, it becomes easier to discipline yourself; it's a
process of growing up and taking responsibility.

------
postfacto
It’s been my experience that most programmers who have worked on many
different projects across many different employers for many years can intuit
whether something will be needed with a very high degree of accuracy.

------
iris-digital
Previous discussion, with lots of comments:

[https://news.ycombinator.com/item?id=9605733](https://news.ycombinator.com/item?id=9605733)

------
gaius
Take this with a pinch of salt. With consultants it's YAGNI until you _do_
need it, at which point you will be billed at their contingency rate! You
don't need to go full waterfall to understand your requirements up front and
make the choice not to wait until something becomes a showstopper because
"YAGNI and it won't fit into this sprint anyway". Trust your experienced, in-
house engineers for what you are or aren't gonna need.

------
camgunz
I think coherency of implementation is a lot more important than YAGNI. For
example:

    
    
      class Car:
    
          def honk(self):
              print('Honk!')
    

Cool, now we have a car, but it only honks. But we only needed it to honk, so
that's fine.

    
    
      class RoadTrip:
    
          def __init__(self, car, destination):
              self.car = car
    
          def go(self):
              self.car.start()
              self.car.drive_to(destination)
    

Oh no, we built a car but it does nothing that a car does. Let's add this
functionality.

    
    
      class Car:
    
          def __init__(self):
              self.started = False
              self.gps = []
              self.location = cool_app.get_current_location()
    
          def honk(self):
              print('Honk!')
    
          def start(self):
              self.started = True
    
          @property
          def location(self):
              return self.gps[-1]
    
          @location.setter
          def location(self, new_location):
              self.gps.append(location)
    
          def drive_to(self, location):
              self.location = location
    

Super easy. Except a different user of our library implemented this
functionality already for a different reason, but in a different way.

    
    
      class CarEngine:
    
          def __init__(self, car):
              self.car = car
              self.started = False
    
          def start(self):
              if self.started:
                  raise Exception('Already started!')
              self.started = True
    
          def turn_off(self):
              if not self.started:
                  raise Exception('Not started!')
              self.started = False
    
      class CarGasTank(self, car):
    
          def __init__(self, gallons):
              self.car = car
              self.capacity = gallons
              self.level = gallons
    
          @property
          def empty(self):
              return self.level == 0
    
      class MotorCar:
    
          def __init__(self, engine, gas_tank, mpg, location):
              self.engine = engine
              self.gas_tank = gas_tank
              self.location = location
              self.mpg = mpg
    
          @property
          def started(self):
              return self.engine.started
    
          def start(self):
              return self.engine.start()
    
          def drive_to(self, location):
              distance = location - self.location
              fuel_required = distance / self.mpg
              if fuel_required > self.gas_tank.gallons:
                  raise Exception('Not enough gas!')
              self.gas_tank.gallons -= fuel_required
              self.location = location
    

I've lost count of the number of times I've seen stuff like this. Sometimes
the original implementation is in a different library that's hard to change.
Sometimes other code rely on specific details of the original implementation
so changing it requires changing that code too. Sometimes additions seem "out
of scope" so they are actively pushed to dependencies.

It might feel like this is a process problem -- like there should have been
better upfront design or communication -- but these "failure cases" are
actually the success cases for code. You want code to rely on your libraries.
You want to consider all users of your libraries when making changes.

The problem is actually YAGNI, because that mentality encourages us to churn
out big, incoherent bags of functions when we should be thinking about code
responsibilities and designing whole systems.

You can see this in action with JavaScript most infamously. Its standard
library is extremely YAGNI, and it led to whole new programming languages
being built on top of it because it was so anemic. The complexity has to live
somewhere, and if you don't deal with it in a coherent and orthogonal way,
someone else will have to deal with it and their options will be a lot more
limited than yours.

Following simple mantras like DRY, YAGNI, and whatever else fits on a poster
is the surest way to mess up your design. It requires thoughtfulness and
experience, and there are no shortcuts.

