Why did Apple Advocate for Bastard Injection?

If you can’t easily stub services for testing, then this implies a serious problem with your design. — Martin Fowler

Joe Susnick
Aug 8, 2017 · 5 min read

So what is ‘Bastard Injection’ and why is it bad?

I’ll try to stay out of the weeds but I can’t really answer this without quickly defining Inversion of Control and Dependency Injection.

Inversion of Control (IoC) is basically the idea that the caller of a function has the information the function needs to do its job.

Dependency Injection (DI), in a nutshell, is a technique to help you achieve IoC by specifying dependencies outside of the classes that use them.

‘Bastard Injection’ is a term that seems to be relatively new. I came across it in this post titled Dependency Injection in Swift. I did a little more digging and found out it’s sometimes used interchangeably with ‘Poor Man’s DI’. I like the explanations in this talk; the speaker defines Bastard Injection as:

[what] happens when we have a constructor that lets us provide dependencies for tests and another constructor with default implementations used in production.

He also mentions why it’s an anti-pattern:

The problem of this anti-pattern is in using as a default a foreign default — defined in other module. That makes our code testable, but tightly coupled with another module.

It appears to be decoupling your code but actually just allows you to change it for testing.


Let’s talk about Apple

There’s a video in WWDC17 that I’ve watched a few times now called Engineering for Testability where Apple lays out their recommendations for how to do basic Dependency Injection.

You should watch it here but it’s long so I’ll give you the tldr.

Talk Summary:

First they describe a method on a view controller that they’re trying to test, openTapped(sender:).

They show how to test this on a UIViewController and how it’s a pain. Specifically they point out that it has two serious problems for testing.

  1. The method is on a subclass of UIViewController so it needs an instance of that view controller in order to test it which is sort of a pain and adds overhead.
  2. It depends on UIApplication as a dependency.

So they propose creating a class DocumentOpener that can be tested in isolation.

They point out that this code still depends on a DocumentOpener instance knowing about UIApplication. They propose adding a property for an opener and adding an initializer to pass in that opener.

The new implementation looks like this:

The problem is, of course, that DocumentOpener still knows about UIApplication.

They advocate for making a protocol URLOpening which copies the method signatures you need from UIApplication. It looks like this:

They updateDocumentOpener to accept any implementation of URLOpening.

Now the test can implement its own mock version of URLOpening that it can pass into a DocumentOpener instance.

Then they give an example of how this can be used in a test by creating a mock:

And using the mock in a unit test:

The crowd. Goes. Wild.


Apple definitely just advocated for using a foreign default in their method. The very definition of bastard injection. This left me wondering — why is this bad? Is it so bad? Is there any benefit?

First, the good:

  • The test does not need an instance of UIViewController to test the DocumentOpener
  • The test is non-deterministic
  • The class allows for dependency injection through parameterization
  • The URLOpening protocol decouples the DocumentOpener code from a specific implementation
  • DocumentOpener is simple and elegant to use because you don’t need to pass in a dependency
  • If you want to use a different default you only need to change it in one place

The bad:

  • The DocumentOpener is still coupled to UIApplication
  • It presents a practice that is ill-advised in a different circumstance

A more concrete example of why this is an anti-pattern:

If you still don’t see the big deal, imagine you have a class that manages how any documents are handled in your project; call it DocumentSettingsManager. This is where you’ll handle toggling your document settings.

You have a class DocumentSettings to keep track of your settings and it conforms to a protocol SettingsManageable that has a toggleSetting(key:) function.

Here’s a playground implementation.

Now in the previous example from Apple it didn’t really matter so much that there was a default for UIApplication. You can pretty much always expect UIApplication to be present in an iOS/TVOS app since you’re building it on their platform.

In this example you cannot always expect DocumentSettings to be present.

This pattern makes it hard to:

  • Move all of your settings handling to another module or a CocoaPod
  • Create a more broadly or narrowly scoped settings object to keep track of more or fewer settings.
  • Make DocumentSettingsManager a singleton and still be able to stub out SettingsManageable

Basically as it stands, DocumentSettingsManager and DocumentSettings have nothing to do with each other (aside from sharing similar names). They are very tightly coupled and this violates Inversion of Control which says whatever is using DocumentSettingsManager should be in control of its dependencies.

So why did Apple do this?

I have three theories:

  1. It’s part of a longer-term strategy ease developers into testing. iOS Developers are not known to be the most vocal advocates of testing. Apple may want to bring them up industry standard practices more gradually.
  2. Apple hasn’t decided the best way to do dependency injection. There are a lot of “right” ways to do dependency injection and each of them comes with consequences.
  3. This is “good enough” dependency injection. This strategy will work to make your code more testable 100% of the time. You lose the benefits of making your code more isolated and modular but maybe you don’t care about that. If your only goal is to make your code more testable, this will help you accomplish that goal.

In the end, I hope Apple takes the next step and provides the community with some best practices for doing actual Dependency Injection. Maybe at WWDC 2018. :D

Notes:

http://ilya.puchka.me/dependency-injection-in-swift/ — a very good general overview of DI.

http://www.danielhall.io/a-swift-y-approach-to-dependency-injection — after trying out Swinject and Dip, I think this lightweight container-less approach is probably my favorite. It leverages the power of Swift protocol extensions and just has a better feel to it. (I think)

As always, thanks for reading and please share if you enjoyed it.

Thanks to Dave Batton

Joe Susnick

Written by

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade