Live data from Hacker News

Giving up on test-first development

iansommerville.com

191–200 of 224 posts

Re: Giving up on test-first development

#191
post #74

[TDD] encourages a focus on sorting out detail to pass tests rather than looking at the program as a whole. I have actually found the opposite to be true. I have to make large refactorings to move things around to arrange the whole system so that each part can be tested without too much effort. To do this I have to view most things in terms of the interfaces they provide. On the test side, I have to write the test co…

I agree.

I've been doing TDD for 4 years now, and I would totally agree that it takes a lot of time to hone the skills. My experiences of TDD on projects is quite similar to yours. However, it took me a year to simply really understand how to do TDD in any kind of sane way.

TDD is not something you can easily pick up in 6 months without a lot of mentoring and training from experienced TDD'ers.

Re: Giving up on test-first development

#192

Earlier quoted context omitted.

Can you give an example? I'm struggling to think of a language where that can't be worked around without bending the original code.

public class Foo { private static class Bar { public void someMethod() { } } } Unit test someMethod. More realistic, concrete examples are harder to describe because they involve an interaction over time between a somewhat vague problem description and exploration of a solution state space, where the abstractions chosen are fluid and slide around before they get into a good shape. I, for one, tend to write code from…

As Uncle Bob describes in his book, you never even make abstractions until you have proven duplication. You make your abstractions based off of evidence, not hypothetically planned out.

Kent Beck in his book doesn't recommend top-down, or bottom-up, but rather from known-to-unknown. Start with what you know, and work toward what you don't know.

Edit: The books I refer to are Test Driven Development: By Example - Kent Beck, and Clean Code - Robert Martin

Re: Giving up on test-first development

#193

Earlier quoted context omitted.

> The preference function (or oracle) can return a truth value without you necessarily having insight into its inner workings. Is this preference function implemented on a computer, or is it just a person giving you seemingly random answers in response to whatever you tell them? > People "know it when they see it" without necessarily being able to define it. That path leads to hell. > After a solution has been found,…

> > People "know it when they see it" without necessarily being able to define it. > That path leads to hell. That's why they pay us the big bucks. If people could define their problems well enough without iterative design, waterfall development would be a success story and all software would be outsourced to the lowest bidder.

That's wrong. It's perfectly possible to define your problem well, and still require an iterative process to find a good solution.

Re: Giving up on test-first development

#194
post #137

Earlier quoted context omitted.

How many of those side projects ended up being 6 million lines of code maintained over 5 years? Because those are the kind of code bases I have in mind when I'm weigthing the pros and cons of TDD or other testing practices. When reading Uncle Bob and others I have always got the feeling that the "goal" of the practices described is to have systems that can be maintained and extended for years by different people and…

it's like i'm an artist. You can't tell an artist how to paint. I'm going to paint my best work when I'm allowed to choose my own easel and pallette and brushes. Let me throw some green paint on the canvas and make the trees how I wanna make the trees. Programming is more art than science.

True, if you're working alone. But 5, 50, 500, 5000 artists trying to paint on the same canvas? Then the game is significantly changed.

Re: Giving up on test-first development

#195
post #74

[TDD] encourages a focus on sorting out detail to pass tests rather than looking at the program as a whole. I have actually found the opposite to be true. I have to make large refactorings to move things around to arrange the whole system so that each part can be tested without too much effort. To do this I have to view most things in terms of the interfaces they provide. On the test side, I have to write the test co…

I agree. I've been doing TDD for 4 years now, and I would totally agree that it takes a lot of time to hone the skills. My experiences of TDD on projects is quite similar to yours. However, it took me a year to simply really understand how to do TDD in any kind of sane way. TDD is not something you can easily pick up in 6 months without a lot of mentoring and training from experienced TDD'ers.

Part of the problem is that there are not that many TDD codebases or TDD'ers around. Also, this is probably not something you can pick up while doing toy projects or school assignments. The benefits start to show in the 100 kloc and above magnitudes, and as there are so many ways to paint yourself into a corner with bad overall design, coupling, unmaintainable (or slow!) tests, chances are, you don't figure out all the necessary things yourself. On top of that, there is no time to learn this much in most dev jobs, so you are left to learn with hobby projects (which do not usually grow big enough).

Re: Giving up on test-first development

#196

Earlier quoted context omitted.

> The only thing that matters to how software works for an end user is its boundary. You're ignoring the fact that tests aren't only to validate "end user functionality". They're also there to make life easier for the developer; to make both initial development and maintenance easier. If I need a custom sort algorithm for my product, I'm going to write unit tests for it's implementation. I'm also going write function…

> If I need a custom sort algorithm for my product, I'm going to write unit tests for it's implementation. I would start with writing an assertion about the end state of the sort. Then using syntactic substitution of the predicate calculi derive the program by assertions. I'd then have a specification of the algorithm as a mathematical model from which I can check every possible execution for the entire domain on the…

Would you actually do this, or do you just like to imagine a world where people do this?

I'm familiar with Coq and Prolog(one of which I think you're hinting at), but I'd reach for Perl or C over either one if I needed to write a trading program or generate a statement from my accounting software or something.

Re: Giving up on test-first development

#197

Earlier quoted context omitted.

public class Foo { private static class Bar { public void someMethod() { } } } Unit test someMethod. More realistic, concrete examples are harder to describe because they involve an interaction over time between a somewhat vague problem description and exploration of a solution state space, where the abstractions chosen are fluid and slide around before they get into a good shape. I, for one, tend to write code from…

