Slide 1

Slide 1 text

Slaying Sacred Cows: Deconstructing Dependency Injection Tomer Gabel

Slide 2

Slide 2 text

Full Disclosure • I was never a fan • I tried researching this properly… – Read a ton of material – Interviewed people – Sat and thought • Still turned out a rant Image: ImgFlip

Slide 3

Slide 3 text

Semantics When I say “dependency injection”, you’re probably thinking of this: public class BillingModule extends AbstractModule { @Override protected void configure() { bind(TransactionLog.class).to(DatabaseTransactionLog.class); bind(CreditCardProcessor.class).to(PaypalCreditCardProcessor.class); } } So did I.

Slide 4

Slide 4 text

1. THE “D” IN SOLID Image: Peter von Bagh, “Just Frozen Water” via Flickr (CC0 1.0 Public Domain)

Slide 5

Slide 5 text

Back to Basics • Single responsibility • Open/closed • Liskov substitution principle • Interface segregation • Dependency inversion Image: Michael Feathers via MozaicWorks

Slide 6

Slide 6 text

Back to Basics • Single responsibility • Open/closed • Liskov substitution principle • Interface segregation • Dependency inversion Image: Michael Feathers via MozaicWorks

Slide 7

Slide 7 text

Dependency Inversion • A simple idea • Given a dependency: – A must not depend on B directly OAuthProvider MysqlUserStore “A” “B”

Slide 8

Slide 8 text

Dependency Inversion • A simple idea • Given a dependency: – A must not depend on B directly – Instead, A depends on an abstraction of B – B depends on the same abstraction OAuthProvider MysqlUserStore UserStore class class interface “A” “B”

Slide 9

Slide 9 text

The Verdict • Dependency inversion is old hat – Seems obvious now – First postulated by Uncle Bob in 1994 (!) • We’ve come a long way since! “The philosophy of one century is the common sense of the next.” -- Henry Ward Beecher Image: Mathew Brady, “Henry Ward Beecher” via Library of Congress (Public Domain)

Slide 10

Slide 10 text

2. DECOUPLE ME SOFTLY Image: Mark Menzies, “Le Chav Sportif” via Flickr (CC-BY-NC-SA 2.0)

Slide 11

Slide 11 text

Dependency Injection • Let’s assume SOLID… • Given a dependency: – Who owns it? – What is the lifecycle? • Traditionally: – The depending service manages everything class UserService { private UserStore store = new MysqlUserStore(Config.JDBC_URL); bool authenticate(String userToken) { UserContext user = store.lookup(userToken); return user != null ? user.isActive() : false; } }

Slide 12

Slide 12 text

