Slide 1

Slide 1 text

A FRESH APPROACH TO DI TOOTHPICK https://github.com/stephanenicolas/toothpick/

Slide 2

Slide 2 text

ABOUT US Senior Android Dev @ Groupon
 ~20 years of Java coding OSS: Dart, TP, BoundBox, … STEPHANE NICOLAS DANIEL MOLINERO REGUERA Android Dev @ Groupon
 Turbulence Ninja OSS: Dart, TP. +stephane nicolas @D_Lemures

Slide 3

Slide 3 text

5IF"OESPJE5FBNJT)JSJOH
 jobs.groupon.com/careers/

Slide 4

Slide 4 text

THE TALK WHY DI ? WHY TOOTHPICK? TOOTHPICK FEATURES 
 SOME EXAMPLES 
 
 UNIT TESTING CONCLUSION SCOPE MODULES & BINDINGS SCOPE TREE SCOPE SINGLETONS MVP & STATE PRESERVATION MULTIPLE ACTIVITIES FLOWS #DroidConBos | @D_Lemures | @GrouponEng

Slide 5

Slide 5 text

WHY DI ? #DroidConBos | @D_Lemures

Slide 6

Slide 6 text

WHY DI ? DECOUPLE #DroidConBos | @D_Lemures

Slide 7

Slide 7 text

WHY DI ? DECOUPLE USES #DroidConBos | @D_Lemures

Slide 8

Slide 8 text

WHY DI ? DECOUPLE REUSE USES #DroidConBos | @D_Lemures

Slide 9

Slide 9 text

WHY DI ? DECOUPLE REUSE USES USES USES #DroidConBos | @D_Lemures

Slide 10

Slide 10 text

WHY DI ? DECOUPLE REUSE TEST USES USES USES #DroidConBos | @D_Lemures

Slide 11

Slide 11 text

WHY DI ? DECOUPLE REUSE TEST USES USES USES MOCK USES #DroidConBos | @D_Lemures

Slide 12

Slide 12 text

WHY TOOTHPICK? #DroidConBos | @D_Lemures

Slide 13

Slide 13 text

WHY TOOTHPICK? SIMPLER #DroidConBos | @D_Lemures

Slide 14

Slide 14 text

WHY TOOTHPICK? SIMPLER BETTER TEST SUPPORT #DroidConBos | @D_Lemures

Slide 15

Slide 15 text

WHY TOOTHPICK? SIMPLER BETTER TEST SUPPORT EVEN FASTER #DroidConBos | @D_Lemures

Slide 16

Slide 16 text

