Slaying Sacred Cows: Deconstructing Dependency Injection
-
Upload
tomer-gabel -
Category
Engineering
-
view
573 -
download
2
Transcript of Slaying Sacred Cows: Deconstructing Dependency Injection
![Page 1: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/1.jpg)
Slaying Sacred Cows:Deconstructing
Dependency Injection
Tomer Gabel
![Page 2: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/2.jpg)
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
![Page 3: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/3.jpg)
Semantics
When I say “dependency injection”, you’re probably thinking of this:
public class BillingModule extends AbstractModule {@Overrideprotected void configure() {bind(TransactionLog.class).to(DatabaseTransactionLog.class);bind(CreditCardProcessor.class).to(PaypalCreditCardProcessor.class);
}}
So did I.
![Page 4: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/4.jpg)
1. THE “D” IN SOLIDImage: Peter von Bagh, “Just Frozen Water” via Flickr (CC0 1.0 Public Domain)
![Page 5: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/5.jpg)
Back to Basics
• Single responsibility
• Open/closed
• Liskov substitution principle
• Interface segregation
• Dependency inversion
Image: Michael Feathers via MozaicWorks
![Page 6: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/6.jpg)
Back to Basics
• Single responsibility
• Open/closed
• Liskov substitution principle
• Interface segregation
• Dependency inversion
Image: Michael Feathers via MozaicWorks
![Page 7: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/7.jpg)
Dependency Inversion
• A simple idea
• Given a dependency:– A must not depend on B
directly
OAuthProvider
MysqlUserStore
“A”
“B”
![Page 8: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/8.jpg)
Dependency Inversion
• A simple idea
• Given a dependency:– A must not depend on B
directly
– Instead, A depends onan abstraction of B
– B depends on thesame abstraction
OAuthProvider
MysqlUserStore
UserStore
class
class
interface
“A”
“B”
![Page 9: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/9.jpg)
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 ofone century is the
common senseof the next.”
-- Henry Ward Beecher
Image: Mathew Brady, “Henry Ward Beecher” via Library of Congress (Public Domain)
![Page 10: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/10.jpg)
2. DECOUPLEME SOFTLY
Image: Mark Menzies, “Le Chav Sportif” via Flickr (CC-BY-NC-SA 2.0)
![Page 11: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/11.jpg)
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;
}
}
![Page 12: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/12.jpg)
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) {
// ...
}
}
![Page 13: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/13.jpg)
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)
![Page 14: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/14.jpg)
3. THINGS GET HAIRY
Image: Matt Acevedo, “Alpaca” via Flickr (CC-BY 2.0)
![Page 15: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/15.jpg)
Inversion of Control
• IoC is not a pattern
• It’s a design principle
• Traditionally:
– “Main” flow calls intocomponents
– Control flows back to the “main” flow
Main (entry point)
• Configuration
• Bootstrapping
Event loop
• Dequeue
• Dispatch
Event handler
• Act on event
• Done
![Page 16: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/16.jpg)
Inversion of Control
• IoC is not a pattern
• It’s a design principle
• With IoC:
– Control is surrendered to a container
– Container calls intocomponents
Main (entry point)
• Setup
IoC container
• Bootstrapping/wiring
• Event loop
Event handler
• Act on event
• Done
![Page 17: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/17.jpg)
Inversion of Control
• IoC means many things
– Servlet containers
– Plugin systems
– Stream computing
– “DI” containers
• We’ll focus on the latter
![Page 18: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/18.jpg)
IoC & DI
• Consider Spring/Guice
– A runtime container
– Manages components
– … including lifecycle
– … and automatic wiring
Image: ImgFlip
![Page 19: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/19.jpg)
Perceived Benefits
• Why use a container?
– Simplify wiring
– Simplify testing
– Dynamic configuration
– Support for AOP
• Let’s consider each
Image: ImgFlip
![Page 20: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/20.jpg)
Perceived Benefits
• Why use a container?
– Simplify wiring
– Simplify testing
– Dynamic configuration
– Support for AOP
• Let’s consider each
Image: ImgFlip
![Page 21: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/21.jpg)
Simplified Wiringclass 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);
}
![Page 22: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/22.jpg)
Simplified Wiringclass 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);
}
}
![Page 23: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/23.jpg)
Simplified Wiringclass 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);
}
}
![Page 24: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/24.jpg)
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)
![Page 25: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/25.jpg)
Simplify Testing
• Proponents will tell you:
1. Bring up a container
2. Swap out components
3. Bob’s your uncle
![Page 26: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/26.jpg)
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.
![Page 27: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/27.jpg)
Simplify Testing
• Congratulations!
• You’re doing
deconstructive
testing
![Page 28: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/28.jpg)
Wha-huh?
Constructive testing Deconstructive testing
MysqlEventStore
DataSource
SiteService
MysqlEventStore
DataSource
MysqlSnapshotStore
DataSource
Clock
![Page 29: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/29.jpg)
Wha-huh?
Constructive testing Deconstructive testing
MysqlEventStore
DataSource
SiteService
MysqlEventStore
DataSource
MockSnapshotStoreFixedClock
![Page 30: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/30.jpg)
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)
![Page 31: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/31.jpg)
IN SUMMARY…
IoC is a solution in search of a problem
![Page 32: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/32.jpg)
… except …
• With huge codebases
– Read: “Monoliths”
– Read: “Enterprise”
• Enables a tradeoff
– Developer discipline
– Code coherence, simplicity, navigability
![Page 33: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/33.jpg)
… 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.
![Page 34: Slaying Sacred Cows: Deconstructing Dependency Injection](https://reader034.fdocuments.net/reader034/viewer/2022051710/5a64a4fd7f8b9a2c568b6967/html5/thumbnails/34.jpg)
QUESTIONS?Thank you for listening
@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.