Clean code via dependency injection + guice

97
Clean code via Dependency Injection + Guice @jordi9 9 noviembre 2012 bit.ly/devfest12cleancode

description

From Google DevFest 2012, Barcelona

Transcript of Clean code via dependency injection + guice

Page 1: Clean code via dependency injection + guice

Clean code via Dependency Injection + Guice

@jordi99 noviembre 2012bit.ly/devfest12cleancode

Page 2: Clean code via dependency injection + guice

... shameless self-promotion bro!

Page 3: Clean code via dependency injection + guice

About you

Gang of Four?Legacy Code?Dependency Injection?Monkey patching?Monkey testing?Unit testing?TDD / BDD?Agile? XP? Scrum what?

Page 4: Clean code via dependency injection + guice

S.O.L.I.D.

Single responsibility principleOpen/closed principleLiskov substitution principleInterface segregation principleDependency inversion principle

Page 5: Clean code via dependency injection + guice

Legacy code is code without test

Page 6: Clean code via dependency injection + guice

Fast Run hundreds or thousands per second

Isolated Failure reasons become obvious

Reliable Run repeatedly in any order, any time

Self-validating No manual evaluation required

Timely Written before the code

F.I.R.S.T.

Page 7: Clean code via dependency injection + guice

Write some code, kill technical debt(or not)

Page 8: Clean code via dependency injection + guice

class Showtimes {

MovieRepository repository;

Showtimes() {

repository = MovieRepositoryFactory.getInstance();

}

Set<Movie> findMovies(City city) { return repository.findByCity(city);

}

}

Showtime!

Page 9: Clean code via dependency injection + guice

class Showtimes {

MovieRepository repository;

Showtimes() {

repository = MovieRepositoryFactory.getInstance();

}

Set<Movie> findMovies(City city) { return repository.findByCity(city);

}

}

Smell: Constructor does real work

Page 10: Clean code via dependency injection + guice

class Showtimes {

MovieRepository repository;

Showtimes() {

repository = MovieRepositoryFactory.getInstance(); }

Set<Movie> findMovies(City city) { return repository.findByCity(city);

}

}

Smell: Constructor does real work

Page 11: Clean code via dependency injection + guice

class Showtimes {

MovieRepository repository;

Showtimes() {

repository = MovieRepositoryFactory.getInstance(); }

Set<Movie> findMovies(City city) { return repository.findByCity(city);

}

}

Smell: Constructor does real work

Page 12: Clean code via dependency injection + guice

Factory Pattern, boilerplate

public class MovieRepositoryFactory { static class MovieRepositoryHolder {

static MovieRepository instance = new MovieRepositoryImpl(); }

public static MovieRepository getInstance() { return MovieRepositoryHolder.instance;

}

static void setInstance(MovieRepository mock) { MovieRepositoryHolder.instance = mock;

}

}

Page 13: Clean code via dependency injection + guice

Factory Pattern, boilerplate

public class MovieRepositoryFactory { static class MovieRepositoryHolder {

static MovieRepository instance = new MovieRepositoryImpl(); }

public static MovieRepository getInstance() { return MovieRepositoryHolder.instance;

}

static void setInstance(MovieRepository mock) { MovieRepositoryHolder.instance = mock;

}

}

Page 14: Clean code via dependency injection + guice

Factory Pattern, boilerplate

public class MovieRepositoryFactory { static class MovieRepositoryHolder {

static MovieRepository instance = new MovieRepositoryImpl(); }

public static MovieRepository getInstance() { return MovieRepositoryHolder.instance;

}

static void setInstance(MovieRepository mock) { MovieRepositoryHolder.instance = mock;

}

}

Page 15: Clean code via dependency injection + guice

Factory Pattern, boilerplate