TOOTHPICK FEATURES public class SmoothieMachine {
 
 @Inject IceMachine iceMachine;
 
 public void doSmoothie() {
 iceMachine.makeIce();
 }
 } @Singleton
 public class IceMachine {
 Foo foo;
 
 @Inject
 public IceMachine(Foo foo) {
 this.foo = foo;
 }
 #DroidConBos | @D_Lemures

Slide 17

Slide 17 text

TOOTHPICK FEATURES public class SmoothieMachine {
 
 @Inject IceMachine iceMachine;
 
 public void doSmoothie() {
 iceMachine.makeIce();
 }
 } @Singleton
 public class IceMachine {
 Foo foo;
 
 @Inject
 public IceMachine(Foo foo) {
 this.foo = foo;
 }
 JSR 330 annotations→nothing new here #DroidConBos | @D_Lemures

Slide 18

Slide 18 text

TOOTHPICK FEATURES SCOPE SCOPE #DroidConBos | @D_Lemures

Slide 19

Slide 19 text

TOOTHPICK FEATURES SCOPE SCOPE MAKE INJECTIONS #DroidConBos | @D_Lemures

Slide 20

Slide 20 text

TOOTHPICK FEATURES SCOPE SCOPE MAKE INJECTIONS public class MyApplication extends Application { @Inject Machine machine;
 
 @Override protected void onCreate() {
 super.onCreate();
 
 Scope appScope = Toothpick.openScope(this); appScope.installModules(…); Toothpick.inject(this, appScope);
 } } #DroidConBos | @D_Lemures

Slide 21

Slide 21 text

TOOTHPICK FEATURES SCOPE, MODULES & BINDINGS SCOPE #DroidConBos | @D_Lemures

Slide 22

Slide 22 text

TOOTHPICK FEATURES SCOPE, MODULES & BINDINGS SCOPE BINDINGS #DroidConBos | @D_Lemures

Slide 23

Slide 23 text

TOOTHPICK FEATURES SCOPE, MODULES & BINDINGS SCOPE BINDINGS MODULES #DroidConBos | @D_Lemures

Slide 24

Slide 24 text

TOOTHPICK FEATURES SCOPE, MODULES & BINDINGS SCOPE BINDINGS MODULES public class MyApplication extends Application { @Inject Machine machine;
 
 @Override protected void onCreate() {
 super.onCreate();
 
 Scope appScope = Toothpick.openScope(this); appScope.installModules(new Module() {{
 bind(Machine.class).to(IceMachine.class); }});
 Toothpick.inject(this, appScope);
 } } #DroidConBos | @D_Lemures

Slide 25

Slide 25 text

TOOTHPICK FEATURES APPLICATION
 SCOPE ACTIVITY 1
 SCOPE SCOPE TREE #DroidConBos | @D_Lemures

Slide 26

Slide 26 text

TOOTHPICK FEATURES APPLICATION
 SCOPE SCOPE TREE #DroidConBos | @D_Lemures

Slide 27

Slide 27 text

TOOTHPICK FEATURES APPLICATION
 SCOPE ACTIVITY 2
 SCOPE SCOPE TREE #DroidConBos | @D_Lemures

Slide 28

Slide 28 text

TOOTHPICK FEATURES APPLICATION
 SCOPE ACTIVITY 2
 SCOPE SERVICE 1
 SCOPE SCOPE TREE #DroidConBos | @D_Lemures

Slide 29

Slide 29 text

TOOTHPICK FEATURES APPLICATION
 SCOPE ACTIVITY 2
 SCOPE SERVICE 1
 SCOPE FRAGMENT 1
 SCOPE SCOPE TREE #DroidConBos | @D_Lemures

Slide 30

Slide 30 text

TOOTHPICK FEATURES APPLICATION
 SCOPE ACTIVITY 2
 SCOPE SERVICE 1
 SCOPE FRAGMENT 1
 SCOPE FRAGMENT 2
 SCOPE SCOPE TREE #DroidConBos | @D_Lemures

Slide 31

Slide 31 text

TOOTHPICK FEATURES APPLICATION
 SCOPE ACTIVITY 2
 SCOPE SERVICE 1
 SCOPE FRAGMENT 3
 SCOPE FRAGMENT 1
 SCOPE FRAGMENT 2
 SCOPE SCOPE TREE #DroidConBos | @D_Lemures

Slide 32

Slide 32 text

TOOTHPICK FEATURES public class LemonActivity extends Activity { @Inject Machine machine; @Inject Context context; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Scope scope = Toothpick.openScopes(getApplication(), this); scope.installModules(new Module() {{ bind(Context.class).toInstance(this); }}); Toothpick.inject(this, scope); } } SCOPE TREE #DroidConBos | @D_Lemures

Slide 33

Slide 33 text

TOOTHPICK FEATURES public class LemonActivity extends Activity { @Inject Machine machine; @Inject Context context; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Scope scope = Toothpick.openScopes(getApplication(), this); scope.installModules(new Module() {{ bind(Context.class).toInstance(this); }}); Toothpick.inject(this, scope); } } SCOPE TREE APPLICATION
 SCOPE ACTIVITY
 SCOPE #DroidConBos | @D_Lemures

Slide 34

Slide 34 text

TOOTHPICK FEATURES APPLICATION
 SCOPE ACTIVITY
 SCOPE SCOPE SINGLETONS #DroidConBos | @D_Lemures

Slide 35

Slide 35 text

TOOTHPICK FEATURES APPLICATION
 SCOPE ACTIVITY
 SCOPE APP SINGLETONS SCOPE SINGLETONS #DroidConBos | @D_Lemures

Slide 36

Slide 36 text

TOOTHPICK FEATURES APPLICATION
 SCOPE ACTIVITY
 SCOPE APP SINGLETONS ACTIVITY SINGLETONS SCOPE SINGLETONS #DroidConBos | @D_Lemures

Slide 37

Slide 37 text

TOOTHPICK FEATURES public class Module extends Module {
 public Module() {
 bind(Machine.class).toInstance(new Ice Machine());
 }
 } SCOPE SINGLETONS SINGLETONS CAN BE DEFINED IN MODULES #DroidConBos | @D_Lemures

Slide 38

Slide 38 text

