Is anyone actually using #tdd in real coding? I have some questions.
@observer11 For roughly 20 years. Ask away. (Bias warning: I make a TDD-focused testing framework for .NET.)

@bradwilson I've been making a torrent client in Go. The hardest thing so far was coming up with a clean and logically separate code (which I haven't done yet 😆), but also I had problems with writing tests which can test the entire system.

To validate that the client is working, I have to spin up real qBittorrent clients, so I use Docker in my tests.

It's hard to articulate my thoughts. It was easy to write a bencode parser with TDD, but everything else is a hassle.

@bradwilson I started doing TDD through https://github.com/quii/learn-go-with-tests which I recommend a lot.

Anyway, it recommends writing acceptance tests first, so I wrote a test to download a file from a torrent peer. The implementation itself is ultra-rudimentary, right in TDD spirit. However, it has been hard to follow it up with good, structured code which is cleanly separated and tested.

Should I have to keep design separate from TDD and come up with a solid design up-front or am I doing something wrong?

GitHub - quii/learn-go-with-tests: Learn Go with test-driven development

Learn Go with test-driven development. Contribute to quii/learn-go-with-tests development by creating an account on GitHub.

GitHub

@observer11 To me, the primary thing that differentiates TDD from "test after" isn't when you write the tests, but why.

I like to call TDD "Design by Example", where the example is executable code. At the API level (testing an individual function), this means writing the test to show how you'd like to consume the function in question, and what the impact of calling that function is (directly, via return value, or indirectly, via interaction with other aspects of your software.

@observer11 So in the case of writing an acceptance test first, what I'd want to see is code that shows how you're interacting with some subset of the system (or the system as a whole), and how it impacts everything else. The larger the scope of the things you're testing, the more likely what you're observing w/ changes involves other parts of the system (vs. just a function return value).
@observer11 No matter what level you're testing at, though, one thing is very common: isolating yourself from things that are hard to control otherwise. In the case of a Torrent, maybe the best thing is to test how the peer responds to specific protocol stimulus. You can do this with a full fledged second peer, or you can do it with something that _simulates_ what a torrent peer might do.
@observer11 Simulations add reliability and make it easier to test both positive and negative responses (including simulating things like network delays, slowdowns, etc.), but they come at the cost of adding complexity to the test setup (you'll have to write the simulator if one doesn't exist), and for very complex interactions, that can be pretty hard to do.
@observer11 So in your specific example, I'd be looking for a simulated torrent peer that you can instruct to both behave properly as well as malfunction in ways which you want to validate your handling of in your own code. I don't have any experience with torrent peers so I don't know if such a thing already exists. It doesn't have to be Go code, as it could be something you just run (perhaps in Docker) to talk to externally.
@observer11 What I generally suggest is that people start with high level acceptance tests, but leave them failing and instead focus on component-level testing of all the individual pieces that will be needed to make the acceptance test past. Once those things are all tested to your satisfaction, then you put them together and hopefully see the acceptance test pass...or discover where the holes are that are yet to be tested.
@observer11 The truth is that the higher level your test is, the more individual things can go wrong that cause the test to fail, so trying to just use high level tests to validate software will feel very frustrating, almost like you're playing Whack-a-Mole.
@observer11 As to the question of whether you need to do high level design before you can start just working on individual components...there's no one good answer. It really depends on the software you're working on, and whether you have a good idea of the components that will be necessary to make the system work as a whole. High level design (with acceptance tests) might give you valuable information you need...or they may not be necessary. "It depends". 😄
@bradwilson thanks for the very detailed reply 😄