public class MovieRepositoryFactory { static class MovieRepositoryHolder {

static MovieRepository instance = new MovieRepositoryImpl(); }

public static MovieRepository getInstance() { return MovieRepositoryHolder.instance;

}

static void setInstance(MovieRepository mock) { MovieRepositoryHolder.instance = mock;

}

}

Page 16: Clean code via dependency injection + guice

Factory Pattern, boilerplate

public class MovieRepositoryFactory { static class MovieRepositoryHolder { static MovieRepository instance = new MovieRepositoryImpl(); }

public static MovieRepository getInstance() { return MovieRepositoryHolder.instance;

}

static void setInstance(MovieRepository mock) { MovieRepositoryHolder.instance = mock;

}

}

Page 17: Clean code via dependency injection + guice

Factory Pattern, boilerplate

public class MovieRepositoryFactory { static class MovieRepositoryHolder { static MovieRepository instance = new MovieRepositoryImpl(); }

public static MovieRepository getInstance() { return MovieRepositoryHolder.instance;

}

static void setInstance(MovieRepository mock) { MovieRepositoryHolder.instance = mock;

}

}

Page 18: Clean code via dependency injection + guice

@Test

void findMovies_cantTestYouDude() { Showtimes showtimes = new Showtimes();

// FRAK!

// No database setup... I'm stuck with my collaborators

// Can't really change it... Will it run in my

// partners computer?

}

Hard to test

Page 19: Clean code via dependency injection + guice

Fix: Constructor does real work

Page 20: Clean code via dependency injection + guice

class Showtimes {

MovieRepository repository;

Showtimes(MovieRepository repository) {

this.repository = repository;

}

Set<Movie> findMovies(City city) { return repository.findByCity(city);

}

}

Fix: Constructor does real work

Page 21: Clean code via dependency injection + guice

class Showtimes {

// Hollywood principle: "Don't call us, we'll call you"

MovieRepository repository;

Showtimes(MovieRepository repository) {

this.repository = repository;

}

Set<Movie> findMovies(City city) { return repository.findByCity(city);

}

}

Fix: Constructor does real work

Page 22: Clean code via dependency injection + guice

class Showtimes {

// Hollywood principle: "Don't call us, we'll call you"

MovieRepository repository;

@Inject Showtimes(MovieRepository repository) {

this.repository = repository;

}

Set<Movie> findMovies(City city) { return repository.findByCity(city);

}

}

Fix: Constructor does real work

Page 23: Clean code via dependency injection + guice

Fix: MovieRepository creation?