Dependency Injection • DI stipulates: – Services should not build dependencies – But instead receive them – Dependencies are state • It does not stipulate how to implement this class UserService { private UserStore store; public UserService(UserStore store) { this.store = store; } bool authenticate(String userToken) { // ... } }

Slide 13

Slide 13 text

The Verdict • Dependency injection is good • If taken at face value: – No frameworks – No containers – No reflection – Simply common sense Image: Tomas Catelazo via Wikimedia Commons (CC-BY-SA 4.0)

Slide 14

Slide 14 text

3. THINGS GET HAIRY Image: Matt Acevedo, “Alpaca” via Flickr (CC-BY 2.0)

Slide 15

Slide 15 text

Inversion of Control • IoC is not a pattern • It’s a design principle • Traditionally: – “Main” flow calls into components – Control flows back to the “main” flow Main (entry point) • Configuration • Bootstrapping Event loop • Dequeue • Dispatch Event handler • Act on event • Done

Slide 16

Slide 16 text

Inversion of Control • IoC is not a pattern • It’s a design principle • With IoC: – Control is surrendered to a container – Container calls into components Main (entry point) • Setup IoC container • Bootstrapping/wiring • Event loop Event handler • Act on event • Done

Slide 17

Slide 17 text

Inversion of Control • IoC means many things – Servlet containers – Plugin systems – Stream computing – “DI” containers • We’ll focus on the latter

Slide 18

Slide 18 text

IoC & DI • Consider Spring/Guice – A runtime container – Manages components – … including lifecycle – … and automatic wiring Image: ImgFlip

Slide 19

Slide 19 text

Perceived Benefits • Why use a container? – Simplify wiring – Simplify testing – Dynamic configuration – Support for AOP • Let’s consider each Image: ImgFlip

Slide 20

Slide 20 text

Perceived Benefits • Why use a container? – Simplify wiring – Simplify testing – Dynamic configuration – Support for AOP • Let’s consider each Image: ImgFlip

Slide 21

Slide 21 text

Simplified Wiring class MyApp { DBI db = new DBIFactory().build(...); EventStore eventStore = new MysqlEventStore(db); SnapshotStore snapshotStore = new MysqlSnapshotStore(db); Clock clock = Clock.systemUTC(); SiteService siteService = new DefaultSiteService( eventStore, snapshotStore, clock); }

Slide 22

Slide 22 text

Simplified Wiring class MyApp { DBI db = new DBIFactory().build(...); EventStore eventStore = new MysqlEventStore(db); SnapshotStore snapshotStore = new MysqlSnapshotStore(db); Clock clock = Clock.systemUTC(); SiteService siteService = new DefaultSiteService( eventStore, snapshotStore, clock); } class MyAppModule extends AbstractModule { @Override protected void configure() { bind(DBI.class).toProvider(...); bind(EventStore.class) .to(MysqlEventStore.class); bind(SnapshotStore.class) .to(MysqlSnapshotStore.class); bind(Clock.class) .toProvider(Clock::systemUTC); bind(SiteService.class) .to(DefaultSiteService.class); } }

Slide 23

Slide 23 text

Simplified Wiring class MyApp { DBI db = new DBIFactory().build(...); EventStore eventStore = new MysqlEventStore(db); SnapshotStore snapshotStore = new MysqlSnapshotStore(db); Clock clock = Clock.systemUTC(); SiteService siteService = new DefaultSiteService( eventStore, snapshotStore, clock); } class MyAppModule extends AbstractModule { @Override protected void configure() { bind(DBI.class).toProvider(...); bind(EventStore.class) .to(MysqlEventStore.class); bind(SnapshotStore.class) .to(MysqlSnapshotStore.class); bind(Clock.class) .toProvider(Clock::systemUTC); bind(SiteService.class) .to(DefaultSiteService.class); } }

Slide 24

Slide 24 text

Simplified Wiring • No tangible benefit! – Wiring is trivial • Real, tangible downsides – Startup time – Code navigability – Dynamic/reflective magic Image: André Nordstrand, “Loss of common sense” via Flickr (CC-BY-NC 2.0)

Slide 25

Slide 25 text

Simplify Testing • Proponents will tell you: 1. Bring up a container 2. Swap out components 3. Bob’s your uncle

Slide 26

Slide 26 text

Simplify Testing deconstruction (source: dictionary.com) Noun 1. a technique of literary analysis that regards meaning as resulting from the differences between words rather than their reference to the things they stand for.

Slide 27

Slide 27 text

Simplify Testing • Congratulations! • You’re doing deconstructive testing

Slide 28

Slide 28 text

Wha-huh? Constructive testing Deconstructive testing MysqlEventStore DataSource SiteService MysqlEventStore DataSource MysqlSnapshotStore DataSource Clock

Slide 29

Slide 29 text

Wha-huh? Constructive testing Deconstructive testing MysqlEventStore DataSource SiteService MysqlEventStore DataSource MockSnapshotStore Fixed Clock

Slide 30

Slide 30 text

Simplify Testing • This is a bad idea – Hard to reason about – Have to deal with subtle interactions – Does not reflect your unit structure • Most importantly… – Leads to poor design! Image: Viewminder, “Strange Bedfellows” via Flickr (CC-BY-NC-ND 2.0)

Slide 31

Slide 31 text

IN SUMMARY… IoC is a solution in search of a problem

Slide 32

Slide 32 text

… except … • With huge codebases – Read: “Monoliths” – Read: “Enterprise” • Enables a tradeoff – Developer discipline – Code coherence, simplicity, navigability

Slide 33

Slide 33 text

… except … • With huge codebases – Read: “Monoliths” – Read: “Enterprise” • Enables a tradeoff – Developer discipline – Code coherence, simplicity, navigability Corollary: If you’re seeing benefit from IoC, your codebase is already out of control.

Slide 34

Slide 34 text

QUESTIONS? Thank you for listening tomer@tomergabel.com @tomerg http://engineering.wix.com Sample Project: http://tinyurl.com/event-sourcing-sample This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.