Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Toothpick - A fresh approach to DI (Including ...
Search
Daniel Molinero Reguera
April 11, 2017
Programming
1
1.1k
Toothpick - A fresh approach to DI (Including Unit Testing)
Presented at Droidcon Boston 2017
Daniel Molinero Reguera
April 11, 2017
Tweet
Share
More Decks by Daniel Molinero Reguera
See All by Daniel Molinero Reguera
TP3 & KTP: Simple, fast, and boilerplate-free DI for Kotlin
dlemures
0
52
Toothpick - A fresh approach to DI - Short Version
dlemures
0
55
Toothpick Bad Practices 🙅 and Nice Tricks 👌
dlemures
0
91
Dart & Henson - Better Android Intents
dlemures
1
210
Toothpick - A fresh approach to DI
dlemures
0
120
Toothpick & Dependency Injection
dlemures
1
2k
Other Decks in Programming
See All in Programming
광고 소재 심사 과정에 AI를 도입하여 광고 서비스 생산성 향상시키기
kakao
PRO
0
170
Less waste, more joy, and a lot more green: How Quarkus makes Java better
hollycummins
0
100
CSC509 Lecture 11
javiergs
PRO
0
180
ペアーズにおけるAmazon Bedrockを⽤いた障害対応⽀援 ⽣成AIツールの導⼊事例 @ 20241115配信AWSウェビナー登壇
fukubaka0825
6
1.9k
Laravel や Symfony で手っ取り早く OpenAPI のドキュメントを作成する
azuki
1
110
役立つログに取り組もう
irof
28
9.6k
Jakarta EE meets AI
ivargrimstad
0
590
ECS Service Connectのこれまでのアップデートと今後のRoadmapを見てみる
tkikuc
2
250
3rd party scriptでもReactを使いたい! Preact + Reactのハイブリッド開発
righttouch
PRO
1
600
【Kaigi on Rails 2024】YOUTRUST スポンサーLT
krpk1900
1
330
イベント駆動で成長して委員会
happymana
1
320
Why Jakarta EE Matters to Spring - and Vice Versa
ivargrimstad
0
1k
Featured
See All Featured
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
6
410
A Modern Web Designer's Workflow
chriscoyier
693
190k
Building Your Own Lightsaber
phodgson
103
6.1k
Large-scale JavaScript Application Architecture
addyosmani
510
110k
Mobile First: as difficult as doing things right
swwweet
222
8.9k
Thoughts on Productivity
jonyablonski
67
4.3k
Navigating Team Friction
lara
183
14k
The World Runs on Bad Software
bkeepers
PRO
65
11k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5k
Art, The Web, and Tiny UX
lynnandtonic
297
20k
Writing Fast Ruby
sferik
627
61k
KATA
mclloyd
29
14k
Transcript
A FRESH APPROACH TO DI TOOTHPICK https://github.com/stephanenicolas/toothpick/
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
5IF"OESPJE5FBNJT)JSJOH jobs.groupon.com/careers/
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
WHY DI ? #DroidConBos | @D_Lemures
WHY DI ? DECOUPLE #DroidConBos | @D_Lemures
WHY DI ? DECOUPLE USES #DroidConBos | @D_Lemures
WHY DI ? DECOUPLE REUSE USES #DroidConBos | @D_Lemures
WHY DI ? DECOUPLE REUSE USES USES USES #DroidConBos |
@D_Lemures
WHY DI ? DECOUPLE REUSE TEST USES USES USES #DroidConBos
| @D_Lemures
WHY DI ? DECOUPLE REUSE TEST USES USES USES MOCK
USES #DroidConBos | @D_Lemures
WHY TOOTHPICK? #DroidConBos | @D_Lemures
WHY TOOTHPICK? SIMPLER #DroidConBos | @D_Lemures
WHY TOOTHPICK? SIMPLER BETTER TEST SUPPORT #DroidConBos | @D_Lemures
WHY TOOTHPICK? SIMPLER BETTER TEST SUPPORT EVEN FASTER #DroidConBos |
@D_Lemures
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
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
TOOTHPICK FEATURES SCOPE SCOPE #DroidConBos | @D_Lemures
TOOTHPICK FEATURES SCOPE SCOPE MAKE INJECTIONS #DroidConBos | @D_Lemures
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
TOOTHPICK FEATURES SCOPE, MODULES & BINDINGS SCOPE #DroidConBos | @D_Lemures
TOOTHPICK FEATURES SCOPE, MODULES & BINDINGS SCOPE BINDINGS #DroidConBos |
@D_Lemures
TOOTHPICK FEATURES SCOPE, MODULES & BINDINGS SCOPE BINDINGS MODULES #DroidConBos
| @D_Lemures
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
TOOTHPICK FEATURES APPLICATION SCOPE ACTIVITY 1 SCOPE SCOPE TREE #DroidConBos
| @D_Lemures
TOOTHPICK FEATURES APPLICATION SCOPE SCOPE TREE #DroidConBos | @D_Lemures
TOOTHPICK FEATURES APPLICATION SCOPE ACTIVITY 2 SCOPE SCOPE TREE #DroidConBos
| @D_Lemures
TOOTHPICK FEATURES APPLICATION SCOPE ACTIVITY 2 SCOPE SERVICE 1 SCOPE
SCOPE TREE #DroidConBos | @D_Lemures
TOOTHPICK FEATURES APPLICATION SCOPE ACTIVITY 2 SCOPE SERVICE 1 SCOPE
FRAGMENT 1 SCOPE SCOPE TREE #DroidConBos | @D_Lemures
TOOTHPICK FEATURES APPLICATION SCOPE ACTIVITY 2 SCOPE SERVICE 1 SCOPE
FRAGMENT 1 SCOPE FRAGMENT 2 SCOPE SCOPE TREE #DroidConBos | @D_Lemures
TOOTHPICK FEATURES APPLICATION SCOPE ACTIVITY 2 SCOPE SERVICE 1 SCOPE
FRAGMENT 3 SCOPE FRAGMENT 1 SCOPE FRAGMENT 2 SCOPE SCOPE TREE #DroidConBos | @D_Lemures
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
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
TOOTHPICK FEATURES APPLICATION SCOPE ACTIVITY SCOPE SCOPE SINGLETONS #DroidConBos |
@D_Lemures
TOOTHPICK FEATURES APPLICATION SCOPE ACTIVITY SCOPE APP SINGLETONS SCOPE SINGLETONS
#DroidConBos | @D_Lemures
TOOTHPICK FEATURES APPLICATION SCOPE ACTIVITY SCOPE APP SINGLETONS ACTIVITY SINGLETONS
SCOPE SINGLETONS #DroidConBos | @D_Lemures
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
TOOTHPICK FEATURES @Singleton public class IceMachine { } @ActivitySingleton public
class SmoothieMachine { } APPLICATION SCOPE ACTIVITY SCOPE SCOPE SINGLETONS OR USING ANNOTATIONS #DroidConBos | @D_Lemures
SOME EXAMPLES MVP & STATE PRESERVATION #DroidConBos | @D_Lemures
APPLICATION SCOPE MVP & STATE PRESERVATION ACTIVITY SCOPE SOME EXAMPLES
#DroidConBos | @D_Lemures
APPLICATION SCOPE MVP & STATE PRESERVATION ACTIVITY SCOPE SOME EXAMPLES
#DroidConBos | @D_Lemures
APPLICATION SCOPE PRESENTER SCOPE MVP & STATE PRESERVATION ACTIVITY SCOPE
SOME EXAMPLES #DroidConBos | @D_Lemures
PRESENTER INSTANCE APPLICATION SCOPE PRESENTER SCOPE MVP & STATE PRESERVATION
ACTIVITY SCOPE SOME EXAMPLES #DroidConBos | @D_Lemures
PRESENTER INSTANCE APPLICATION SCOPE PRESENTER SCOPE MVP & STATE PRESERVATION
SOME EXAMPLES #DroidConBos | @D_Lemures
PRESENTER INSTANCE APPLICATION SCOPE PRESENTER SCOPE MVP & STATE PRESERVATION
ACTIVITY SCOPE SOME EXAMPLES #DroidConBos | @D_Lemures
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
@PresenterSingleton public class MyPresenter { String dealId; int quantity; }
PRESENTER SCOPE MVP & STATE PRESERVATION SOME EXAMPLES #DroidConBos | @D_Lemures
ACTIVITY 1 ACTIVITY 3 ACTIVITY 2 MULTI ACTIVITY FLOWS SOME
EXAMPLES #DroidConBos | @D_Lemures
ACTIVITY 1 ACTIVITY 3 ACTIVITY 2 MULTI ACTIVITY FLOWS Purchase
Flow SOME EXAMPLES #DroidConBos | @D_Lemures
ACTIVITY 1 ACTIVITY 3 ACTIVITY 2 MULTI ACTIVITY FLOWS Purchase
Flow SOME EXAMPLES #DroidConBos | @D_Lemures
ACTIVITY 1 ACTIVITY 3 ACTIVITY 2 MULTI ACTIVITY FLOWS SOME
EXAMPLES #DroidConBos | @D_Lemures
ACTIVITY 1 ACTIVITY 3 ACTIVITY 2 MULTI ACTIVITY FLOWS SOME
EXAMPLES #DroidConBos | @D_Lemures
ACTIVITY 1 ACTIVITY 3 ACTIVITY 2 MULTI ACTIVITY FLOWS SOME
EXAMPLES #DroidConBos | @D_Lemures
ACTIVITY 1 ACTIVITY 3 ACTIVITY 2 MULTI ACTIVITY FLOWS SOME
EXAMPLES #DroidConBos | @D_Lemures
APPLICATION SCOPE ACTIVITY 1 SCOPE FLOW SCOPE MULTI ACTIVITY FLOWS
SOME EXAMPLES #DroidConBos | @D_Lemures
APPLICATION SCOPE ACTIVITY 1 SCOPE FLOW SCOPE MULTI ACTIVITY FLOWS
SOME EXAMPLES #DroidConBos | @D_Lemures
APPLICATION SCOPE ACTIVITY 1 SCOPE FLOW SCOPE ACTIVITY 2 SCOPE
MULTI ACTIVITY FLOWS SOME EXAMPLES #DroidConBos | @D_Lemures
APPLICATION SCOPE ACTIVITY 1 SCOPE FLOW SCOPE ACTIVITY 3 SCOPE
ACTIVITY 2 SCOPE MULTI ACTIVITY FLOWS SOME EXAMPLES #DroidConBos | @D_Lemures
APPLICATION SCOPE FLOW SCOPE MULTI ACTIVITY FLOWS SOME EXAMPLES #DroidConBos
| @D_Lemures
APPLICATION SCOPE MULTI ACTIVITY FLOWS SOME EXAMPLES #DroidConBos | @D_Lemures
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
@FlowSingleton public class ShoppingCart { List<PurchaseItem> purchases… } FLOW SCOPE
MULTI ACTIVITY FLOWS SOME EXAMPLES #DroidConBos | @D_Lemures
UNIT TESTING WE TEST UNITS #DroidConBos | @D_Lemures
UNIT TESTING WE TEST UNITS MOCK USES WE MOCK DEPENDENCIES
#DroidConBos | @D_Lemures
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
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
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
CONCLUSION QUESTIONS ? COMMENTS ? #DroidConBos | @D_Lemures | @GrouponEng
CONCLUSION QUESTIONS ? COMMENTS ? #DroidConBos | @D_Lemures | @GrouponEng
A FRESH APPROACH TO DI TOOTHPICK https://github.com/stephanenicolas/toothpick/ +stephane nicolas @D_Lemures