| "TDD creates bad architecture". What is good architecture? I subscribe to the idea that we are doing software engineering and as such there are some "generally" understood principles such as SOLID, the Law of Demeter, Cyclomatic Complexity, etc that provide objective measures of "good" architecture (I apply SOLID all the way up the architecture hierarchy not just on classes). What I've noticed is that TDD results in code that scores well against these measures, while code that scores well is easy to test (i.e. after writing the code). Therefore, I think the argument that TDD creates bad architecture is false. About 25 minutes into the talk we get to the crux of DHH's complaint and it is that Hexagon is an alternative to the Active Record (which he created) and the only reason Hexagon exists is to allow TDD. Hexagon requires throwing away the really useful code that is Active Record. Hexagon appears to be an attempt to introduce sound software engineering practices (SOLID etc) into the Ruby world (with what success I do not know). Active Record and Rails in general is really useful if what you want is what it does, but sometimes its not. The implied claim that Hexagon is a bad architecture is false. The claim that Hexagon only exists to facilitate TDD is false. "Mocks returning mocks returning mocks" I use mocks. Fowler and Beck said on the whole they don't use them which genuinely surprised me. They cited examples of code where the test actually enforced implementation rather than purpose. I think that's probably how I wrote tests for the first few years. Code that results in mocks returning mocks returning mocks is code that is violating the Law of Demeter. Its bad code. It happens to be really hard to test, and it happens to be really hard to write tests first that way. Universally I've only ever seen tests like that when the tests were written after the code. TDD doesn't produce code like that because its easier to refactor it rather than keep digging that hole. Mocks returning mocks returning mocks is a symptom of not doing TDD. "My mind works differently... I have to write code first" Spike. Problems that I don't know how to solve I spike first (I write code with no tests, or with tests only as drivers of execution). That's easy. The hard question is, "Now I have all this code, I have to throw it away and TDD it?" That's pretty hard to stick to in a business environment. I choose to write tests-after for all those pieces of code that already meet SOLID metrics, and rewrite the code (using TDD) for the pieces that don't. The pieces that don't are very difficult to write tests for after, and they also happen to be the pieces where I find bugs (for example, I'll cut and paste a bit of logic and find its wrong for one set of inputs). "All code should have full coverage of automated tests" All three agreed that this is the case. Fowler: "If you have a full suite of tests I don't care how you got it [TDD or not]". I don't know about you but I'm still fighting this battle. I also have to deal with teams that have a "full suite of tests" and 80% test coverage, but where every single one of those tests simply executes code. No actual "test" occurs. Indeed, in particularly memorable test, I managed to delete 70% of the lines of code and all the tests passed (including deleting the one line that was the main purpose of the method). Approximately 90% of all the tests were complete garbage: they reported success as long as the code didn't throw an exception. |
Cyclomatic Complexity is not a principle, it's a specific measurement of potential complexity. Law of Demeter is a guideline SOLID is an object oriented-centric set of principles.
These are 3 completely different things.
You then go on to state using these makes software more testable. Since TDD can only exist in "testable" code, TDD is good design because these measurements/guidelines/principles are good design.
It's a non-sequitur of epic proportions.
I guaran-goddamned-tee you I can write a piece of software with less cyclomatic complexity than the Linux kernel, that is not nearly as well designed. Conflating those two things is what it means to be PHB.
CC is simply a measurement of a specific type of complexity, and like all measurements, it means jack shit without context. For example. the measurement of 8 inches. Is that number high, low, or normal? Or put another way, are we measuring a mans penis, a mans leg, or a mans hand?
this is why so much software turns to shit. This right here. The process by which you make decisions. If it's a good process, you'll have a tendency to make good decisions. If not, as illustrated by the post above, you will have a tendency to make bad decisions. A series of mostly good decisions will result in acceptable to good software. And the opposite results in unacceptable to bad software.
You want to learn how to write good, stable software? Learn to examine your thought process, and be explicit in your attempt to make good decisions. Be willing, and able, to identify bad decisions, why they're bad, and what you should have done instead.
What you did was believe the conclusion (TDD is good design) and then constructed the argument for it. DO NOT DO THIS. This is the stuff of bad decisions and software design failures, and this will happen regardless of which process you subscribe to.