Code noise

Musings on software construction

Angular + TDD: Together Apart

Angular is one of the few front-end frameworks I’ve had the pleasure to work with that emphasizes testing as a first-class concern. The dependency injection system encourages a separation of concerns that makes testing of all components easier, and the framework itself comes with a number of helpful mocking and test-support pieces. Things aren’t quite perfect – the DI system is somewhat intrusive, forcing itself into unit tests where it might not be especially welcome – but it’s a whole lot better than hacking your way through a pile of jQuery code.

So what’s the problem

The problem doesn’t lie with Angular, nor with the way it approaches TDD. Rather, it lies with the following two observations:

  1. Most front-end developers are not particularly familiar with unit testing, and especially not TDD, because of the lack of historical in existing frameworks
  2. TDD is hard. Like any other new approach to software development it requires practice, perserverance, and a lot of focused concentration, especially at first.

So, what happens when you start using Angular? Well, you’re obviously introducing a major new topic: Angular itself. Angular’s approach is itself substantially different to anything most of your devs are likely have seen before, so there’s going to be a lot of time, effort, and brainpower expended on picking that up.

If, like me, you’re eager to introduce TDD to as many people as you can, you’re going to be introducing a second major topic: testing and TDD. This is the problem.

The net result

Attempting to introduce both TDD and Angular at the same time is very appealing: if we’re building something new with Angular, we want to start out with something that is well tested, well designed (which our TDD will drive), and can be reliably worked on by all of our colleagues. The risk, though, is that the two concepts get confused, mixed together, and neither of them learned properly: the pace of acquiring Angular knowledge is reduced, and the quality of test and design is diminished.

John Lindquist put it well at Fluent Conference 2014 when he said that when writing Angular code we should strive for testable code from people who are learning the framework, and accept that tested code will be something that may come later. We don’t want to give up on the idea of using TDD to build our Angular codebase, but we equally don’t want to get so hung up on it that we put everyone off both approaches.

What do we do about it?

I don’t yet have a full answer to this. I’ve found it depends heavily on the experience of each engineer, both in prior exposure to TDD and comfort with the concepts in Angular. Somewhat counter-intuitively, I’ve found those coming from a server-side background – as opposed to existing front-end developers – have had an easier time, likely because TDD and IoC/DI are better established there. I now aim to teach people Angular first, and introduce testing and TDD as a second round of important concepts.

This doesn’t mean that when first demonstrating Angular I don’t push the testing and testability message: I still show how tests can be written, how separating concerns helps with testability and the evolution of design, and how that design can be evolved through the application of TDD. What I don’t do is require that everyone practice that approach from the start. Rather, I enourage people to learn the framework in their own way, and gradually push for more and earlier testing as they “level-up” in Angular.