using and contributing to the next guice

73
Using and contributing to the next Guice Adrian Cole @adrianfcole #netflixoss http://www.linkedin.com/in/ adrianforrestcole

Upload: adrian-cole

Post on 27-May-2015

1.833 views

Category:

Technology


1 download

DESCRIPTION

This overviews Guice and its successor Dagger in context of usage in NetflixOSS

TRANSCRIPT

Page 1: Using and contributing to the next Guice

Using and contributing to the next Guice

Adrian Cole@adrianfcole #netflixoss

http://www.linkedin.com/in/adrianforrestcole

Page 2: Using and contributing to the next Guice

•Introduction

•Guice

•Guice at Netflix

•Dagger

•Dagger at Netflix

•Wrapping up

Page 3: Using and contributing to the next Guice

Adrian• cloud guy at Netflix• founded jclouds• focus on (small) libraries

Page 4: Using and contributing to the next Guice

thanks @jessewilson

• Guice• javax.inject• Android Core Libraries• Dagger

Page 5: Using and contributing to the next Guice

•Introduction

•Guice

•Guice at Netflix

•Dagger

•Dagger at Netflix

•Wrapping up

Page 6: Using and contributing to the next Guice

Wiring With Guice!

Page 7: Using and contributing to the next Guice

(cc) creative commons from flickr.com/photos/uscpsc/7894303566/

Page 8: Using and contributing to the next Guice

class Thermosiphon implements Pump { private final Heater heater;

Thermosiphon(Heater heater) { this.heater = heater; }

@Override public void pump() { if (heater.isHot()) { System.out.println("=> => pumping => =>"); } }}

Page 9: Using and contributing to the next Guice

class Thermosiphon implements Pump { private final Heater heater;

@Inject Thermosiphon(Heater heater) { this.heater = heater; } ...}

Declare Dependencies

Page 10: Using and contributing to the next Guice

class CoffeeMaker {

@Inject Heater heater; @Inject Pump pump; ...}

Declare Dependencies

Page 11: Using and contributing to the next Guice

class DripCoffeeModule extends AbstractModule {

@Overrides void configure() { bind(Heater.class).to(ElectricHeater.class);

bind(Pump.class).to(Thermosiphon.class); }}

Satisfy Dependencies

Page 12: Using and contributing to the next Guice

class CoffeeApp {

public static void main(String[] args) {

Injector injector

= Guice.createInjector(new

DripCoffeeModule());

CoffeeMaker coffeeMaker

= injector.getInstance(CoffeeMaker.class);

coffeeMaker.brew(); }

}

Build the Injector

Page 13: Using and contributing to the next Guice

•Introduction

•Guice

•Guice at Netflix

•Dagger

•Dagger at Netflix

•Wrapping up

Page 14: Using and contributing to the next Guice

Netflix uses lots of Guice• Governator– Governate (verb) to wire together an app so that

it implicitly bootstraps and exposes its lifecycle.

• Karyon– Karyonate (verb) unpronouncable… so– Blueprint for a web app or REST service

Page 15: Using and contributing to the next Guice

Governator Bootstrap

• Extends Guice– classpath scanning and automatic binding– lifecycle management– configuration to field mapping– field validation– parallelized object warmup

• Some overlap with Apache Onami

Page 16: Using and contributing to the next Guice

