Unlock This Episode
Our Free plan includes 1 subscriber-only episode of your choice, plus weekly updates from our newsletter.
Introduction
Today we’re going to revisit a topic we’ve talked about in the past: side effects. We introduced the topic in our second episode with a deep dive on how side effects are kind of like hidden inputs and outputs to our functions, demonstrating how they make testing difficult and how they can introduce subtle bugs. Side effects are complicated and require attention.
The examples in that episode were a bit contrived, so today we’re going to look at code that’s a bit more real-world and explore how we can extract and control side effects quickly and painlessly.
This is a method we’ve used in production again and again, and it’s proven itself over time. We hope that others get the same benefit!
Subscribe to Point-Free
Access this episode, plus all past and future episodes when you become a subscriber.
Already a subscriber? Log in
Exercises
Today’s episode was powered by playground-driven development, but we’re talking about real-world code and that kind of code usually lives in an application target. The following exercises explore how to apply playground-driven development to actual application code.
-
Download the episode code and copy it into a new iOS project called “Repos”. The app should display the repos navigation controller as the window’s root view controller.
-
Add a framework target to the project called “ReposKit” and embed it in the Repos app. Move all of our application code (aside from the app delegate) to ReposKit. Make sure that the source files are members of the framework target, not the app target. Repos should
import ReposKit
into the app delegate in order to access and instantiate theReposViewController
. Build the application to make sure everything still works (you will need to make some types and functionspublic
). -
Create an iOS playground and drag it into your app project. Import ReposKit, instantiate a
ReposViewController
, and set it as the playground’s live view. You can use our original playground code as a reference. -
Swap out the
Current
, live world for ourmock
one. This playground page can now act as a living reference for this screen! You can modify themock
to test different states, and to test changes to the view controller, you can rebuild ReposKit.
-
There are a few dependencies in the application that we didn’t cover. Let’s explore controlling them over a couple exercises.
-
The analytics client is calling out to several singletons:
Bundle.main
,UIScreen.main
, andUIDevice.current
. Extract these dependencies toEnvironment
. What are some advantages of controlling these dependencies? -
DateComponentsFormatter
can produce different strings for different languages and locales, but defaults to the device locale. Extract this dependency toEnvironment
, control it on the formatter, and demonstrate how mockingCurrent
allows you to test formatting over different languages and locales.
-
References
Structure and Interpretation of Swift Programs
Colin Barrett • Tuesday Dec 15, 2015Colin Barrett discussed the problems of dependency injection, the upsides
of singletons, and introduced the Environment
construct at Functional Swift 2015.
This was the talk that first inspired us to test this construct at Kickstarter and refine it over the years and
many other code bases.
How to Control the World
Stephen Celis • Monday Sep 24, 2018Stephen gave a talk on our Environment
-based approach to dependency injection at NSSpain 2018. He starts
with the basics and slowly builds up to controlling more and more complex dependencies.