Thanks for your thoughtful reply, Tim!

Am 03.06.2013 07:35, schrieb Tim Starling:
> On 31/05/13 20:15, Daniel Kinzler wrote:
>> "Writing Testable Code" by Miško Hevery
>> <http://googletesting.blogspot.de/2008/08/by-miko-hevery-so-you-decided-to.html>.
>>
>> It's just 10 short and easy points, not some rambling discussion of code 
>> philosophy.
> 
> I'm not convinced that unit testing is worth doing down to the level
> of detail implied by that blog post. Unit testing is essential for
> certain kinds of problems -- especially complex problems where the
> solution and verification can come from two different (complementary)
> directions.

I think testability is important, but I think it's not the only (or even main)
reason to support the principles from that post. I think these principles are
also important for maintainability and extensibility.

Essentially, they enforce modularization of code in a way that makes all parts
as independent of each other as possible. This means they can also be understood
by themselves, and can easily be replaced.

> But if you split up your classes to the point of triviality, and then
> write unit tests for a couple of lines of code at a time with an
> absolute minimum of integration, then the tests become simply a mirror
> of the code. The application logic, where flaws occur, is at a higher
> level of abstraction than the unit tests.

That's why we should have unit tests *and* integration tests.

I agree though that it's not necessary or helpful to enforce the maximum
possible breakdown of the code. However, I feel that the current code is way to
the monolithic end of the spectrum - we could and should do a lot better.

> So my question is not "how do we write code that is maximally
> testable", it is: does convenient testing provide sufficient benefits
> to outweigh the detrimental effect of making everything else inconvenient?

If there are indeed such detrimental effects. I see two main inconveniences:

* More classes/files. This is, in my opinion, mostly a question of using the
proper tools.

* Working with "passive" objects, e.g. $chargeProcessor->process( $card )
instead of $card->charge(). This means additional code for injecting the
processor, and more code for calling the logic.

That is inconvenient, but not detrimental, IMHO: it makes responsibilities
clearer and allows for easy substitution of logic.

> As for the rest of the blog post: I agree with items 3-8.

yay :)

> I would
> agree with item 1 with the caveat that value objects can be
> constructed directly, which seems to be implied by item 9 anyway.

Yes, absolutely: value objects can be constructed directly. I'd even go so far
as to say that it's ok, at least at first, to construct controller objects
directly, using servies injected into the local scope (though it would be better
to have a factory for the controllers).

> The
> rest of item 9, and item 2, are the topics which I have been
> discussing here and on the wiki.

To me, 9 is pretty essential, since without that principle, value objects will
soon cease to be thus, and will again grow into the monsters we see in the code
base now.

Item 2 is less essential, though still important, I think; basically, it
requires every component (class) to make explicit which other component it
relies on for collaboration. Only then, it can easily be isolated and
"transplanted" - that is, re-used in a different context (like testing).

> Regarding item 10: certainly separation of concerns is a fundamental
> principle, but there are degrees of separation, and I don't think I
> would go quite as far as requiring every method in a class to use
> every field that the class defines.

Yes, I agree. Separation of concerns can be driven to the atomic level, and at
some point becomes more of a pain than an aid. But we definitely should split
more than we do now.

-- daniel


_______________________________________________
Wikitech-l mailing list
Wikitech-l@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/wikitech-l

Reply via email to