http://www.perlmonks.org?node_id=979293


in reply to Test Driven Development example + design question

I haven't read the book that you read, so might advice might differ a bit from what the book said.

As another disclaimer, Perl is much more expressive than Java, so we can make some APIs simpler, and still have flexibility under the hood.

So, what do you know about the problem? It involves reading of some files, computations, and writing of files. What's the simplest possible API for reading files?

my $data = read_file($filename); # or maybe the reader needs to know the file format too? my $data = read_file($filename, $fileformat);

Maybe you'll object "but that's not object oriented!". So what? Your job is to get stuff done. You can still do some OO stuff behind the scence if you really want, but for now you should focus on making the APIs as simple as possible. Oh, and you probably return some kind of object from read_file, so there's your OO part.

Anyway, now that you have a simple API for a part of your program, you can start to write tests.

use 5.010; use Test tests => 2; use YourModule qw/read_file/; my $data = read_file('t/data/ExampleData'); # now you have to ask yourself, what kind of data # will you need for processing the spreadsheets? # I know nothing about your application, so # I'm just making up some stuff here: is join(',', $data->headings), 'time,pressure,temperature', 'can get column headings from $data'; is $data->temperature( time => "0.01"), 273.018, 'can retrieve temperature by time';

So, now you need to implement it far enough to get the tests passing.

Next you can do the same for processing the data, and for writing a file. The API of each of those can always be a single subroutine call.

If you need some more flexiblity later on, those subroutines can call some constructors on your classes and use polymorphism and whatever buzzword you want to be compatible with. But always remember that the user should seee as little complexity as possible. That way the tests also see very little complexity, and it becomes very easy to test each piece of functionality in isolation from the others.

Once you have all of this in place, you will probably want some higher level abstraction, for example something that reads several input files, passes them to a routine that does the processing, and then writes output files. Again the API for this can be a simple function, and thus it can be easy to call and test.

read_process_write( inputfiles => [ 't/data/TestInput1', 't/data/TestInput2'], merger => sub { ... }, outputfile => 't/data/temp/TestResult', );

Again, write the tests for it and implement it. Then be happy.

Note that all this time I didn't talk about how to structure roles and classes. That's because it's not really central to the working of your program, and it is often obvious. Once you know that an API is my $data = read_file($path);, it is obvious that $data must contain an object that knows everything interesting about the data in file $path (or contains other objects that know it).

Replies are listed 'Best First'.
Re^2: Test Driven Development example + design question
by mascip (Pilgrim) on Jul 01, 2012 at 12:49 UTC

    Thank you for you two answers.

    You are both saying : "your program is simple, just do things one after the other, you probably don't need objects." (and giving me examples of how you use TDD, thank you)

    Practically I agree, BUT
    my question is more theoretical than practical.
    I am trying to understand key concepts on a (too) simple example. And i think in a way, i finally understood that my question is "bottom-up or top-down design?". Could anybody confirm this? This is all new vocabulary to me, so i would appreciate if someone experienced told me whether i am understanding the concepts properly or not.

    When i will build a bigger, more complex program, i will have the same question again : should i first start building low-level objects (bottom-up approach), thus basing my design on assumptions about external inputs? Or shall i go "outside-in", first interacting with my external peers, and then delegating responsibilities to new lower-level classes when i see that i need to.

    The programer who wrote this article prefers a top-down approach , because he doesn't like to base a design on assumptions, and thus write useless code.
    While this one prefers bottom-down, because it (would) result in more loosely-coupled elements of reusable code; and it requires a lot less stubs or mocks while in development.

    These questions are important to me. Sure, i don't want to become a "purist", and to make my life complicated on simple problems all the time. But i am just trying to learn how to design highly maintainable, loosely-coupled code. And if there are several ways to do it, i'd rather learn about them.

    ~ ~ ~
    I don't find it today, but yesterday i read this blog entry by chromatic, saying that he likes to use the smallest possible objects and roles as possible. And i read it in a few other places too. I guess it sounds as if it was "more work", and people will say "why are you being so complicated?" But it also gives maintainability and flexibility. And i don't think that "more classes = more work", as creating classes is so simple with Moose.

    PS : thank you for pointing at Test::XT

      I found the blog entry. chromatic wrote this as a comment :
      "I wish Perl 5 had classes with less inertia. It wouldn't have to go as far as Smalltalk, but if I felt classes were lighter and more agile, I'd use a lot more little classes.
      Am I the only one?"

Re^2: Test Driven Development example + design question
by mascip (Pilgrim) on Jul 01, 2012 at 18:29 UTC

    I read a bit more.
    Apparently i misderstood the vocabulary :
    "Coding by Intention you write your code top-down instead of bottom up. Instead of thinking, "I'm going to need this class with these methods," you just write the code that you want... before the class you need actually exists. "

    So, i can do TDD and code top-down, for any of my two designs. And i still don't know what differentiates these two designs.

    I'm lost, help

Re^2: Test Driven Development example + design question
by mascip (Pilgrim) on Jul 01, 2012 at 19:46 UTC

    I'm getting really confused, not sure whether the second design idea is just stupid.

    I think that i understood "from inputs to outputs" the wrong way around. Inputs are events that trigger a functionality, not just data.

    So, my Input here is the user (me) requesting a calculation. I need design 1.

    Sorry. I will experiment a bit more before asking further questions. And read a book about TDD in Perl.