As Uncle Bob describes in his book, you never even make abstractions until you have proven duplication. You make your abstractions based off of evidence, not hypothetically planned out. Kent Beck in his book doesn't recommend top-down, or bottom-up, but rather from known-to-unknown. Start with what you know, and work toward what you don't know. Edit: The books I refer to are Test Driven Development: By Example - Kent…

Abstractions aren't merely for duplication removal. Abstractions are for symbolic chunking; for thinking about things at different levels.

We don't use e.g. units-of-measure types [1] because they remove duplication from our code; if anything, they add duplication. They do however clarify our thinking with help from the type checker.

I think a lot in terms of flows / pipes / functional transforms. So I tend to try and express problems in that shape, because I have a lot of mental tools that I can apply, and I know they're extremely easy to test in isolation. Creating a pipe-like thing means reducing it to a simple common push or pull stream pattern. But it's not duplication I'm removing here; I'm actively introducing an abstraction because it has proven power for creating good software and solving problems.

I try and create few, minimal abstractions that can be applied widely. Take a cue from functional languages and split out types from algorithms; if you make your types more general, you increase the reusability of your algorithms. Classical OO design tends to create a lot of types that are specific to the domain model. I happen to think that OO designs are usually poor; they tend to have a high code complexity to implemented logic ratio, and require awkward composition that leaves details hanging out.

I spent 20 years writing OO software and was a big fan, especially in the early 2000s. I still work in OO languages, but most OO code I read makes me wretch now.

I don't recognize either Kent Beck or Bob Martin as particularly noteworthy for good architectural design (Beck is on the right path with agile though). In fact, I blame TDD for Java-itis: proliferation of single-implementation interfaces (has there ever been a worse idea more often propagated by cargo culters?), poorly abstracted object graphs, leaky implementation abstractions, and more.

> Start with what you know, and work toward what you don't know

I've been programming for more than 25 years. A lot of stuff has changed in that time; what hasn't changed is patterns of abstraction. So I start out with abstractions, chosen from experience.

Read Norvig on TDD [2] - his experience matches mine. If you know a lot of software tools (i.e. abstractions, algorithms, approaches), you can apply them to a problem. TDD is a poor tool for creating new tools, though. And if you rely on code duplication for creating a tool, well, you're going to have a bad time with hard problems.

[1] https://blogs.msdn.microsoft.com/andrewkennedy/2008/08/29/un...

[2] http://pindancing.blogspot.co.uk/2009/09/sudoku-in-coders-at...

Re: Giving up on test-first development

#198

TDD: Write the test case representing "this USB host controller driver has no race conditions", and then just fill in the code, and out pops a race-free USB host controller driver! (Of course, it does nothing so far other than demonstrating freedom from races, but that's just a small matter of writing more tests for actual USB requirements and fulfilling those.)

TDD is not about reduction of bugs, or race conditions. Robert Martin has said that reduction of bugs is not sufficient enough to warrant using TDD for code. TDD is about achieving better designed code that is maintainable and readable for many years. TDD uses unit tests, not integration tests. So, the behaviour of each function is asserted independently. Maybe you have a function that sets up a data structure at a p…

[deleted]

Re: Giving up on test-first development

#199

> I won’t spend ridiculous amounts of time writing tests when I can read the code and clearly understand what it does. Is he arguing that simply trusting yourself not to make mistakes is a sufficient guarantor of quality? Ian Sommerville is the author of a famous textbook on software engineering, so it would be surprising if he was. TDD is actually much more difficult in practice than people realise. I read Kent Beck…

What changed at Pivotal labs? And what do you get with regards to specs? It seems to me the methodology fits how requirements are derived.

> What changed at Pivotal labs?

The bread and butter of Labs is teaching people pair programming and TDD. So I was taught those things, and I'm still learning.

It takes a few passes through the whole cycle of story->feature test->integration test->unit test for things to begin to click, for that way of thinking to become habitual. It is uncomfortable and frustrating for some time, as Ian Sommerville found. In fact, because most code is not written test-first, it is difficult to test. So all that keeps you to TDD is habit and, to some degree, help from another engineer.

> And what do you get with regards to specs? It seems to me the methodology fits how requirements are derived.

The most popular story-writing style I have seen so far is the As A/I Want/So I; Given/When/Then. Usually some acceptance criteria are supplied. To varying degrees of fidelity that the feature tests will typically follow Given/When/Then.

In our weekly Iteration Planning Meetings engineers are expected to pipe up if there are useful ways to decompose stories into smaller stories, which makes the overall situation more manageable.

Re: Giving up on test-first development

#200

Earlier quoted context omitted.

To be fair the author was abandoning TDD not tests. He explictly said that he'll add tests after he writes the code.

Perhaps the author is more disciplined than me, but I'd have an extremely hard time actually following through and writing tests after-the-fact. After the code is "done", it's hard to keep working on it—no matter how much the "extra" work is needed. I find tests to be extremely helpful for designing APIs. I write tests to enforce the contract my API is making with its consumers. Therefore, TDD forces me to consider t…

That works well when your API is small and understood. But when you're exporting someone else's results (e.g., returning the result of a floating point operation,) your tests could start to become so exacting that they are more difficult to write and less reliable than the code you're testing itself. In that case, writing tests is basically writing an ad-hoc waterfall-style software specification.

I tend to write tests when I'm not confident in the implementation or when the tests are trivial to write. At least, that's how I do it for new developments. If you're releasing code that people are relying on, you should have a whole suite of user tests and regression tests.

Post reply on HN