Dale said:
That's where I disagree. I've argued before with someone claimed that
according to YAGNI you would never create an interface until you have
two classes that would implement the interface. I disagree strongly with
that notion.
YAGHI (You Aint Gonna Need It) and DTSTTCPW
(DoTheSimplestThingThatCouldpossiblyWork) are XP concepts more than TDD
ones. Its just that the majority of TDDers tend to be Agile (XP, Scrum,
etc) Developers also and so naturally favour them.
I actually disagree with YAGNI or more particularly with this
overstatement of it.
From a previous discussion I had on the subject:
YAGNI flies in the face of sound engineering judgment. The real problem
is that it is a statement not a question. Good engineering is about
balancing trade offs and cost benefit analysis. Do you really want an
engineer on a safety critical device designing by proclamations like
"You aren't going to need it"?
To me YAGNI should be replaced with a series of questions:
- How likely is it that you are ever gonna need it?
- How likely is it that someone else is gonna need it?
- How much will it cost to wait until someone does need it?
- How much does it cost to go ahead and do it now?
- How much will it cost if someone does need it, they don't have it, and
they have to work around the fact that it isn't there?
- Is the design better (e.g. better encapsulation, tighter coupling,
lower cohesion, more flexible) if I add it even if I don't need it yet?
You can't necessarily know the future with absolute certainty, but you
can make reasonable predictions and weigh the probabilities and the
costs and benefits. YAGNI assumes that there is no probability that any
one will need it and the costs of adding it now versus later are
constant. Neither of these are universally true.
It is quite often the case that you can say with high probability it
will be needed and it is almost always the case that it is much cheaper
to add something in the beginning than to add it later.
YAGNI does not mean 'turn off your brain and ignore all of the skills
you have learned'
It merely means, 'think about these cases, keep them in mind when
designing, but unless you need them 'AT THIS VERY MOMENT', dont
implement them.
You might well need them 5 minutes later, next month, quarter or year,
but AT THIS VERY MOMENT you dont, so dont worry too much. You might need
later but for now you dont, so its better business value to concentrate
on the things that you need now.
That being said, its not a license for being dumb or lazy and making
stupid design choices - see the end of this email for an account of when
it did happen on one of my previous teams.
When you start talking about public API's that are exposed to other
programmers outside of your control then the cost of adding something
later is extremely high and you really have to try to predict how it is
going to be used.
I'm not advocating over-designing systems, just using good, engineering
judgment instead of using over-simplistic platitudes like YAGNI.
So there are many good reasons for using interfaces even if you don't
have a bona fide "need" yet.
Public or rather Published APIs are different to non-public APIs and I'd
agree with you, that you'd want to make sure you use Interfaces from the
start.
In fact with published APIs I'd make sure I only ever have Interfaces,
there would be no Classes (concrete or abstract). As good design
experience has shown that classes in published APIs cause more trouble
for the client than benefit.
But then again, YAGNI isn't violated here. You DO need an API now, and
your design choice should be the most appropriate for what you need to
do now, which in this case means testing and creating an Interface.
You deliberately start out with a Failing testcase that makes use of the
Interface and not the class thats implementing it.
This also does not violate DTSTTCPW for the same reasons.
Again, these ideas are not about ignoring sound engineering principles
that we have learned, its about learning to apply them When They Are
Truly Needed.
I can't say with any certainty in this hypothetical example, but I could
reasonably see constraints that would lead you to create the interface
first.
yeah its a simple example.
But my actual point was that the need to create the interface did not
come from the creation of the implementation, but from the caller of the
implementation and its tests.
This can happen. It'll happen alot when you have a any reasonable sized
code base. TDDing tends to introduce interfaces very quickly as they
provide means of injecting or inverting dependencies, which makes
testing SO MUCH MORE easier!
The upside of Easy To Test Code, is that it naturally is highly
decoupled and cohesive. This stems from the fact that every class has at
least two clients :
1) The testcases
2) The other classes/interfaces within the system.
Without testing, its easy to create classes within an overall well
designed system, that still have high couplings and low cohesiveness.,
simply because we may not see a need for breaking these at that time.
Where as TDD creates that need straight away.
That being said, anyone saying that TDD will prevent these is barking
mad and a liar!
TDD doesn't prevent anything. Its a design methodology.
And like any design methodology can be used to create crap, awful
tangled messes if applied wrongly.
The same goes for YAGNI and DTSTTCPW being applied blindly and naively.
In a previous job, two experienced developers who were pair programming
no less! Decided for some reason (probably laziness rather than
stupidity, but who knows) to create a Singleton instead of just Creating
One instance of a class.
The reason they gave was both....
DTSTTCPW
For them, this gave them license to sprinkle the GUI code base with
invocations of the static method 'getInstance()' to gain access to the
singleton. This was 'easier' than changing the design so that an
instance of the class could be passed around or obtained as would have
been a more appropriate design.
YAGNI
'Whilst we NEED to have multiple instances next month, TODAY we only
need one instance so lets create a Singleton!!'.
They effectively ignored the sound design experience they both have in
favour of an easy life, for that day.
Needless to say, the rest of the team wasn't impressed!
And it was yours truly that then had to spend 2 days changing and
refactoring the code in order to remove the singleton. Mind you, this
wasn't all bad as it allowed me to show the team how to actually apply
refactoring in small steps to change a large design.
I hope this clears some of the picture of what YAGNI and DTSTTCPW
actually mean, but feel free to fire more questions about them if not.
Regards
Andrew