class DieselHeater implements Heater {

...

@PostConstruct void startEngine() {

// mmm… exhaust with coffee.. }}

Define @PostConstruct

Page 17: Using and contributing to the next Guice

class CoffeeApp {

public static void main(String[] args) {

Injector injector

= LifeCycleInjector.createInjector(new

DripCoffeeModule());

CoffeeMaker coffeeMaker

= injector.getInstance(CoffeeMaker.class);

coffeeMaker.brew(); }

}

Build the Injector

Page 18: Using and contributing to the next Guice

Karyon• Web Service Blueprint– Extends Governator, Guice Servlet– Built-in Admin Console– Pluggable Web Resources– Cloud-Ready hooks

@Application has @Components Usually has a HealthCheckHandler

Page 19: Using and contributing to the next Guice

@Component(disableProperty = “killswitch”)class DieselHeater implements Heater {

...

@PostConstruct void startEngine() {

// mmm… exhaust with coffee.. }}

Define @Component

Page 20: Using and contributing to the next Guice

appName.properties com.netflix.karyon.server.base.packages= com.foo.appName.components

Check config

Page 21: Using and contributing to the next Guice

A Cloud Native Open Source Platform

@adrianfcole #netflixoss

More?

Page 22: Using and contributing to the next Guice

•Introduction

•Guice

•Guice at Netflix

•Dagger

•Dagger at Netflix

•Wrapping up

Page 23: Using and contributing to the next Guice

Dagger

Slides by Jesse Wilson from Square

A fast dependency injector for Android and Java.

Page 24: Using and contributing to the next Guice

•Dagger

–Motivation

–Using Dagger

–Inside Dagger

Page 25: Using and contributing to the next Guice

Motivation for Dependency Injection

• Decouple concrete from concrete• Uniformity

Page 26: Using and contributing to the next Guice

Dependency InjectionChoices

• PicoContainer• Spring• Guice• javax.inject

Page 27: Using and contributing to the next Guice

(cc) creative commons from flickr.com/photos/getbutterfly/6317955134/

Page 28: Using and contributing to the next Guice

(cc) creative commons from flickr.com/photos/wikidave/2988710537/

Page 29: Using and contributing to the next Guice

We still love you, Froyo

• Eager vs. lazy graph construction• Reflection vs. codegen

Page 30: Using and contributing to the next Guice

typicalprogrammer.com/?p=143

“I didn’t really expect anyone to use [git] because it’s so hard to use, but that turns out to be its big appeal.

No technology can ever be too arcane or complicated for the black t-shirt crowd.”

–Linus Torvalds

Page 31: Using and contributing to the next Guice

No black t-shirt necessary

Page 32: Using and contributing to the next Guice

(cc) creative commons from flickr.com/photos/mike_miley/5969110684/

Page 33: Using and contributing to the next Guice

• Know everything at build time.

• Easy to see how dependencies are used & satisfied

Page 34: Using and contributing to the next Guice

Motivation for Dagger

• It's like Guice, but with speed instead of features

• Simple• Predictable

also...

Page 35: Using and contributing to the next Guice

•Dagger

–Motivation

–Using Dagger

–Inside Dagger

Page 36: Using and contributing to the next Guice

DirectedAcyclicGraph

DAGger.

Page 37: Using and contributing to the next Guice

(cc) creative commons from flickr.com/photos/uscpsc/7894303566/

Page 38: Using and contributing to the next Guice

class Thermosiphon implements Pump { private final Heater heater;

Thermosiphon(Heater heater) { this.heater = heater; }

@Override public void pump() { if (heater.isHot()) { System.out.println("=> => pumping => =>"); } }}

Page 39: Using and contributing to the next Guice

class Thermosiphon implements Pump { private final Heater heater;

@Inject Thermosiphon(Heater heater) { this.heater = heater; } ...}

Declare Dependencies

Page 40: Using and contributing to the next Guice

class CoffeeMaker {

@Inject Heater heater; @Inject Pump pump; ...}

Declare Dependencies

Page 41: Using and contributing to the next Guice

@Module(injects = CoffeeMakerApp.java)class DripCoffeeModule {

@Provides Heater provideHeater() { return new ElectricHeater(); }

@Provides Pump providePump(Thermosiphon pump) { return pump; }}

Satisfy Dependencies

Page 42: Using and contributing to the next Guice

class CoffeeApp {

public static void main(String[] args) {

ObjectGraph objectGraph

= ObjectGraph.create(new DripCoffeeModule());

CoffeeMaker coffeeMaker

= objectGraph.get(CoffeeMaker.class);

coffeeMaker.brew(); }

}

Build the Graph

Page 43: Using and contributing to the next Guice

Neat features

• Lazy<T>• Module overrides• Multibindings

Page 44: Using and contributing to the next Guice

class GridingCoffeeMaker {

@Inject Lazy<Grinder> lazyGrinder;

public void brew() {

while (needsGrinding()) { // Grinder created once and cached.

Grinder grinder = lazyGrinder.get()

grinder.grind(); } }}

Lazy<T>

Page 45: Using and contributing to the next Guice

@Module( includes = DripCoffeeModule.class,

injects = CoffeeMakerTest.class,

overrides = true ) static class TestModule {

@Provides @Singleton Heater provideHeater() { return Mockito.mock(Heater.class); }

}

Module Overrides

Page 46: Using and contributing to the next Guice

@Moduleclass TwitterModule { @Provides(type=SET) SocialApi provideApi() { ... }}@Moduleclass GooglePlusModule { @Provides(type=SET) SocialApi provideApi() { ... }}...@Inject Set<SocialApi>

Multibindings

Page 47: Using and contributing to the next Guice

•Dagger

–Motivation

–Using Dagger

–Inside Dagger

Page 48: Using and contributing to the next Guice

Graphs!

Page 49: Using and contributing to the next Guice

Creating Graphs

• Compile time– annotation processor

• Runtime– generated code loader– reflection

Page 50: Using and contributing to the next Guice

Using Graphs

• Injection• Validation• Graphviz!

Page 51: Using and contributing to the next Guice

But how?

• Bindings have names like“com.squareup.geo.LocationMonitor”

• Bindings know the names of their dependencies, like“com.squareup.otto.Bus”

Page 52: Using and contributing to the next Guice

final class CoffeeMaker$InjectAdapter extends Binding<CoffeeMaker> {

private Binding<Heater> f0; private Binding<Pump> f1;

public CoffeeMaker$InjectAdapter() { super("coffee.CoffeeMaker", ...); }

public void attach(Linker linker) { f0 = linker.requestBinding("coffee.Heater", coffee.CoffeeMaker.class); f1 = linker.requestBinding("coffee.Pump", coffee.CoffeeMaker.class); }

public CoffeeMaker get() { coffee.CoffeeMaker result = new coffee.CoffeeMaker(); injectMembers(result); return result; }

public void injectMembers(CoffeeMaker object) { object.heater = f0.get(); object.pump = f1.get(); }

public void getDependencies(Set<Binding<?>> bindings) { bindings.add(f0); bindings.add(f1); }

}

Page 53: Using and contributing to the next Guice

Validation

• Eager at build time• Lazy at runtime

Page 54: Using and contributing to the next Guice

dagger-compiler

(cc) creative commons from flickr.com/photos/discover-central-california/8010906617

Page 55: Using and contributing to the next Guice

Built into javac

Foolishly easy to use. Just put dagger-compiler on your classpath!

javax.annotation.processing

Page 56: Using and contributing to the next Guice

It’s a hassle(for us)

• Coping with prebuilt .jar files• Versioning• Testing

Page 57: Using and contributing to the next Guice

... and it’s limited(for you)

• No private or final field access• Incremental builds are imperfect• ProGuard

Page 58: Using and contributing to the next Guice

... but it’s smoking fast!(for your users)

• Startup time for Square Wallet on one device improved from ~5 seconds to ~2 seconds

Page 59: Using and contributing to the next Guice

Different Platforms are Different

• HotSpot• Android• GWT

Page 60: Using and contributing to the next Guice

HotSpot:Java on the Server

• The JVM is fast• Code bases are huge

Page 61: Using and contributing to the next Guice

Android

• Battery powered• Garbage collection causes jank• Slow reflection, especially on older devices• Managed lifecycle

Page 62: Using and contributing to the next Guice

GWT• Code size really matters• Compiler does full-app optimizations• No reflection.

github.com/tbroyer/sheath

Page 63: Using and contributing to the next Guice

API Designin the GitHub age

Forking makes it easy to stay small & focused

Page 64: Using and contributing to the next Guice

public @interface Inject {}

public @interface Named { String value() default "";}

public interface Provider { T get();}public @interface Qualifier {}public @interface Scope {}public @interface Singleton {}

javax.inject

Page 65: Using and contributing to the next Guice

public interface Lazy<T> {

T get();}

public interface MembersInjector<T> {

void injectMembers(T instance);}

public final class ObjectGraph {

public static ObjectGraph create(Object... modules);

public ObjectGraph plus(Object... modules);

public void validate();

public void injectStatics();

public <T> T get(Class type);

public <T> T inject(T instance);}

public @interface Module {

Class[] injects() default { }; Class[] staticInjections() default { }; Class[] includes() default { }; Class addsTo() default Void.class; boolean overrides() default false; boolean complete() default true; boolean library() default true;}

public @interface Provides {

enum Type { UNIQUE, SET }

Type type() default Type.UNIQUE;}

dagger

Page 66: Using and contributing to the next Guice

•Introduction

•Guice

•Guice at Netflix

•Dagger

•Dagger at Netflix

•Wrapping up

Page 67: Using and contributing to the next Guice

PORTABLE CONTROL OF DNS CLOUDS

Page 68: Using and contributing to the next Guice

@Provides @SingletonRoute53 route53(Feign feign, Route53Target target) {

return feign.newInstance(target);}

Dependencies are HTTP Targets

Page 69: Using and contributing to the next Guice

Portable implementations

class Route53ZoneApi implements ZoneApi {

@Inject Route53 route53; ...}

Page 70: Using and contributing to the next Guice

•Introduction

•Guice

•Guice at Netflix

•Dagger

•Dagger at Netflix

•Wrapping up

Page 71: Using and contributing to the next Guice

• Still the best choice for many apps• Broad ecosystem and stable core• May soon be able to mix & match with

Dagger

Guice

Page 72: Using and contributing to the next Guice

• Great for libraries• Extension averse, feature conservative• Friendly forks

Dagger

Page 73: Using and contributing to the next Guice

Takeaway

Dagger is a leaner version of Guice, suitable for libraries.

Fork-friendly doesn’t mean don’t collaborate.

http://square.github.io/dagger/https://groups.google.com/forum/#!forum/dagger-discuss

http://www.linkedin.com/in/adrianforrestcole@adrianfcole #netflixoss