TOOTHPICK FEATURES @Singleton
 public class IceMachine {
 } @ActivitySingleton
 public class SmoothieMachine {
 } APPLICATION
 SCOPE ACTIVITY
 SCOPE SCOPE SINGLETONS OR USING ANNOTATIONS #DroidConBos | @D_Lemures

Slide 39

Slide 39 text

SOME EXAMPLES MVP & STATE PRESERVATION #DroidConBos | @D_Lemures

Slide 40

Slide 40 text

APPLICATION SCOPE MVP & STATE PRESERVATION ACTIVITY SCOPE SOME EXAMPLES #DroidConBos | @D_Lemures

Slide 41

Slide 41 text

APPLICATION SCOPE MVP & STATE PRESERVATION ACTIVITY SCOPE SOME EXAMPLES #DroidConBos | @D_Lemures

Slide 42

Slide 42 text

APPLICATION SCOPE PRESENTER SCOPE MVP & STATE PRESERVATION ACTIVITY SCOPE SOME EXAMPLES #DroidConBos | @D_Lemures

Slide 43

Slide 43 text

PRESENTER INSTANCE APPLICATION SCOPE PRESENTER SCOPE MVP & STATE PRESERVATION ACTIVITY SCOPE SOME EXAMPLES #DroidConBos | @D_Lemures

Slide 44

Slide 44 text

PRESENTER INSTANCE APPLICATION SCOPE PRESENTER SCOPE MVP & STATE PRESERVATION SOME EXAMPLES #DroidConBos | @D_Lemures

Slide 45

Slide 45 text

PRESENTER INSTANCE APPLICATION SCOPE PRESENTER SCOPE MVP & STATE PRESERVATION ACTIVITY SCOPE SOME EXAMPLES #DroidConBos | @D_Lemures

Slide 46

Slide 46 text

MVP & STATE PRESERVATION public class MyActivity extends Activity {
 
 @Inject MyPresenter presenter; 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 Scope scope = openScopes(getApplication(), 
 PresenterSingleton.class, 
 this);
 Toothpick.inject(this, scope);
 } } SOME EXAMPLES #DroidConBos | @D_Lemures

Slide 47

Slide 47 text

@PresenterSingleton
 public class MyPresenter {
 String dealId;
 int quantity;
 } PRESENTER SCOPE MVP & STATE PRESERVATION SOME EXAMPLES #DroidConBos | @D_Lemures

Slide 48

Slide 48 text

ACTIVITY 1 ACTIVITY 3 ACTIVITY 2 MULTI ACTIVITY FLOWS SOME EXAMPLES #DroidConBos | @D_Lemures

Slide 49

Slide 49 text

ACTIVITY 1 ACTIVITY 3 ACTIVITY 2 MULTI ACTIVITY FLOWS Purchase Flow SOME EXAMPLES #DroidConBos | @D_Lemures

Slide 50

Slide 50 text

ACTIVITY 1 ACTIVITY 3 ACTIVITY 2 MULTI ACTIVITY FLOWS Purchase Flow SOME EXAMPLES #DroidConBos | @D_Lemures

Slide 51

Slide 51 text

ACTIVITY 1 ACTIVITY 3 ACTIVITY 2 MULTI ACTIVITY FLOWS SOME EXAMPLES #DroidConBos | @D_Lemures

Slide 52

Slide 52 text

ACTIVITY 1 ACTIVITY 3 ACTIVITY 2 MULTI ACTIVITY FLOWS SOME EXAMPLES #DroidConBos | @D_Lemures

Slide 53

Slide 53 text

ACTIVITY 1 ACTIVITY 3 ACTIVITY 2 MULTI ACTIVITY FLOWS SOME EXAMPLES #DroidConBos | @D_Lemures

Slide 54

Slide 54 text

ACTIVITY 1 ACTIVITY 3 ACTIVITY 2 MULTI ACTIVITY FLOWS SOME EXAMPLES #DroidConBos | @D_Lemures

Slide 55

Slide 55 text

APPLICATION SCOPE ACTIVITY 1 SCOPE FLOW SCOPE MULTI ACTIVITY FLOWS SOME EXAMPLES #DroidConBos | @D_Lemures

Slide 56

Slide 56 text

APPLICATION SCOPE ACTIVITY 1 SCOPE FLOW SCOPE MULTI ACTIVITY FLOWS SOME EXAMPLES #DroidConBos | @D_Lemures

Slide 57

Slide 57 text

