I want to reflect specifically on the testing part. Henrik Warne talks about how unit tests were an improvement to the development process, and how designing for testing was an improvement for program design.

I think both are very naive ideas (as I think overall about Agile and XP). But, before I get to the "why" part, I want to first describe my perspective on how testing changed over time.

The perspective on testing before the "shift left" happened was that testing is supposed to be adversarial. I.e. it was important that the testers don't know how the code works or what decisions did the development team make to solve higher-level problems the software was meant to solve. This was important so that testers wouldn't turn the blind eye to the software problems they would've otherwise gotten used to, or would have accepted the trade-offs before even getting into testing. The reason is very similar to how in clinical trials the participants aren't told whether they get placebo or the real drug.

This is also why the testing would normally start after the software was in a shape ready for testing (i.e. after a reasonably long development interval). This is also why a lot of it was manual: there wouldn't have been time to develop utilities for testing since the testers didn't know what the software was like.

But, of course, there were also commercial incentives to finish earlier. This is how "patch version" became a thing for example: a typical testing cycle would be to receive the system from the developers, to deploy it, to validate it (i.e. to ensure that the minimal required functionality is there), and then to try to "break" it. If the system broke, the developer would be notified. They then would have to fix the problems and deliver the fixes as patches. These patches then would be given a version number, and the testers would be required to use them to patch the deployed system in place, in order to continue testing.

A system shipped to the customer would usually contain a bunch of patches, and the installation process would include patching as well.

The downside of this system is the time it takes to get to the working product. The upside is the better overall quality of the product. The better quality comes from the testers working from specification rather than from their familiarity with the code.

----

So, unit tests. From the perspective of someone who had to manage CI for rather large organizations: unit tests give the least value for the most effort (among different test types). Because unit tests deal with the minutia of the code details they tend to change a lot, they grow stale very quickly, and they require a lot of maintenance because they tend to also multiply very quickly. Besides, most of the unit tests in every CI run test the code that didn't change anyways. They just burn electricity for no effect. It's very hard to come up with the system that would only apply unit tests where the code changed.

In the end of the day, given the limited time and resources, if there's any test a developer should be spending their efforts on it's the end-to-end test. They don't change as often, and they at least can guarantee that the program, as a whole, works sometimes (unit tests have no useful guarantees about the whole program).

----

When it comes to designing for testing... it's also complicated. There are many dangers in doing this. Testing code is often a security backdoor. Testing code can also cause performance problems. There's a very delicate balance between the ways of how the system can be instrumented for testing and how much this instrumentation actually contributes to the quality of the system. My approach here is that as much as possible, the testing needs to be external to the system. This is to prevent tests from affecting the system, and especially from leaving undesirable artifacts in it.

----

Agile, or any other simplistic software development management process is just that: simplistic. It doesn't mean it "doesn't work" -- it means that it works sometimes. But, I wish we spent time on studying the process and discovering better way of doing things instead of trying to shoehorn things we meet in practice into existing simplistic process descriptions to justify their existence.