class App {

public static void main(String[] args) { // Manual Dependency Injection... but much more

// boilerplate!

// Maybe some <init> method... but that's why

// constructors exist right?

// Some container injection... mmm... Spring, Pico?

// Or better, Guice time! }

}

Page 24: Clean code via dependency injection + guice

class App {

public static void main(String[] args) { Injector injector = Guice.createInjector( new AbstractModule() {

@Override void configure() { bind(MovieRepository.class)

.to(JpaMovieRepository.class);

}

});

injector.getInstance(Showtimes.class).findMovies(bcn);

}

}

Fix: MovieRepository creation

Page 25: Clean code via dependency injection + guice

class App {

public static void main(String[] args) { Injector injector = Guice.createInjector( new AbstractModule() {

@Override void configure() { bind(MovieRepository.class) .to(JpaMovieRepository.class);

}

});

injector.getInstance(Showtimes.class).findMovies(bcn);

}

}

Fix: MovieRepository creation

Page 26: Clean code via dependency injection + guice

class App {

public static void main(String[] args) { Injector injector = Guice.createInjector( new AbstractModule() {

@Override void configure() { bind(MovieRepository.class) .to(JpaMovieRepository.class);

}

});

// Injection is VIRAL! Avoid at all cost using the // Injector in more than one place (aka Service Locator)

injector.getInstance(Showtimes.class).findMovies(bcn); }

}

Fix: MovieRepository creation

Page 27: Clean code via dependency injection + guice

Showtimes showtimes;

@Mock MovieRepository repository;

@Test void findMovies_easyNow() { showtimes = new Showtimes(repository);

given(repository.findByCity(bcn)) .willReturn(ImmutableSet.of(looper));

Set<Movie> movies = showtimes.findMovies(bcn);

assertThat(movies, hasItem(looper));}

Fix: Testable and flexible design

Page 28: Clean code via dependency injection + guice

Showtimes showtimes; //SUT

@Mock MovieRepository repository;

@Test void findMovies_easyNow() { showtimes = new Showtimes(repository);

given(repository.findByCity(bcn)) .willReturn(ImmutableSet.of(looper));

Set<Movie> movies = showtimes.findMovies(bcn);

assertThat(movies, hasItem(looper));}

Fix: Testable and flexible design

Page 29: Clean code via dependency injection + guice

Showtimes showtimes; //SUT

@Mock MovieRepository repository; // <3 Mockito, BDD

@Test void findMovies_easyNow() { showtimes = new Showtimes(repository);

//given

given(repository.findByCity(bcn)) .willReturn(ImmutableSet.of(looper)); //when

Set<Movie> movies = showtimes.findMovies(bcn);

//then

assertThat(movies, hasItem(looper));}

Fix: Testable and flexible design

Page 30: Clean code via dependency injection + guice

Showtimes showtimes; //SUT

@Mock MovieRepository repository; // <3 Mockito, BDD

@Test void findMovies_easyNow() { showtimes = new Showtimes(repository);

//given

given(repository.findByCity(bcn)) .willReturn(ImmutableSet.of(looper)); //when

Set<Movie> movies = showtimes.findMovies(bcn);

//then

assertThat(movies, hasItem(looper)); // <3 Hamcrest}

Fix: Testable and flexible design

Page 31: Clean code via dependency injection + guice

Showtimes showtimes; //SUT

@Mock MovieRepository repository; // <3 Mockito, BDD

@Test void findMovies_easyNow() { showtimes = new Showtimes(repository);

//given

given(repository.findByCity(bcn)) .willReturn(ImmutableSet.of(looper)); // <3 Guava //when

Set<Movie> movies = showtimes.findMovies(bcn);

//then

assertThat(movies, hasItem(looper)); // <3 Hamcrest}

Fix: Testable and flexible design

Page 32: Clean code via dependency injection + guice

Constructor does real work, more flavours

Page 33: Clean code via dependency injection + guice

class Ratings {

User user;

Ratings(AccountManager manager) {

user = manager.getLoggedUser();

user.setQueue(new ItTakesForeverToBuildOSSQueue());

}

}

Flavour: Partial objects, Law of Demeter

Page 34: Clean code via dependency injection + guice

class Ratings {

User user;

Ratings(AccountManager manager) {

user = manager.getLoggedUser(); user.setQueue(new ItTakesForeverToBuildOSSQueue()); }

// Test? Slow, really slow

// We don't use AccountManager anywhere else

}

Flavour: Partial objects, Law of Demeter

Page 35: Clean code via dependency injection + guice

class Ratings {

User user;

@Inject Ratings(User user) {

this.user = user;

}

}

Fix: Partial objects, Law of Demeter

Page 36: Clean code via dependency injection + guice

class Ratings {

User user;

// How do we inject this User like we need it?

// Where's the Queue?

@Inject Ratings(User user) {

this.user = user;

}

}

Fix: Partial objects, Law of Demeter

Page 37: Clean code via dependency injection + guice

@Provides

User providesUser(AccountManager manager, Queue queue) {

User user = manager.getLoggedUser();

user.setQueue(queue);

return user;

}

@Provides @Singleton

Queue providesLongRunningQueue() {

return new ItTakesForeverToBuildOSSQueue();

}

Fix: Partial objects, Law of Demeter

Page 38: Clean code via dependency injection + guice

@ProvidesUser providesUser(AccountManager manager, Queue queue) {

User user = manager.getLoggedUser();

user.setQueue(queue);

return user;

}

@Provides @Singleton

Queue providesLongRunningQueue() {

return new ItTakesForeverToBuildOSSQueue();

}

Fix: Partial objects, Law of Demeter

Page 39: Clean code via dependency injection + guice

@ProvidesUser providesUser(AccountManager manager, Queue queue) {

User user = manager.getLoggedUser();

user.setQueue(queue);

return user;

}

@Provides @Singleton // no JVM Singleton, yay!Queue providesLongRunningQueue() {

return new ItTakesForeverToBuildOSSQueue();

}

Fix: Partial objects, Law of Demeter

Page 40: Clean code via dependency injection + guice

@ProvidesUser providesUser(AccountManager manager, Queue queue) {

User user = manager.getLoggedUser();

user.setQueue(queue);

return user;

}

@Provides @Singleton // no JVM Singleton, yay!Queue providesLongRunningQueue() {

return new ItTakesForeverToBuildOSSQueue();

}

// Provider methods should be inside a Module

Fix: Partial objects, Law of Demeter

Page 41: Clean code via dependency injection + guice

Ratings ratings; //SUT

@Test void ratings_findAverage() { ratings = new Ratings(new DummyUser());

// Easy to test now, we can have a mock or test-double

// and check everything about Ratings. We don't care

// about collaborators.

}

Test: Partial objects, Law of Demeter

Page 42: Clean code via dependency injection + guice

Warning signs: Constructor does real work

New keyword in constructor or fieldsStatic method callsAnything more than field assignmentsObject not fully initialized after constructorControl flow

Page 43: Clean code via dependency injection + guice

Smell: Digging into Collaborators

Page 44: Clean code via dependency injection + guice

class TicketPriceCalculator {

MovieTheaterService service;

TicketPriceCalculator(MovieTheaterService service) {

this.service = service;

}

BigDecimal calculatePrice(User user, Invoice invoice) { UserBalance balance = user.getBalance();

BigDecimal amount = invoice.getSubtotal();

return service.calculateTotal(balance, amount);

}

}

Flavour: Digging around

Page 45: Clean code via dependency injection + guice

class TicketPriceCalculator {

MovieTheaterService service;

TicketPriceCalculator(MovieTheaterService service) {

this.service = service;

}

BigDecimal calculatePrice(User user, Invoice invoice) { UserBalance balance = user.getBalance();

BigDecimal amount = invoice.getSubtotal();

return service.calculateTotal(balance, amount);

}

}

Flavour: Digging around

Page 46: Clean code via dependency injection + guice

TicketPriceCalculator calculator; //SUT

@Mock MovieTheaterService service;

@Test void calculatePrice_tooMuchWork() { calculator = new TicketPriceCalculator(service);

given(user.getBalance()).willReturn(new DummyBalance()); given(invoice.getSubtotal()).willReturn(new BigDecimal("9.3"));

BigDecimal result = calculator.calculatePrice(balance, invoice);

assertThat(result, is(new BigDecimal("8.3"));}

Hard to test? Digging around

Page 47: Clean code via dependency injection + guice

TicketPriceCalculator calculator; //SUT

@Mock MovieTheaterService service;

@Test void calculatePrice_tooMuchWork() { calculator = new TicketPriceCalculator(service);

given(user.getBalance()).willReturn(new DummyBalance()); given(invoice.getSubtotal()).willReturn(new BigDecimal("9.3"));

BigDecimal result = calculator.calculatePrice(balance, invoice);

assertThat(result, is(new BigDecimal("8.3"));}

Hard to test? Digging around

Page 48: Clean code via dependency injection + guice

class TicketPriceCalculator {

MovieTheaterService service;

TicketPriceCalculator(MovieTheaterService service) {

this.service = service;

}

// Deceitful API, Law of Demeter

BigDecimal calculatePrice(User user, Invoice invoice) { UserBalance balance = user.getBalance(); BigDecimal amount = invoice.getSubtotal(); return service.calculateTotal(balance, amount);

}

}

Flavour: Digging around

Page 49: Clean code via dependency injection + guice

class TicketPriceCalculator {

MovieTheaterService service;

TicketPriceCalculator(MovieTheaterService service) {

this.service = service;

}

// Problem? Imagine this in a big application, your code

// will be much more complicated than you (and your team) need BigDecimal calculatePrice(User user, Invoice invoice) { UserBalance balance = user.getBalance(); BigDecimal amount = invoice.getSubtotal(); return service.calculateTotal(balance, amount);

}

}

Flavour: Digging around

Page 50: Clean code via dependency injection + guice

class TicketPriceCalculator {

MovieTheaterService service;

TicketPriceCalculator(MovieTheaterService service) {

this.service = service;

}

// Cleaner API, forget about "Middle men" class

BigDecimal calculatePrice(UserBalance balance, BigDecimal am) { return service.calculateTotal(balance, am);

}

}

Fix: Digging around

Page 51: Clean code via dependency injection + guice

TicketPriceCalculator calculator; //SUT

@Mock MovieTheaterService service;

@Test void calculatePrice_tooMuchWork() { calculator = new TicketPriceCalculator(service);

UserBalance balance = new DummyBalance("1.0");

BigDecimal amount = new BigDecimal("9.3"));

BigDecimal result = calculator.calculatePrice(balance, amount);

assertThat(result, is(new BigDecimal("8.3"));}

Fix: Digging around

Page 52: Clean code via dependency injection + guice

Digging into Collaborators, more flavours

Page 53: Clean code via dependency injection + guice

class MovieTheaterService {

void processOrder(UserContext context) { User user = context.getUser();

Order order = context.getOrders().byUser(user).now();

order.process();

}

}

Flavour: "Context", "Container"...

Page 54: Clean code via dependency injection + guice

class MovieTheaterService {

void processOrder(UserContext context) { User user = context.getUser(); Order order = context.getOrders().byUser(user).now(); order.process();

}

}

Flavour: "Context", "Container"...

Page 55: Clean code via dependency injection + guice

class MovieTheaterService {

void processOrder(UserContext context) { User user = context.getUser(); Order order = context.getOrders().byUser(user).now(); order.process();

}

// Test? Create a UserContext with ton of mocks and stuff

}

Flavour: "Context", "Container"...

Page 56: Clean code via dependency injection + guice

class MovieTheaterService {

void processOrder(UserContext context) { User user = context.getUser(); Order order = context.getOrders().byUser(user).now(); order.process();

}

// Test? Create a UserContext with ton of mocks and stuff

}

Flavour: "Context", "Container"...

Page 57: Clean code via dependency injection + guice

class MovieTheaterService {

void processOrder(User user, Order order) { order.process();

}

// Test? Sure! You got everything you need in place.

}

Fix: "Context", "Container"...

Page 58: Clean code via dependency injection + guice

Warning signs: Digging into Collaborators

Objects to use other objects, not themself. Having to create mocks that return other mocks

Law of Demeter everywhere Seeing more than one period (.) in a method

chaining. Going deep in the object graph: mgs.getSolid().findOcelot().now()

Exception: DSLs

Suspicious names Context, Environment, Container...

Page 59: Clean code via dependency injection + guice

Smell: Global state and Singletons

Page 60: Clean code via dependency injection + guice

@Test void chargeCreditCard() { // Example: @mhevery CreditCard cc = new CreditCard("9999 0000 7777", 5, 2009);

assertThat(cc.charge(30.0), is(true));}

Flavour: They are liars!

Page 61: Clean code via dependency injection + guice

@Test void chargeCreditCard() { CreditCard cc = new CreditCard("9999 0000 7777", 5, 2009);

assertThat(cc.charge(30.0), is(true));

// Fails at runtime:

// java.lang.NullPointerExpection}

Flavour: They are liars!

Page 62: Clean code via dependency injection + guice

@Test void chargeCreditCard() { CreditCardProcessor.init(); CreditCard cc = new CreditCard("9999 0000 7777", 5, 2009);

assertThat(cc.charge(30.0), is(true));}

Flavour: They are liars!

Page 63: Clean code via dependency injection + guice

@Test void chargeCreditCard() { CreditCardProcessor.init(); CreditCard cc = new CreditCard("9999 0000 7777", 5, 2009);

assertThat(cc.charge(30.0), is(true));

// Argh! This is getting awkward

// java.lang.NullPointerExpection}

Flavour: They are liars!

Page 64: Clean code via dependency injection + guice

@Test void chargeCreditCard() { CreditCardProcessor.init();

OfflineQueue.start(); CreditCard cc = new CreditCard("9999 0000 7777", 5, 2009);

assertThat(cc.charge(30.0), is(true));}

Flavour: They are liars!

Page 65: Clean code via dependency injection + guice

@Test void chargeCreditCard() { CreditCardProcessor.init();

OfflineQueue.start(); CreditCard cc = new CreditCard("9999 0000 7777", 5, 2009);

assertThat(cc.charge(30.0), is(true));

// Are you kidding?

// java.lang.NullPointerExpection}

Flavour: They are liars!

Page 66: Clean code via dependency injection + guice

@Test void chargeCreditCard() { Database.connect("hsqldb"); CreditCardProcessor.init();

OfflineQueue.start();

CreditCard cc = new CreditCard("9999 0000 7777", 5, 2009);

assertThat(cc.charge(30.0), is(true));}

Flavour: They are liars!

Page 67: Clean code via dependency injection + guice

@Test void chargeCreditCard() { Database.connect("hsqldb"); // Global State CreditCardProcessor.init(); // Global State

OfflineQueue.start(); // Global State

CreditCard cc = new CreditCard("9999 0000 7777", 5, 2009);

assertThat(cc.charge(30.0), is(true));

// How do we know this? Sure it's documented somewhere... right?

}

Flavour: They are liars!

Page 68: Clean code via dependency injection + guice

How do you provide global variables in languages without global variables?

"Don't. Your programs will thank you for taking the time to think about design instead."

-- Kent Beck, JUnit and TDD creator

Page 69: Clean code via dependency injection + guice

Fix: They are liars!

Page 70: Clean code via dependency injection + guice

Fix: They are liars!

Dependency Injection

Page 71: Clean code via dependency injection + guice

Fix: They are liars!

Dependency Injection

Dependency Injection

Page 72: Clean code via dependency injection + guice

Fix: They are liars!

Dependency Injection

Dependency Injection

Dependency Injection

Page 73: Clean code via dependency injection + guice

Fix: They are liars!

Dependency Injection

Dependency Injection

Dependency Injection

Dependency Injection

Page 74: Clean code via dependency injection + guice

Fix: They are liars!@Test void chargeCreditCard() { Database db = mock(Database.class); Queue queue = new OfflineQueue(db); CreditCardProcessor ccProc = new CreditCardProcessor(queue); CreditCard cc = new CreditCard(ccProc, "9999 0000 7777"); cc.charge(30.0);}

Page 75: Clean code via dependency injection + guice

Fix: They are liars!@Test void chargeCreditCard() { Database db = mock(Database.class); Queue queue = new OfflineQueue(db); CreditCardProcessor ccProc = new CreditCardProcessor(queue); CreditCard cc = new CreditCard(ccProc, "9999 0000 7777"); cc.charge(30.0);}

Page 76: Clean code via dependency injection + guice

Fix: They are liars!@Test void chargeCreditCard() { CreditCardProcessor ccProc = mock(CreditCardProcessor.class); CreditCard cc = new CreditCard(ccProc, "9999 0000 7777"); cc.charge(30.0);}

Page 77: Clean code via dependency injection + guice

Singletons and JVM Singletons Gang of four, static instance field. Best known as an Anti-pattern.

But there's nothing wrong about having one instance of an Object Application Singleton

Managed by someone, eg: Guice @Singleton scope

About Singletons

Page 78: Clean code via dependency injection + guice

Global state is Evil Dirty design, enables Action at a distance (anti-pattern), extremely-hard-to-test, etc.

Caveat: When it's ok? Primitive or immutable constant reference

static final String DEVFEST = "Devfest rocks" When information only travels one way org.slf4j.Logger // but hard to test

About Global State

Page 79: Clean code via dependency injection + guice

Warning signs: Global State and Singletons

Using SingletonsStatic fields or static methods Don't confuse with helper or factory methods

Static initialization block class App {

static {

MutableObject object = Registry.find();

}

}

Service Locators

Page 80: Clean code via dependency injection + guice

Smell: Class does too much

Page 81: Clean code via dependency injection + guice

Smell: Class does too much, aka

Kitchen Sink

Page 82: Clean code via dependency injection + guice

Smell: Class does too much, aka

Kitchen SinkDumping Ground

Page 83: Clean code via dependency injection + guice

Smell: Class does too much, aka

Kitchen SinkDumping GroundThis Class does this AND that AND ...

Page 84: Clean code via dependency injection + guice

Smell: Class does too much, aka

Kitchen SinkDumping GroundThis Class does this AND that AND ...God Class

Page 85: Clean code via dependency injection + guice

Smell: Class does too much, aka

Kitchen SinkDumping GroundThis Class does this AND that AND ...God ClassQuijote

Page 86: Clean code via dependency injection + guice

Smell: Class does too much, aka

Kitchen SinkDumping GroundThis Class does this AND that AND ...God ClassQuijote"You can look at everything except this Class"

Page 87: Clean code via dependency injection + guice

Smell: Class does too muchinterface MovieTheater {

void open();

void addShowtime(Showtime showtime);

Set<Showtime> getShowtimes();

void purchaseTicket(Buyer buyer, Movie movie);

UserBalance findUserBalance(User balance);

void processOrder(Order order);

// ...}

Page 88: Clean code via dependency injection + guice

Smell: Class does too muchinterface MovieTheater {

void open();

void addShowtime(Showtime showtime);

Set<Showtime> getShowtimes();

void purchaseTicket(Buyer buyer, Movie movie);

UserBalance findUserBalance(User balance);

void processOrder(Order order);

// ...}

Page 89: Clean code via dependency injection + guice

Fix: Class does too muchinterface MovieTheater { void open();

void addShowtime(Showtime showtime);

Set<Showtime> getShowtimes();}

interface BillingService { void purchaseTicket(Buyer buyer, Movie movie);

UserBalance findUserBalance(User balance);

void processOrder(Order order);}

Page 90: Clean code via dependency injection + guice

Warning signs: Class does too much

Descriptive names for this smellTiny scroll barMany fields, many methods Use Sonar and LCOM4 (Lack of Cohesion) to check this

Many collaboratorsJust don't getting the Class

Page 91: Clean code via dependency injection + guice

Dependency Injection enables you to write testable code

Page 92: Clean code via dependency injection + guice

Deep synergies between testable code and good design

-- Michael Feathers

Page 93: Clean code via dependency injection + guice

Maintainable code

Page 94: Clean code via dependency injection + guice

Much more Guice!

JSR330 javax.inject -- Google + Spring effort

Roboguice Android, @InjectView, @InjectResource

Dagger From Square, original Guice committers, built on JSR330, pretty exciting!

Page 96: Clean code via dependency injection + guice

Thanks!

[email protected]@jordi9

slideshare.net/giro9

Page 97: Clean code via dependency injection + guice

Q & A

[email protected]@jordi9