X: We need to follow TDD to reduce the number of bugs we get in live.
Y: Yes we might have to from now on. We also need to compliment it with BDD.
Z: Erm.. what does TDD have to do with live bugs? We need to follow ATDD.
Stakeholder: I simply wanted to convey the message that we are getting too many live bugs on feature “A”. May be that area need attention and few more tests to monitor the stability.
Common language and shared understanding is clearly missing on the above conversation. Partly because TDD stands for “Test Driven Development”. Self testing code is what we are after. There are many ways to write self testing code and TDD is one of the best approaches for doing just that. It doesn’t mean it is the only approach. Unit testing is the other more prominent contender.
Before we go further, lets expand the acronyms for those who are new to the concepts or new in the field of software development:
TDD – Test Driven Development
BDD – Behaviour Driven Development
ATDD – Acceptance Test Driven Development
TDD is NOT about testing
It’s true that we write a test before we write any code in TDD. It’s also true that we create a suite of tests that can be dependable during Continuous Integration (CI). What we fail to explain in this process, is to clarify a non-technical member that the core benefit of –
TDD is to help design an excellent architecture. The tests and the resulting suite are merely a byproduct.
TDD tests are robust and can confirm if a new commit have broken the existing build or not. Although, what it cannot confirm that if that awesome commit actually meets the acceptance criteria. A solid robust commit have every possible chance to be completely useless, unless we run end to end tests to verify the acceptance criteria. It assures quality but it is created by developers for themselves to clarify the low level architectural requirements.
A self testing code, hence, is a sanity check of the codebase’s stability and not necessarily a check on what the end users are expecting.
TDD is NOT the same as Unit Testing
Another way of creating self testing code is writing Unit tests after the code is implemented. The purpose is same as TDD, fast feedback about a commit. Although –
Unit Tests does not assure quality, it confirms an existing logic.
Why? Because the Unit tests can only see that a logic exists. Whether the logic is right or wrong, it is too late for that. Any test written after the code is implemented never assures quality. It simply confirms “yeah that’s what it does, no idea if that’s what it’s suppose to do or not“.
Assuring vs Controlling
Quality Assurance (QA) and Quality Control (QC aka Testing) have very different purpose.
- QA prevents bug where as QC controls the known bugs to a manageable level.
- QA is about discovering plausible scenarios as a team before coding, QC is about executing the tests manually/automated to discover edge cases after coding.
- QA requires a whole team to focus on quality from the moment an acceptance criteria is written. QC is historically what all testers do and consider as their job.
Only if we focus on prevention early on, we may not need a dedicated role as a Tester. If you are writing the code, you should fully own the practice of confirming if it does what it’s suppose to do. Anyway..
So, TDD assures the quality of the design & architecture, which is great but not enough. Integrations tests and the end to end UI tests on the other hand are about QC. It certainly depends on when they are written – in ATDD they are written before the code is implemented. Not many companies follow ATDD, reason why most Integration & UI tests are written too late after the feature is already deployed on a staging environment.
In fact, we write these tests NOT to “test” anything; we write them to save time during regression testing, to save manual effort of repetitive tasks and cover our arse in the hope that the end users/stakeholders might accept the iteration, that’s all. It’s a team responsibility to assure quality not any particular individual’s.
TDD is not mandatory, neither is evolution
If we don’t consider scaling as a viable option in any near future, then feel free to ignore TDD. Truth be told, any software we see today always need scaling and an evolving architecture. To evolve we need constant refactoring and continued attention to the design and architecture.
Non-technical members won’t get this, neither you have to ask them. You, as a developer, thinks it is important – good enough, just do it while being transparent about it. Need to add few extra velocity points? Go on then, it’s necessary – it isn’t a theory. Technical debt is a reality, might as well pay the debt while you can.
As a developer, if you can’t see the benefits yourself, good luck explaining the benefit to someone else who only cares about faster delivery of error prone “working software”. It’s your job as developers to raise awareness and build quality in to prevent waste of time later.
Whether we think TDD benefits us or not, it’s always a very good way to constantly be agile and stay agile. Evolving <anything> is what we need and TDD closes that gap by reducing risk on low level and ensures a great quality architecture. Don’t focus on what it’s called, focus on what it’s suppose to achieve. ATDD and BDD both compliments TDD, not replace it. They simply have very different purposes even though many “think” these are all about testing. It’s not, it never was.