Skip to content

Instantly share code, notes, and snippets.

@marcinjackowski
Created September 9, 2018 20:38
Show Gist options
  • Save marcinjackowski/27c3cee02fc4dbf5a0aec414b35a10bb to your computer and use it in GitHub Desktop.
Save marcinjackowski/27c3cee02fc4dbf5a0aec414b35a10bb to your computer and use it in GitHub Desktop.
[DependencyInversion Markdown] #dependencyInversion

Dependency inversion

Dependency inversion is the last letter of SOLID therm. Last position doesn't mean less important than other in my opinion this principle is the most important software design pattern.

General idea

The general idea of this principle is as simple as it is important:

High-level modules, which provide complex logic, should be easily reusable and unaffected by changes in low-level modules, which provide utility features.

In simple words - we shouldn't use class name in any function and variable declaration. Instead, we should use protocols or abstract class.

Based on this idea, Robert C. Martin’s definition of the Dependency Inversion Principle consists of two parts:

A. High-level modules should not depend on low-level modules. Both should depend on abstractions.

B. Abstractions should not depend on details. Details should depend on abstractions.

If it's your first time with DI you probably don't understand those sentences because it sounds incomprehensible. Don't worry! In next step i will show you the difference between traditional and inversion dependency.

Traditional dependency

Imagine that you have to implement screen in your app to fetch user friends from API. In traditional way you will create some service and add property to the class. Example:

https://gist.github.com/f33c834157be62a41d5ab09d42eed748#file-profile-swift

Congrats!🙌🏻 Project manager and client are happy. Everything is working fine. But in one day requirements are changing. You have to change logic of fetch friends from API to database (CoreData) 🤔.

The service variable is of a concrete type SpecificReceiver and you invoke service method directly. This means the high level Profile depends on the low level FriendsService.

Why is this bad? Because if you were to change the FriendsService, you would have to change the Profile as well.

Traditional dependency

So how we should change the code to conform to dependency inversion principle? Let's move to the next step.

Dependency inversion

To design this approach we have to start with an abstraction. You have to create protocol which all service to fetch friends from API or database conform.

https://gist.github.com/0390e7637c716df33f026be7a7adb827#file-friendsworker-swift

Let's redesign Profile class.

https://gist.github.com/31b3c78b642458253ea30c45e3e54b5f#file-profiledi-swift

In this scenario Profile class depends on the FriendsWorker protocol not to a concrete type FriendsService. This approach give us the opportunity to change logic without changing code in Profile class! That's awesome. If you want to fetch friends list form API, create FriendsService class conform to FriendsWorker protocol and inject this object to Profile init! What about fetch friends from Database? How to do it? In the same way!

https://gist.github.com/cc60216ef5c83f26aaa190b2bbcff946#file-final-swift

This is the dependency inversion, as shown in the following diagram. Any service or database just needs to conform to the FriendsWorker protocol in order to be used by Profile.

Dependency inversion

That’s it. Thanks for being awesome and leave a comment below. Clap if you liked it ✌🏻

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment