Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

Dependency Injection Demystified

Jacob BartlettFollowBetter Programming--2ListenShareUnit testing will inherently nudge you towards writing your code in a maintainable way. You’ll separate concerns, design sensible interfaces, and break your code into small, easy-to-reason-about chunks.Modern language features like async/await and functional reactive programming bring incredible ergonomics to our code. However, your tests for this code can be flaky if you’re not careful.I’ve always wanted to write this one since I rarely see it explained well — frankly, it’s a tough set of concepts, and clearly I think a lot of myself if I’m writing a six-part series:Dependency injection, a.k.a. DI, is a handy concept that’s often explained terribly. So-called “senior devs” (i.e., nerds) invoke cryptic jargon like the inversion of control and parrot unhelpful platitudes like DI is a 25-dollar term for a 5-cent concept.I viscerally remember these exact phrases making me feel like both an idiot and an imposter when I was a junior. Hell, maybe when I was a mid.Thanks for reading Jacob’s Tech Tavern! If you subscribe, you get a beer on the house.I was fortunate enough to marry this year and duly abandoned my obligation to stay in shape — so I’ll indulge in a culinary analogy.Think of DI like a fancy restaurant. Your class (or struct, module, etc.) is head chef, and DI is the sous-chef who hands her the ingredients she needs to cook up a storm. By separating the tasks of “gathering ingredients” and “cooking,” our menu is far more testable (I never said the analogy would make sense).Without Dependency Injection here, we’d force the chef to make up the ingredients herself, rush to cook, and leave us with an unmaintainable dumpster fire of a kitchen.In a nutshell, DI divides the duties of “get what I need” and “do what I need to do” like a perfectly sharpened cleaver. Bon appétit!Hold your horses!I could dive right into testing, and tech you how to write basic tests to prove that 1+1= 2, or that the string you hardcoded matches… well, your hardcoded string.I’m starting slow and steady with DI because I want to give you a proper foundation to start from.Essentially, what I’m saying is, you don’t want to brush your teeth (unit test) until after you’ve eaten your veggies (created mocks), and you need to preheat the oven (learn dependency injection) before you can cook your veggies.When you use DI to inject services into your classes, you can create a corresponding buffet of mock services. These conform to the same interface — they look and act like the real deal — but really it’s you pulling the strings.This is where the magic happens:With your mock, you can count how many times the mock’s functions are called, stub out test data to return, or even make it scream ERROR! in digital agony. This control allows you to write test cases for every conceivable outcome.You’ll get a much more in-depth explanation, along with worked examples, in Part II: Mocking like a Pro and Part III: Unit testing async code — the basics.Here’s some sample code I whipped up for an app called Bev, which uses the fantastic PunkAPI to get data on Brewdog beers. It’ll be our gourmet code reference throughout this series.The structure is a basic layered modular architecture (wildly overkill for a project this size, but perfect for future articles).The key layers in our technological lasagna are:Each Layer depends on the layer underneath: With DI, we can serve our class up something to allow smooth communication between the layers.As well as nicely separating your concerns, this technique is extremely important when testing your code — wait for Part II: Mocking like a Pro to see how.I’ve waffled for long enough. It’s time to show you some code.MVVM is the most popular way to structure SwiftUI apps, building our screens with Views that react to state changes in associated View Models.The view model behaves like a movie director, with the view as a stereotypical brain-dead actor. The view model tells the view what to do, what to look like, and how to act; the view’s job is to look pretty and avoid thinking for itself.This view model, at the top layer, is charged with dealing with stuff happening in the “real world,” such as user input and app lifecycle events.Here, we inject the data layer dependency. This means we’re initialising the view model with reference to a Repository — defined in the Data Layer below.When we call loadBeers(), we are instructing the repository to load the data and setting the result as an array of Beer models, which is rendered to the user as the list of tasty beverages.This approach separates the concerns of “creating the beer repository object” and “asking the repository to load some beers.”As mentioned before, the Data Access Layer defines what data we want to get, not how we get it.The data layer is like the kitchen, with the interface as the menu: “I’ll give you this meal when you ask for it.” The UI layer — a hungry patron — doesn’t know or care how the sausage is made.If we wanted to be posh, we’d say the data layer is an abstraction on top of how we get the data.Here, we define the interface with the BeerRepository protocol (an interface if you’re from Kotlin), then implement an object that conforms to that protocol, handling the beer-fetching duties.The protocol defines all the behaviour — and keeps the messy details of how the beer is fetched hidden from the layer above. The implementation of interface, BeerRepositoryImpl, has the API dependency injected.This is the “how” we’re fetching data, and it’s hidden from the protocol definition. The repository asks the API to get the beers and forwards this to the UI layer.In a more complex app, the data access layer can do a lot more. For example, it might have multiple ways of accessing the Beer data.There might be a local database. The data access layer could fetch locally persisted data if it exists, quickly return that to the UI layer, and also request the latest data from the network to update the UI with the most up-to-date info.This hides the complexity of managing these disparate data sources from the layer above.Like a skilled waiter, the Network Layer defines how we get the data. In this case, we request an API to fetch it from the internet. This is the “how” of getting the data we crave.Maintaining my posh demeanour, this is the concrete implementation of our data acquisition — the lowest-level layer.We’re ‘injecting’ the dependency of the URL session, which is the thing that lets us ask for things over the network. The “concrete” implementation of URLSession is handled by Foundation, a fundamental iOS library, which handles the nitty-gritty of sending our humble API request through the internet (at least, sending it to the Transport layer).Congratulations. You made it this far.In the stand-up comedy circuit, the hardest step — the step which gets you ahead of 99% of people — is starting. Reading the following five courses in my tasting menu of async testing will turn you into a true connoisseur.In summary, dependency injection is a technique that allows you to separate the responsibility of gathering the tools an entity needs to do its job from actually using those tools.We learned a little about how we might thoughtfully structure an application with layers and use DI to facilitate data flow between these layers like a well-oiled machine.But you haven’t seen the pièce de résistance of dependency injection until you’ve put it to the test… as in, unit testing.We’ll know more about it in part 2.----2Better ProgrammingLead Mobile Engineer @ Gener8, amateur stand-up comedian, heavy metal vocalist, jaded dadJacob BartlettinBetter Programming--5Sergei SavvovinBetter Programming--13Dmitry KruglovinBetter Programming--34Jacob BartlettinBetter Programming--1Rico FritzscheinLevel Up Coding--25Zhimin Zhan--Julie Perilla GarciainLevel Up Coding--30Moritz KrossinC# Programming--4Love SharmainByteByteGo System Design Alliance--53Daley WilhelminUX Collective--76HelpStatusWritersBlogCareersPrivacyTermsAboutText to speechTeams



This post first appeared on VedVyas Articles, please read the originial post: here

Share the post

Dependency Injection Demystified

×

Subscribe to Vedvyas Articles

Get updates delivered right to your inbox!

Thank you for your subscription

×