APPLICATION SCOPE ACTIVITY 1 SCOPE FLOW SCOPE ACTIVITY 2 SCOPE MULTI ACTIVITY FLOWS SOME EXAMPLES #DroidConBos | @D_Lemures

Slide 58

Slide 58 text

APPLICATION SCOPE ACTIVITY 1 SCOPE FLOW SCOPE ACTIVITY 3 SCOPE ACTIVITY 2 SCOPE MULTI ACTIVITY FLOWS SOME EXAMPLES #DroidConBos | @D_Lemures

Slide 59

Slide 59 text

APPLICATION SCOPE FLOW SCOPE MULTI ACTIVITY FLOWS SOME EXAMPLES #DroidConBos | @D_Lemures

Slide 60

Slide 60 text

APPLICATION SCOPE MULTI ACTIVITY FLOWS SOME EXAMPLES #DroidConBos | @D_Lemures

Slide 61

Slide 61 text

MVP & STATE PRESERVATION public class MyActivity extends Activity {
 
 @Inject ShoppingCart shoppingCart; 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 Scope scope = openScopes(getApplication(), 
 FlowSingleton.class, 
 this);
 Toothpick.inject(this, scope);
 } } SOME EXAMPLES #DroidConBos | @D_Lemures

Slide 62

Slide 62 text

@FlowSingleton
 public class ShoppingCart {
 List purchases…
 } FLOW SCOPE MULTI ACTIVITY FLOWS SOME EXAMPLES #DroidConBos | @D_Lemures

Slide 63

Slide 63 text

UNIT TESTING WE TEST UNITS #DroidConBos | @D_Lemures

Slide 64

Slide 64 text

UNIT TESTING WE TEST UNITS MOCK USES WE MOCK DEPENDENCIES #DroidConBos | @D_Lemures

Slide 65

Slide 65 text

UNIT TESTING public class SmoothieMachine { @Inject IceMachine iceMachine; @Inject SyrupDispenser syrupDispenser; public void doSmoothie() { Smoothie smoothie = iceMachine.makeIce(); syrupDispenser.addSyrup(smoothie); return smoothie; } } WE WANT TO SIMULATE THE DEPENDENCIES #DroidConBos | @D_Lemures

Slide 66

Slide 66 text

UNIT TESTING public class TestSmoothieMachine extends EasyMockSupport { @Rule public EasyMockRule easyMockRule = new EasyMockRule(this);
 
 @Mock IceMachine iceMachineMock; @Mock SyrupDispenser syrupDispenserMock; @Mock Smoothie smoothieMock;
 @Test
 public void doSmoothie_should_createSmoothie() {
 // GIVEN expect(iceMachineMock.makeIce()).andReturn(smoothieMock); syrupDispenserMock.addSyrup(smoothieMock); replayAll(); // WHEN Smoothie smoothie = smoothieMachine.doSmoothie(); // THEN assertThat(smoothie, sameInstance(smoothieMock)); verifyAll(); }
 } 1. CREATE MOCKS -> EASYMOCK #DroidConBos | @D_Lemures

Slide 67

Slide 67 text

UNIT TESTING public class TestSmoothieMachine extends EasyMockSupport { @Rule public EasyMockRule easyMockRule = new EasyMockRule(this); @Rule public ToothPickRule toothPickRule = new ToothPickRule(this, “testScope”);
 
 @Mock IceMachine iceMachineMock; @Mock SyrupDispenser syrupDispenserMock; @Mock Smoothie smoothieMock; @Inject SmoothieMachine classUnderTest;
 @Test
 public void doSmoothie_should_createSmoothie() {
 // GIVEN expect(iceMachineMock.makeIce()).andReturn(smoothieMock); syrupDispenserMock.addSyrup(smoothieMock); replayAll(); // WHEN toothPickRule.inject(this); Smoothie smoothie = smoothieMachine.doSmoothie(); // THEN assertThat(smoothie, sameInstance(smoothieMock)); verifyAll(); }
 } 2. INJECT MOCKS -> TOOTHPICK #DroidConBos | @D_Lemures

Slide 68

Slide 68 text

CONCLUSION QUESTIONS ? COMMENTS ? #DroidConBos | @D_Lemures | @GrouponEng

Slide 69

Slide 69 text

CONCLUSION QUESTIONS ? COMMENTS ? #DroidConBos | @D_Lemures | @GrouponEng

Slide 70

Slide 70 text

A FRESH APPROACH TO DI TOOTHPICK https://github.com/stephanenicolas/toothpick/ +stephane nicolas @D_Lemures