The underlying problem involves downloading stuff from the network. The existing code uses an old framework class to do the download; now we want to use a shiny new framework class that does the download better. How do we do it?
The Old Way: tear out the old code. Write new code. debug until it works.
Incredibly, this was the way everybody did this all the time until the last few years.
Jalkut’s Facade: Jalkut wraps the new class so its API looks like the old one. Having done this, he can plug the new code in easily – and all the existing tests remain in place. The wrapper class is typically a kind of facade, a pattern from the Gang of Four book invented specifically for this task: the facade makes one class behave like a different class.
The disadvantage is that we’ve added another class, and we’re stuck using the wrapper, not the actual shiny new object. That can turn out to be limiting; eventually we may be tempted to broaden the wrapper to get at more of the new functionality. Eventually, the wrapper may become a messy restatement of the underlying class with an worse API.
Simmons’ Abstraction: Simmons uses extract class to wrap the old class in a higher-level abstraction, an object that encapsulated the operation of fetching something from the network and then doing some work with it. This improves the code without even using the new class. He writes tests for the new class to give confidence that it works.
That done, he tears each old API calls out, one by one, and replaces them with new API calls. This is safe because the new class is well tested, and its client is also well tested; if we break something, we’re bound to find out fast.
The advantage is that the new abstraction is fits the problem; it's motivated by the task, not by the need for a facade. There’s no vestige of the old API, and no constraint on using the new API either.
Which is better? Brent and Daniel are being all polite to each other, and this (slightly) obscures the tradeoff here.
Facade is better:
- when lots of different objects all over the place use the old API, since they can all share the facade but each will need its own task abstraction.
- when there’s no abstraction for the task that’s better than the bare API.
- when you don’t trust the existing unit tests and you can’t fix that
- when you are really short of time, short of confidence, or when it’s past midnight and you’ve got to get this out tomorrow.
The rest of the time, Brent’s abstraction is better.