Hacker News new | ask | show | jobs
by hitchstory 495 days ago
Not the only value though. Red-green-refactor can also provides live feedback about whether your code is behaving correctly as you write it.

Requiring the test before writing the code also ensures you dont forget to write a test to match the scenario.

So what is gained by test after... is that it is almost as good?

I still dont get it.

4 comments

I need something to work with before I can write the test. So my order tends to be: get the code working first with the simplest case, and by using it I know that simple case is working, then use that to write the first couple of tests. Only then would I expand the tests to the cases not written yet and to a TDD style.

This order also helps verify I didn't typo something in the test itself and end up TDD-ing myself into broken code.

I usually start with a basic e2e that tests the most minimal happy path possible. It makes no assumptions about architecture or anything else.

You don't need something to work with to write it. You can, by definition, write an e2e test against an app that doesnt exist.

This test isnt special as far as TDD is concerned - red-green-refactor works the same way.

Im sensing a pattern in the answers to my question though. I keep getting "well, if you assume TDD is only done with low level unit tests..."

> Im sensing a pattern in the answers to my question though. I keep getting "well, if you assume TDD is only done with low level unit tests..."

Completely wrong.

Even with your example, there's an initial exploratory stage where you're still figuring out the interface that the tests would use. I, personally, am not capable of using something that doesn't exist. I have to make that initial version first before I can use it in a test.

Quick edit aside: This is also why I rarely work top-down or bottom-up, I work mostly throughline - following the data flow and jumping up and down the abstraction stack as needed.

Im not sure quite why you feel you always need to write code before sussing out what an API or UI should look like but it seems like a very expensive habit to me.

What happens when you then show it to stakeholders (e.g. other teams consuming your API, customers or UX people) or and they tell you to change it again?

Rewrite everything again?

Thats gonna be reaaaaaaaalllly labor intensive and could damage your code base too.

Im equally perplexed about why people dont try to build top down. It's one of those few things in programming that always makes sense regardless of circumstance.

> What happens when you then show it to stakeholders (e.g. other teams consuming your API, customers or UX people) or and they tell you to change it again?

> Rewrite everything again?

> Thats gonna be reaaaaaaaalllly labor intensive and could damage your code base too.

Why would I do that? Only the thing they have issue with would need to be changed, it wouldn't take any longer than another way of doing it.

You seem to have forgotten what I said, something needs to exist for me to work with. Well, in this "stakeholders want something changed", something exists. It's not a rewrite from scratch.

>Why would I do that?

If you change the spec (e.g. changing the contract on a REST API), you will probably need to consult to make sure it aligns with everybody's expectations. Does the team calling it even have the customer ID you've just decided to require on, say, this new endpoint?

>You seem to have forgotten what I said, something needs to exist for me to work with.

No. I'm assuming here that a code base exists and that you are mostly (if not 100%) familiar with it.

If Izkata is anything like me they write code as part of their exploratory design process with no intention of showing it to anyone else until they've iterated their way to a design that they like.
Sometimes you need the unit before you can unit test.

So you end up writing the unit's boilerplate, that doesn't yet do anything but needs to compile/run for a suite to test it throwing a adhoc error of the notImplemented sort or whatever, then break flow to set the test suite and check the reds (that aren't telling you anything useful because of course it's red), then actually write the code.

I find it flow-breaking and cumbersome for little to no gain.

For additions to existing code I find TDD more useful, but even then it's not unusual to decide to move logic around until deciding a final structure, so the units you end up with might be solidified later in time. Writing tests for scraped units is a waste of time then.

>Sometimes you need the unit before you can unit test.

Right. In those situations I TDD with an e2e or integration test.

I dont get why youd restrict yourself to doing TDD with just with low level unit tests.

I don't, but you agree that in that case the unit test comes after? That was the point I was arguing.
Not necessarily. On plenty of projects I have done 100% TDD and never written a single low level unit test.

The type of test is, in my mind, a completely different topic to red-green-refactor and for the decision about which one to write I follow a set of rules which is also unconnected.

TDD is just red-green-refactor. It works with any test.

If you value red green refactoring then you should write the tests first.

I only use that technique for pieces of code that really fit that well - usually functions that have a very strong relationship between their input and output - so I'll write tests first for those, but not for most of my other stuff.

Well ok...but then what kind of code doesnt it fit well?

Almost every user story I follow in production code follows the form of given/when/then scenario which can always be transformed into a test of some kind (e2e, integration, sometimes even unit).

Where it's something like "do x, y and z and then a graph appears" I find TDD with a snapshot test with, say, playwright works best.

I'm talking about strict test-first development here, where you write the tests before you write the implementation.

If you're using snapshot tests (a technique I really like) surely you can't write the tests before the implementation, because you need the implementation in order to generate the snapshot?

(This is what I hate about the term TDD: sometimes it means test-first, sometimes it doesn't - which leads to frustrating conversations where people are talking past each other.)

You need the final implementation before taking the final snapshot but you can write the entire test up front (given/when). The snapshot artefact is generated not written (often in a different file entirely), so Id argue it still fits the definition cleanly.

I agree that "unit test"/"integration test" as a definition sucks horribly and leads to people talking past each other, but I think with TDD the main issue is that lots of people have developed a fixed and narrow idea of the kind of test you are "supposed" to write with it which makes the process miserable if the type of code doesnt fit that type of test.

The whole idea of a unit test being "the" kind of "default" test and being "tests a class/method as a unit" definitely needs to die.

> Red-green-refactor can also provides live feedback about whether your code is behaving correctly as you write it.

No, it provides live feedback about whether your code is passing your tests

If you have written your tests poorly then set out to make the tests pass, then your tests become the target rather than the correct behavior

If you are continuously updating your tests while your code evolves because you missed test cases or your understanding of the behavior has improved, then writing the tests first didn't actually give you any value. In fact it just wasted a lot of your time

Write the code Manually test to verify correctness and to identify the test cases you have to write THEN write tests to protect against regressions