(coming from you): • 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).
out of the S in SOLID is this, that’s fine. • So much code could be cleaned up and fixed 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 violates this.
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.
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.
CoreDataHelper returns to doing 1 job. • New WeatherDataSource promises to do 1 job, give back Weather data. It will now use the CoreDataHelper. • 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 WeatherDataSource?
okay • Dependencies keep the modules/parts safely independent while continuing to do their 1 intended job. • WeatherDataSource is now a dependency of ViewController • CoreDataHelper is now a dependency of WeatherDataSource.
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.
WeatherDataSource through Initializer Injection. • Either is fine, 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.
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 EVERY app…
so write some JSON. • Best bet is to keep a file handy in the project with JSON that you believe will come back from your service. • return that JSON as Data() in your fake client.
real or fake to get back Data, from there it’ll parse and form into NSManagedObjects. • 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 first a cached set of data (from the stack), then when the completion block completes, it’ll get updated data
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.
• The protocol/interface can be injected instead, increasing flexibility • This makes it easier to swap out the fake from the real client by changing 1 line.
stack. • What if for faster prototyping we need something simpler, like NSUserDefaults (UserDefaults now in Swift 3) • Hmm… sounds like a familiar situation.
but now uses a new interface to persisted data. • The Persistence protocol will be injected into the WeatherDataSource instead of the specific CoreDataHelper. • 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.
app, instead of changing it. • 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 fetching JSON)
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.
imagine Lego pieces and not lines of code. • Use Design Patterns only when it suits the situation. • The Dependency Resolver is a good example of the Factory Pattern.