[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

BDD and TDD - What are they for?

Clinton D. Judy

8/15/2008 8:10:00 PM

I'd like someone to give me very basic reasons for why I need Behavior
Driven Development (BDD, see RSpec) and/or Test Driven Development (TDD,
See Test::Unit).

=20

I'm a fairly competent programmer. I think I use what they call an
"iterative" style of programming; I don't rush out to build the entire
program at once. I do a very small framework, then attempt to run it and
see if it's giving me the result I expect. If it's not, then I figure
out what's going wrong, and attempt to solve it before going on to the
next small part. You could say I do several iterations in an hour, to
give an idea of time.

=20

It looks like TDD does exactly what I'm doing, but introduces far more
code to the equation. One of the biggest features of TDD is being able
to run a suite of tests to make sure new features don't break old
features. Yet I have an eye for this while developing; I either fix the
upcoming problem because I know it's going to happen, or I'm doing it
wrong in the first place. Sure, I occasionally miss, but who doesn't? I
find the issue as quickly as I can and resolve it in a clean style.

=20

BDD looks like a way to make it easy for non-programmers to do
programming, but not having people keep several functions in mind at any
one time. And it also does TDD? Am I close?

=20

But everyone continually praises TDD and BDD, which leads me to believe
I'm missing something profound that could make me a better programmer.
So what's the big deal?

=20

Clinton Judy

Web Developer

Glenn O. Hawbaker, Inc.

=20


41 Answers

Avdi Grimm

8/15/2008 8:32:00 PM

0

On Fri, Aug 15, 2008 at 4:10 PM, Clinton D. Judy <cdj@goh-inc.com> wrote:
> BDD looks like a way to make it easy for non-programmers to do
> programming, but not having people keep several functions in mind at any
> one time. And it also does TDD? Am I close?

BDD is simply an altered vocabulary for TDD. Vocabulary is important;
it effects how you think about a problem and how you decompose it.
For a lot of people, including myself, thinking about things in terms
of specifications of behavior rather than in terms of "how do I test
this method" leads to better-designed code.

What's the deal? Like pair programming, BDD/TDD is one of those
things you have to try to get. If you can, find someone who is a pro
at it and do some TDD coding together. At some point it will "click".

For me it was when I spent several weeks coding C++ by myself with
nothing but the spec for a communications protocol, and the very first
time we integrated my library into the main product it worked out of
the box. That kind of integration experience was unheard-of where I
used to work. I was hooked from then on, and I've never gone back.
Most of the TDDers I know have their own similar conversion story.

I find that when I'm writing code test/spec-first, I don't have to
worry about debugging. The code is usually right the first time, and
when it isn't the problem is obvious. It also forces me to write code
that is properly decoupled and obeys the single responsibility
principle, making changes much easier.

It sounds like you are doing most of your coding alone, on projects
that you can pretty much hold in your head at the one time, and on
which you can manually test without much trouble. When you start to
work on projects that haved tens or hundreds of thousands of lines of
code, have had many developers, some of whom are long gone, and which
could take days to manually test, the benefits of complete test/spec
coverage become impossible to ignore. And the only way to guarantee
complete coverage is to write the tests first.

But really, the only way to discover the joys of BDD/TDD is to do it
for a while.

--
Avdi

Home: http:...
Developer Blog: http:.../devblog/
Twitter: http://twitte...
Journal: http://avdi.livej...

brabuhr

8/15/2008 8:33:00 PM

0

On Fri, Aug 15, 2008 at 4:10 PM, Clinton D. Judy <cdj@goh-inc.com> wrote:
> I'd like someone to give me very basic reasons for why I need Behavior
> Driven Development (BDD, see RSpec) and/or Test Driven Development (TDD,
> See Test::Unit).
>
> I'm a fairly competent programmer. I think I use what they call an
> "iterative" style of programming; I don't rush out to build the entire
> program at once. I do a very small framework, then attempt to run it and
> see if it's giving me the result I expect. If it's not, then I figure
> out what's going wrong, and attempt to solve it before going on to the
> next small part. You could say I do several iterations in an hour, to
> give an idea of time.

I pulled this link off the TDD page on our internal wiki here at work:

http://www.railsenvy.com/2007/10/4/how-i-learned-to-love-testing-pr...

Shadowfirebird

8/15/2008 8:36:00 PM

0

I see your point. I'm struggling with TDD concepts myself. But I
think you answered your own question when you said:

> Sure, I occasionally miss, but who doesn't?

Test programs don't. That thing they tested last week that you forgot
about? They remembered.

I agree that the overhead is extra development time. And I'm sure
test scripts are not infallible -- for example, if you change
functionality in the program but not in the test.

Also, I've said this before here, but as a commercial programmer I've
spent years telling people that the code can't tell you what the
program is *supposed* to do; only what it *does*. Test scripts tell
you what the code is supposed to do. That's pretty cool.

Avdi Grimm

8/15/2008 8:49:00 PM

0

On Fri, Aug 15, 2008 at 4:35 PM, Shadowfirebird
<shadowfirebird@gmail.com> wrote:
> I agree that the overhead is extra development time.

After doing TDD/BDD for, oh, five years or so, I'm convinced that the
"it takes longer" argument is a red herring. It may be true when
you're first learning TDD and it takes you awhile to work out how to
properly test something. But I've found that once I internalized
testing my coding velocity actually *increased*. And more
importantly, it became much steadier. Non-TDD projects are often
marked by a very fast initial ramp-up, then velocity starts to
decline, and then eventually they hit a wall where every change seems
to take 2-5 times as long as it should because of all the unintended
consequences. TDD projects, by contrast, retain about the same speed
from start to finish. Write test; watch test fail; make test pass;
refactor; repeat - it's a rhythm that stays constant no matter how
large the codebase.

I've also found that for me, personally, TDD reduces my initial
startup time. In the past I used to spend a lot of time trying to
dream up the "right" object model to fit the project, and I'd have a
hard time actually figuring out where to dig in and start coding. And
then when I did dig in for awhile, it would suddenly occur to me that
I'd failed to account for something basic and I'd realize I needed to
re-tool my design. And of course the subsequent refactoring would be
prone to breakage because I had no regression tests.

When I'm doing TDD, all I have to think about to get started is the
simplest possible unit of concrete, testable functionality. I make
that work the simplest possible way, and then move on to the next
simplest case. As soon as I find myself duplicating code I refactor.
Out of this rhythm the "right" design emerges, a piece at a time - as
it is needed. And there's no wasted time at the beginning trying to
figure out how to architect for the future.

Which is all to say why I find any project over, say, a hundred lines
of code actually goes *slower* without TDD/BDD.

--
Avdi

Home: http:...
Developer Blog: http:.../devblog/
Twitter: http://twitte...
Journal: http://avdi.livej...

Phlip

8/15/2008 9:14:00 PM

0

Clinton D. Judy wrote:

> I'd like someone to give me very basic reasons for why I need Behavior
> Driven Development (BDD, see RSpec) and/or Test Driven Development (TDD,
> See Test::Unit).

Shine the "Phlip" symbol on the underside of the nearest cloud deck!

> I'm a fairly competent programmer. I think I use what they call an
> "iterative" style of programming; I don't rush out to build the entire
> program at once. I do a very small framework, then attempt to run it and
> see if it's giving me the result I expect. If it's not, then I figure
> out what's going wrong, and attempt to solve it before going on to the
> next small part. You could say I do several iterations in an hour, to
> give an idea of time.

When you say "attempt to run it", you should be mixing manual testing with
running unit tests. They give a second opinion.

However, they are permanent. Imagine if you put a "mini-me" in a bottle, who
came out and manually tested, instantly, each time you changed the code. Imagine
if it would warn if nearly any behavior changed since the last run.

You could go faster - making bigger changes - with less manual testing.

> It looks like TDD does exactly what I'm doing, but introduces far more
> code to the equation.

Yet that code should be super-easy to write. A TDD test should obey the Assemble
Activate Assert pattern:

def test_case
foo = assemble_foo()
result = foo.activate()
assert{ result == 42 }
end

Compared to production code, that test code looks super-easy to write. Tip: The
easier a test is to write, the cleaner and more decoupled your code is. So,
counter-intuitively, the more lazy you get writing tests, the more pressure
forces your code to decouple.

To do TDD, you write the test case first, then write code to pass the test. You
only write new code if you have a failing test case. So your code is decoupled
before it is even written.

> One of the biggest features of TDD is being able
> to run a suite of tests to make sure new features don't break old
> features. Yet I have an eye for this while developing; I either fix the
> upcoming problem because I know it's going to happen, or I'm doing it
> wrong in the first place. Sure, I occasionally miss, but who doesn't? I
> find the issue as quickly as I can and resolve it in a clean style.

You should run a TDD test suite after the fewest possible edits: 10 at the most,
and hopefully just 1. A coding session should go type-type Test, type-type Test,
type-type Test, in tiny cycles.

If you delay to run the test, the more risk you absorb with your edits.

This helps sustain projects as they get huge; the code stays just as easy to
work with as a tiny project. Nobody can cross-check everything in a huge program.

> BDD looks like a way to make it easy for non-programmers to do
> programming, but not having people keep several functions in mind at any
> one time. And it also does TDD? Am I close?

Yes - BDD is TDD with an added layer: A "literate programming" framework that
forces you to think in clear English* statements that your client could understand.

*or whatever your client speaks!

That anyone can do TDD with BDD (and they do) speaks volumes about Ruby's
ability to support easy and flexible DSLs.

> But everyone continually praises TDD and BDD, which leads me to believe
> I'm missing something profound that could make me a better programmer.
> So what's the big deal?

The big deals are: Almost no debugging, a super-high velocity, the ability to
deploy any integration, the ability to rapidly share code with colleagues, code
that strongly resists new bugs, and the ability to allow your client to "steer"
your project, feature-by-feature, in real-time.

If your tests fail unexpectedly, the fault must lie in your last edit. You can
undo or revert it. If your tests gate your Subversion or Gitorious version
controller, then you know that you can always revert your code to get rid of a
test failure. Working in tiny cycles, and constantly integrating your code,
allows you to take bigger steps with more confidence.

Debugging is the greatest time-waster in all programming. Grizzled senior
programmers (like some of my friends!) can all remember working on projects with
bugs so big, you could spend the first week just isolating which module
contained the bug. With debugging out of the way, you spend your remaining time
understanding requirements, implementing them, integrating them, and deploying
them. Your project goes very fast as your client learns to request very small
features, each an increment over the existing features. Very few features go to
waste. And a project with a complete test rig cannot lose its value over time.
New code is often easier to write than old code, even despite projects with
thousands of features. This metric is unheard of in software engineering, where
new features are typically harder to write than the first ones.

If your tests gate your integrations, than you could deploy any integration. It
might have unfinished features (and you might make their View buttons
invisible!), but the tests will tell you it has no bugs. This metric is also
unheard-of in classical programming, where a project typically must endure a
"polish phase", as much as 25% of development time, to get it "ready to ship".

Next, if I need my colleagues to be able to mess with code I wrote (and vice
versa), then I don't need them breaking it because they didn't understand it
(what are the odds?:). If they run my tests (and they do!), then there's a
little bit of me in them, working with them, keeping my features stable while
they add theirs.

The TDD cycle has three steps: Write a test that fails for the correct reason,
write simple code that passes the test, and refactor your code to make it clean
and dry. Notice you don't refactor until the code passes its test. Refactoring
means merging the new code with the preexisting code. And you don't refactor
until your tests say the new code works. This implies only good code with valid
features gets merged together. TDD's influence on design cannot be understated:
It produces rock-solid code that strongly resists bugs.

Under classic software development, you would ask your client for a long list of
features, then ask to be left alone for a while! Under TDD, your new features
can be reviewed _as_ they emerge. Your client has better odds of getting the
features they want if they practice "just in time requirements". They only
require features in small increments from those installed features which they
like. TDD allows a business cycle as short as a week to add features, review the
code, and request for features. This improves the odds your client gets the
features they need - not just some of the features they ask for. Your client no
longer has the burden of predicting the future and planning every feature they
might need.

The Ruby on Rails project has copious unit tests; its success is an example of
these forces at work...

--
Phlip

David Masover

8/16/2008 2:00:00 AM

0

On Friday 15 August 2008 15:10:26 Clinton D. Judy wrote:
> I'd like someone to give me very basic reasons for why I need Behavior
> Driven Development (BDD, see RSpec) and/or Test Driven Development (TDD,
> See Test::Unit).

BDD is a philosophy and a vocabulary for talking about TDD. They are not
mechanically different -- a good TDD suite should support BDD, and vice
versa. But they do introduce a few new ways of thinking about the problem.

> I do a very small framework, then attempt to run it and
> see if it's giving me the result I expect. If it's not, then I figure
> out what's going wrong, and attempt to solve it before going on to the
> next small part.

That's good. Question: How do you know when it's giving you the result you
expect?

BDD adds an extra step: You write down the result you expect, in code form, as
tests. You then write your framework, pretty much as you've described, until
the test passes.

There are two direct benefits to this approach: First, you know when you're
done. If it passes a test and you don't think it's done, write down _why_ you
don't think it's done -- again, as a test.

In other words, it prevents you from writing a ton of unnecessary code.

The second benefit is that, coding this way, you accumulate some small measure
of documentation: By reading your tests (which BDD calls "specs"), it's
possible for someone to get an idea of what your code is supposed to do.

> It looks like TDD does exactly what I'm doing, but introduces far more
> code to the equation.

Correct. I won't sugarcoat it -- when I'm doing proper BDD/TDD, I will
sometimes have twice as much code in tests as I do in the actual program.

> One of the biggest features of TDD is being able
> to run a suite of tests to make sure new features don't break old
> features.

Not just new features, but any code change. It means that you can do a massive
internal refactoring, or even replace one library (or program) with another,
and have some assurance that things still work exactly the way they're
supposed to.

A simple example: Web browsers. Having the spec, in written form, wasn't good
enough. That's why we have the Acid2 and Acid3 tests -- now we can know which
browsers have properly implemented the specs, and to what extent. It also
provides something for browser developers to work towards.

> Yet I have an eye for this while developing; I either fix the
> upcoming problem because I know it's going to happen, or I'm doing it
> wrong in the first place.

The problem is, you know your own code very, very well right now.

Will you know this code that well in five years? Will you be able to change
any part of it without fear that you will break something?

And, perhaps more importantly, will a total stranger be able to sit down and
do the same?

> Sure, I occasionally miss, but who doesn't?

Your test suite.

> BDD looks like a way to make it easy for non-programmers to do
> programming, but not having people keep several functions in mind at any
> one time.

It's not about keeping several functions in your mind.

It's about keeping the entire program in your mind at once.


But the mention of non-programmers does bring to mind another benefit, and one
which I rarely see implemented: Stories. A story is a way to express, in
plain text, how a program should behave, from the user's point of view.
Ideally, a customer could write stories by themselves.

Realistically, you would probably write the stories with the customer -- they
do read like plain English, so the customer can understand them, but they
need to be somewhat stricter, so that you can more easily use them to write
tests later.

Given a story, and a bit of translation, you can define your eventual target
behavior, exactly the way the customer (or your boss) wants. Converted to
integration tests, you have feedback as to when you're done -- when it does
exactly what the customer wants.



I'm still not fluent enough at writing tests that I can actually start with a
clean project and test first. I still usually end up doing an evening or a
weekend worth of code before I have enough of a program in place that I can
properly reason about what my tests would look like -- what I actually expect
from this program.

But I'm not sure yet whether this is a deficiency in BDD or in my own line of
thought. And I do find that after a week or so of development, the program
has gotten to a point where I need tests -- or at least, where I'm doing so
much testing manually that it's a pain.

Simple example: I'm writing a program which spiders a certain website, scrapes
some useful information out of the HTML, and dumps it into a database. I've
been building it incrementally, as you've described, but every time I want to
make sure something works, I have to start with a fresh database, open up an
irb console, and have it download the same page. I then have to browse
through the database records, making sure they match what I'm expecting.

I'm about to convert this process to a test suite -- some pre-downloaded HTML,
so I'm not hitting the site every time, and a test to cover this behavior, so
that I don't have to keep browsing through records.

Phlip

8/16/2008 2:27:00 AM

0

David Masover wrote:

> BDD is a philosophy and a vocabulary for talking about TDD. They are not
> mechanically different -- a good TDD suite should support BDD, and vice
> versa. But they do introduce a few new ways of thinking about the problem.

BDD is "customer facing". It's _supposed_ to be about writing the tests in terms
a civilian client could understand and agree on.

> It's not about keeping several functions in your mind.
>
> It's about keeping the entire program in your mind at once.

And it's about keeping the entire program out of your mind all at once. It's
about making changes while looking at a huge application like a map thru a soda
straw. I want to make one little change, in one corner, without worrying that I
will derail some other far-flung part of the app. Its tests will defend it.

Good stuff snipped!

--
Phlip

David A. Black

8/16/2008 11:51:00 AM

0

Hi --

On Sat, 16 Aug 2008, Phlip wrote:

> Clinton D. Judy wrote:
>
>> BDD looks like a way to make it easy for non-programmers to do
>> programming, but not having people keep several functions in mind at any
>> one time. And it also does TDD? Am I close?
>
> Yes - BDD is TDD with an added layer: A "literate programming" framework that
> forces you to think in clear English* statements that your client could
> understand.

I wouldn't call it literate programming in the Knuthian sense, though.
Knuth says: "The practitioner of literate programming can be regarded
as an essayist, whose main concern is with exposition and excellence
of style."[1] It's a different undertaking from writing BDD
specifications (even though of course it's nice if BDD specifications
are reasonably well-written).


David

[1] http://www.literateprogra...
--
Rails training from David A. Black and Ruby Power and Light:
* Advancing With Rails August 18-21 Edison, NJ
* Co-taught by D.A. Black and Erik Kastner
See http://www.r... for details and updates!

David A. Black

8/16/2008 12:02:00 PM

0

Hi --

On Sat, 16 Aug 2008, Clinton D. Judy wrote:

> BDD looks like a way to make it easy for non-programmers to do
> programming, but not having people keep several functions in mind at any
> one time. And it also does TDD? Am I close?

I wouldn't say that it makes it easy for non-programmers to program.
At its best, it can provide output and summaries that non-programmers
can easily read, understand, and amend. But the programming part of
BDD is truly programming.

This is actually at the root of why a lot of people, including me,
find it hard to bond with RSpec. In some respects, the syntax tries to
look and read like English, but it's still 100% programming and there
are serious impedance mismatches between English and Ruby. But RSpec
generates summaries that are purely in English, and that describe the
program's requirements in such a way that any stakeholder in the
project, programmer or not, can read them. I would not expect a
non-programmer to be able to read RSpec code.

You should, however, check out RSpec if you're interested in BDD. It
represents a fantastic achievement (my problems with it are at the
level of my own stylistic preferences), and has a huge following.

> But everyone continually praises TDD and BDD, which leads me to believe
> I'm missing something profound that could make me a better programmer.
> So what's the big deal?

It scales. If you're doing something small, you can run it and eyeball
the results and that's fine (and that is, in fact, a test). Like
everything else in programming, though -- calculations, data munging,
administrative tasks -- testing your code benefits from being
automated when you have to do more than a miniscule amount of it. It's
really that simple, and everything else proceeds from that.


David

--
Rails training from David A. Black and Ruby Power and Light:
* Advancing With Rails August 18-21 Edison, NJ
* Co-taught by D.A. Black and Erik Kastner
See http://www.r... for details and updates!

Eleanor McHugh

8/16/2008 1:54:00 PM

0

On 16 Aug 2008, at 12:51, David A. Black wrote:
> On Sat, 16 Aug 2008, Phlip wrote:
>> Clinton D. Judy wrote:
>>
>>> BDD looks like a way to make it easy for non-programmers to do
>>> programming, but not having people keep several functions in mind
>>> at any
>>> one time. And it also does TDD? Am I close?
>>
>> Yes - BDD is TDD with an added layer: A "literate programming"
>> framework that forces you to think in clear English* statements
>> that your client could understand.
>
> I wouldn't call it literate programming in the Knuthian sense, though.
> Knuth says: "The practitioner of literate programming can be regarded
> as an essayist, whose main concern is with exposition and excellence
> of style."[1] It's a different undertaking from writing BDD
> specifications (even though of course it's nice if BDD specifications
> are reasonably well-written).

Many programmers believe they're bad at writing essays, and rather
seeing an opportunity to improve their skills they would rather write
tests. But tests are only as good as the analysis which goes into them
and can very quickly become redundant when working on greenfield
projects with very loose requirements. They're also as prone to error
as any other code so beyond a certain level of complexity it's not
entirely obvious that they improve code quality rather than hindering
it.

That said, everyone seems to love them so they must have some value.


Ellie

Eleanor McHugh
Games With Brains
http://slides.games-with-...
----
raise ArgumentError unless @reality.responds_to? :reason