Bringing back the SOLID to mobile development, presented to the Houston iPhone User Group.
Bringing the SOLID Back.
Mark Wilkinson - Houston iPhone Developer Meetup
We See Bad, Evil Code
Sometimes, we write it.
• Name some ways to prevent said bad code (coming
• Quit and do something else for monies?
• have someone else write all your code, basically be
a manager or pm?
• Actually learn patterns and practices, learn from
your mistakes (most of us).
Patterns and Practices
That Single Responsibility
That Single Responsibility
• If all you ever get out of the S in SOLID is this, that’s
• So much code could be cleaned up and ﬁxed if it
followed this rule, of having 1 and only 1 job.
• Think of your code when you see it… “YOU HAD ONE
JOB CLASS/Function/Module, ONE JOB.”
• Even Microsoft and Apple example/starter code
Lets start the code…
What we did…
• Made the AppDelegate continue to do only 1 thing.
• The CoreDataHelper does only 1 thing (provide an
interface to the CoreData Stack) and can be accessed
from anywhere with sharedInstance.
• We also introduced the beginning of a pattern that’s
extremely useful in any app architecture…
• It’ll be the D in SOLID, but more on that later.
Now we need a data layer
• Lets say we want to have a friendly interface to
fetching cached data (whether from user input or last
web service call, etc).
• Put that in the CoreDataHelper? Let’s try it out.
• Well, now the CoreDataHelper is promising Weather
days? Sounds like that’s not it’s job.
• Move it out, create a new job for someone else.
Lets ﬁx it.
Now the source of Data is a
• CoreDataHelper returns to doing 1 job.
• New WeatherDataSource promises to do 1 job, give
back Weather data. It will now use the
• The abstraction now lets the ViewController worry
about getting actual WeatherData and not manipulating
the CD Stack.
• Wait… Who is going to give the ViewController the
The D in SOLID
• Now we’re skipping around, that’s okay
• Dependencies keep the modules/parts safely
independent while continuing to do their 1 intended
• WeatherDataSource is now a dependency of
• CoreDataHelper is now a dependency of
Lets inject it instead.
What we did
• Injected (or handed) the ViewController an instance of the
WeatherDataSource, without having IT instantiate itself.
• We also handed WeatherDataSource an instance of
CoreDataHelper for the same reasons.
• Notice there’s a chain here, of one class handing another
the dependencies it needs.
• This is called Dependency Injection and it helps insure
that classes only worry about what they promise to do
(that 1 thing) any other work is done by its dependencies.
• ViewController got it through Property Injection, the
WeatherDataSource through Initializer Injection.
• Either is ﬁne, use whatever suits your needs best.
• Usually, because of storyboards, ViewControllers will
need to get it through property injection, all other
classes though that can be initialized, should get it
through their inits.
Introduce the I in SOLID
• Now lets build the Networking layer and see why the I
or Interfaces are needed.
What we did.
• Created a client class to use NSURLSession that at
some point will return data from a service.
• Lets imagine the endpoint isn’t ready yet (cause that’s
never happened in a mobile project before).
• Best case, and you should do this at the start of
• In most instances, you’ll get JSON back, so write
• Best bet is to keep a ﬁle handy in the project with
JSON that you believe will come back from your
• return that JSON as Data() in your fake client.
What we did.
• WeatherDataSource will use a WebClient either real or
fake to get back Data, from there it’ll parse and form
• The WebClient will be injected into the
WeatherDataSource as well.
• In doing this the WeatherDataSource will be the glue
between CoreDataHelper and the WebClient
• From there the ViewController will get back ﬁrst a
cached set of data (from the stack), then when the
completion block completes, it’ll get updated data
A few more things…
• Notice the AppDelegate is now pretty much handling
the injections of dependencies two levels beneath it.
• Also notice we’re hardcoding the dependency to be a
FakeWebClient, not a common client that could be
either real or fake.
• I know the urge… subclass, but don’t, just don’t.
avoid Subclassing with this pattern at ALL COSTS.
What should we do then?
• Notice the FakeWebClient and the WebClient adhere
to a common interface:
• Here’s our I in SOLID, we need an Inteface.
• Of course in Swift and Objective-C they’re protocols.
Lets use a protocol instead
• Now the webClients adhere to the Client protocol.
• The protocol/interface can be injected instead,
• This makes it easier to swap out the fake from the real
client by changing 1 line.
• This is the selling point of Dependency Injection, it’s
easy to swap out pieces for completely different
behaviors (even at runtime) with minimal effort.
But wait, we’re not done.
• CoreData is a hefty stack.
• What if for faster prototyping we need something
simpler, like NSUserDefaults (UserDefaults now in
• Hmm… sounds like a familiar situation.
Build those LEGO pieces.
What we did.
• WeatherDataSource still uses a Client interface, but
now uses a new interface to persisted data.
• The Persistence protocol will be injected into the
WeatherDataSource instead of the speciﬁc
• In doing this the WeatherDataSource no longer needs
to know about the CoreData stack, just a layer
persisting to disk.
• Again, we’re following the rules of modules knowing
less and less and doing only what they need to do.
Best way to imagine
The O in SOLID
Exactly what we did
• We extended functionality of the app, instead of
• By using protocols, new implementations like
UserDefaults instead of CoreData could be swapped
out (again at runtime if need be).
• The app didn’t change, it was just enhanced with more
capabilities for doing the same task (persisting data, or
• AppDelegate shouldn’t worry about injecting, that
should be a job for someone else.
• In comes a Dependency Resolver.
• A class that simply registers protocols with
implementations (with a Dictionary).
• Even better, create Xcode build schemes, one for
fakes, one for reals, where certain lines of code in the
Resolver are run for each.
• We created a better App stack.
• Again, imagine Lego pieces and not lines of code.
• Use Design Patterns only when it suits the
• The Dependency Resolver is a good example of
the Factory Pattern.