On 31/05/13 20:15, Daniel Kinzler wrote:
When looking for resources to answer Tim's question at https://www.mediawiki.org/wiki/Architecture_guidelines#Clear_separation_of_concerns, I found a very nice and concise overview of principles to follow for writing testable (and extendable, and maintainable) code:
"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.
As far as I am concerned, these points can be our architecture guidelines. Beyond that, all we need is some best practices for dealing with legacy code.
MediaWiki violates at least half of these principles in pretty much every class. I'm not saying we should rewrite MediaWiki to conform. But I'd wish that it was recommended for all new code to follow these principles, and that (local) "just in time" refactoring of old code in accordance with these guidelines was encouraged.
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.
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.
Even if you test code in larger chunks, very simple code tends to fail in ways that are invisible to unit tests. For example, you can get 100% test coverage of some code that generates an HTML form by confirming that it generates the HTML you wanted it to generate, but that's trivial. The most likely place for a flaw is in the specification -- i.e. in the HTML code which you typed into the unit tests and then typed again (perhaps with a trivial transformation) into the implementation.
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?
As for the rest of the blog post: I agree with items 3-8. 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. The rest of item 9, and item 2, are the topics which I have been discussing here and on the wiki.
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.
-- Tim Starling