SlideShare a Scribd company logo
1 of 143
Download to read offline
Refactoring Wunderlist
for Android
César Valiente
- Episode I. The presentation layer -
Who is this guy?
Image Placeholder
César Valiente
Android Engineer @Wunderlist (@Microsoft)
Android Google Developer Expert (GDE)
+CesarValiente @CesarValiente
This is a story of…
evolution
growth
evolution
growth
simplicity
evolution
growth
simplicity
evolution
improvement
How is Wunderlist built?
How is Wunderlist built?
Android
Layer
Presentation layer
(UI and Android stuff)
Android project
How is Wunderlist built?
Android
Layer
Presentation layer
(UI and Android stuff)
Android project
Sync
Layer
Model layer
(Business logic)
Java project
How is Wunderlist built?
Android
Layer
Presentation layer
(UI and Android stuff)
Android project
Sync
Layer
Model layer
(Business logic)
Java project
Network
Layer
Network layer
(Accessing to the API data)
Java project
How is Wunderlist built?
Android
Layer
Presentation layer
(UI and Android stuff)
Android project
Sync
Layer
Model layer
(Business logic)
Java project
Network
Layer
Network layer
(Accessing to the API data)
Java project
Sync boundaries
How is Wunderlist built?
Android
Layer
Presentation layer
(UI and Android stuff)
Android project
Sync
Layer
Model layer
(Business logic)
Java project
Network
Layer
Network layer
(Accessing to the API data)
Java project
Sync boundaries Network boundaries
Dependency rule
Network
Dependency rule
Sync
Network
Dependency rule
Presentation
Sync
Network
Dependency rule
Presentation
Sync
Network
Dependency rule
The outer model knows
the inner, not viceversa.
Problems?
Problems?
Activities/Fragments become GOD classes.
Problems?
Activities/Fragments become GOD classes.
Responsibilities are messed up.
Problems?
Activities/Fragments become GOD classes.
Responsibilities are messed up.
Database in presentation layer (since it was our only Android related layer).
Problems?
Activities/Fragments become GOD classes.
Responsibilities are messed up.
Difficult to test: framework dependencies.
Database in presentation layer (since it was our only Android related layer).
Problems?
Activities/Fragments become GOD classes.
Responsibilities are messed up.
Difficult to test: framework dependencies.
Database in presentation layer (since it was our only Android related layer).
Cache in the sync layer.
Problems?
Activities/Fragments become GOD classes.
Responsibilities are messed up.
Difficult to test: framework dependencies.
Database in presentation layer (since it was our only Android related layer).
Cache in the sync layer.
Complex data schemes used also in the presentation layer, not needed here.
Problems?
Activities/Fragments become GOD classes.
Responsibilities are messed up.
Difficult to test: framework dependencies.
Database in presentation layer (since it was our only Android related layer).
Cache in the sync layer.
Complex data schemes used also in the presentation layer, not needed here.
We wanted to do it better!
What are we going to do?
What are we going to do?
We are going to separate responsibilities. Yes, Even more!
What are we going to do?
We are going to separate responsibilities. Yes, Even more!
We are going to decouple the different core elements of our app.
What are we going to do?
We are going to separate responsibilities. Yes, Even more!
We are going to decouple the different core elements of our app.
We are going to improve the way we fetch data.
What are we going to do?
We are going to separate responsibilities. Yes, Even more!
We are going to decouple the different core elements of our app.
We are going to improve the way we fetch data.
We are going to make testing easier to do, and increase our test coverage.
What are we going to do?
We are going to separate responsibilities. Yes, Even more!
We are going to decouple the different core elements of our app.
We are going to improve the way we fetch data.
We are going to make testing easier to do, and increase our test coverage.
We are going to improve our codebase.
What are we going to do?
We are going to separate responsibilities. Yes, Even more!
We are going to REFACTOR
We are going to decouple the different core elements of our app.
We are going to improve the way we fetch data.
We are going to make testing easier to do, and increase our test coverage.
We are going to improve our codebase.
Presentation
layer
Presentation
layer
App/UI
(Android project)
Presentation
layer
App/UI
(Android project)
UI domain
(Java project)
Presentation
layer
App/UI
(Android project)
UI domain
(Java project)
DB/Cache
(Android project)
Everything starts with the Model View Presenter (MVP) 😎
VIEW
Activity/Fragment
Everything starts with the Model View Presenter (MVP) 😎
VIEW
Activity/Fragment
PRESENTER
Man in the middle
Everything starts with the Model View Presenter (MVP) 😎
VIEW
Activity/Fragment
PRESENTER
Man in the middle
MODEL
Business logic
Everything starts with the Model View Presenter (MVP) 😎
VIEW
Activity/Fragment
PRESENTER
Man in the middle
MODEL
Business logic
User interacts
with the app
Everything starts with the Model View Presenter (MVP) 😎
VIEW
Activity/Fragment
PRESENTER
Man in the middle
MODEL
Business logic
Starts the
process
User interacts
with the app
Everything starts with the Model View Presenter (MVP) 😎
VIEW
Activity/Fragment
PRESENTER
Man in the middle
MODEL
Business logic
Starts the
process
Executes
use caseUser interacts
with the app
Everything starts with the Model View Presenter (MVP) 😎
VIEW
Activity/Fragment
PRESENTER
Man in the middle
MODEL
Business logic
Starts the
process
Executes
use case
Returns the result
User interacts
with the app
Everything starts with the Model View Presenter (MVP) 😎
VIEW
Activity/Fragment
PRESENTER
Man in the middle
MODEL
Business logic
Starts the
process
Executes
use case
Updates view Returns the result
User interacts
with the app
Everything starts with the Model View Presenter (MVP) 😎
VIEW PRESENTER
VIEW PRESENTER
VIEWCALLBACK
USE CASE
VIEW PRESENTER
VIEWCALLBACK
USE CASE
implements and passes
it to the presenter
VIEW PRESENTER
VIEWCALLBACK
USE CASE
implements and passes
it to the presenter
creates an
instance and passes it to the
presenter
VIEW PRESENTER
VIEWCALLBACK
USE CASE
implements and passes
it to the presenter
creates an
instance and passes it to the
presenter
will execute it to start
the process
VIEW PRESENTER
VIEWCALLBACK
USE CASE
implements and passes
it to the presenter
creates an
instance and passes it to the
presenter
will invoke it to
communicate back (when we have
the result)
will execute it to start
the process
ViewCallback
public interface ViewCallback {

void showProgressDialog();

void hideProgressDialog();

void updateList(List content);

}
View
public class SharingFragmentActivity extends WLFragmentActivity
implements ViewCallback {
private View progressDialog;

private Adapter adapter;

private SharingPresenter sharingPresenter;



public void onCreate (Bundle onSavedInstanceState) {

super.onCreate(onSavedInstanceState);



bindViews();

setupPresenters();

}
public class SharingFragmentActivity extends WLFragmentActivity
implements ViewCallback {
private View progressDialog;

private Adapter adapter;

private SharingPresenter sharingPresenter;



public void onCreate (Bundle onSavedInstanceState) {

super.onCreate(onSavedInstanceState);



bindViews();

setupPresenters();

}
public class SharingFragmentActivity extends WLFragmentActivity
implements ViewCallback {
private void setupPresenters () {

GetListMembershipUseCase getListMembershipUseCase =
new GetListMembershipUseCase(
listId, appDataController);
sharingPresenter = new SharingPresenter (
this, getListMembershipUseCase);

}
//——————— next slides ———————//
public class SharingFragmentActivity extends WLFragmentActivity
implements ViewCallback {
//——————————-— previous slide (setup) ———————————-—//
//——————— next slide (presenter invocation) ———————//
@Override void showProgressDialog() {

progressDialog.show();

}



@Override void hideProgressDialog() {

progressDialog.hide();

}



@Override void updateList(List<Memberships> list) {

adapter.updateContent(list);

}

}
public class SharingFragmentActivity extends WLFragmentActivity
implements ViewCallback {
//——————————-— previous slide (setup) ———————————-—//
//——————— next slide (presenter invocation) ———————//
implements ViewCallback {
//——————————— slide 1 (setup) —————————-—//
public class SharingFragmentActivity extends WLFragmentActivity
implements ViewCallback {
//————— slide 2 (ViewCallback impl) ————-//
@OnClick private void showListMembers () {

sharingPresenter.getListMembers();

}
//——————————— slide 1 (setup) —————————-—//
public class SharingFragmentActivity extends WLFragmentActivity
implements ViewCallback {
//————— slide 2 (ViewCallback impl) ————-//
Presenter
public class SharingPresenter extends Presenter {
public class SharingPresenter extends Presenter {
private ViewCallback viewCallback;

private GetListMembershipUseCase getListMembershipUseCase;



public SharingPresenter (
ViewCallback viewCallback,
GetListMembershipUseCase getListMembershipUseCase) {


this.viewCallback = viewCallback;

this.getListMembershipUseCase = getListMembershipUseCase;

}
//——————— next slides ———————//
public class SharingPresenter extends Presenter {
//——————————-— previous slide (setup) ———————————-—//
@Override public void onStart() {

EventBus.getDefault().register(this);

}



@Override public void onStop() {

EventBus.getDefault().unregister(this);

}
public class SharingPresenter extends Presenter {
//——————————-— previous slide (setup) ———————————-—//
@Override public void onStart() {

EventBus.getDefault().register(this);

}



@Override public void onStop() {

EventBus.getDefault().unregister(this);

}
public class SharingPresenter extends Presenter {
//——————————-— previous slide (setup) ———————————-—//
public void onEventMainThread(ListMembershipEvent event) {

viewCallback.hideProgressDialog();

viewCallback.updateList(event.getContent());

}
//——————— next slide (Use Case execution) ———————//
public class SharingPresenter extends Presenter {
//————————————- slide 1 (setup) ———————————————————-—//
//———————————— slide 2 (listening for events) ———————//
public void showListMembers () {

viewCallback.showProgressDialog();

getListMembershipUseCase.execute();

}

}
public class SharingPresenter extends Presenter {
//————————————- slide 1 (setup) ———————————————————-—//
//———————————— slide 2 (listening for events) ———————//
M
O
D
E
L
M
O
D
E
L
Use Cases
UI-Items, DB,
Cache, etc.
M
O
D
E
L
Use Cases
Use case
public class GetListMembershipUseCase
implements UseCase<List<WLMembership>> {
public class GetListMembershipUseCase
implements UseCase<List<WLMembership>> {
private String listId;

private AppDataController appDataController;



public GetListUseCase(
String listId, AppDataController appDataController) {

this.listId = listId;

this.appDataController = appDataController;

}



public class GetListMembershipUseCase
implements UseCase<List<WLMembership>> {
private String listId;

private AppDataController appDataController;



public GetListUseCase(
String listId, AppDataController appDataController) {

this.listId = listId;

this.appDataController = appDataController;

}



@Override

public void execute() {

appDataController.get(ApiObjectType.MEMBERSHIP, listId);

}

}
How were we fetching data?
LOADER
Activity/
Fragment
DB
Presentation layer
1. Using loaders
LOADER
Activity/
Fragment
DB
Presentation layer
1. Using loaders
LOADER
Activity/
Fragment
DB
Presentation layer
1. Using loaders
LOADER
Activity/
Fragment
BUS
Event or data
is fired
Presentation layer
2. Using loaders + Bus
LOADER
Activity/
Fragment
BUS
Subscription
Event or data
is fired
Presentation layer
2. Using loaders + Bus
LOADER
Activity/
Fragment
BUS
Subscription
Event or data
is fired
Data
Presentation layer
2. Using loaders + Bus
LOADER
Activity/
Fragment
BUS
Subscription Data
Event or data
is fired
Data
Presentation layer
2. Using loaders + Bus
And how do we fetch data now?
(an evolution of approaches)
1. Use case that returns data. Synchronous.
Presenter
View
Presentation layer Model
UI domain
db/
cache
U
s
e
C
a
s
e
1. Use case that returns data. Synchronous.
Presenter
View
Presentation layer Model
UI domain
db/
cache
U
s
e
C
a
s
e
1
1. Use case that returns data. Synchronous.
Presenter
View
Presentation layer Model
UI domain
db/
cache
U
s
e
C
a
s
e
1
2
1. Use case that returns data. Synchronous.
Presenter
View
Presentation layer Model
UI domain
db/
cache
U
s
e
C
a
s
e
1
2
3
1. Use case that returns data. Synchronous.
Presenter
View
Presentation layer Model
UI domain
db/
cache
U
s
e
C
a
s
e
1
2
3
4
1. Use case that returns data. Synchronous.
Presenter
View
Presentation layer Model
UI domain
db/
cache
U
s
e
C
a
s
e
1
2
5
3
4
1. Use case that returns data. Synchronous.
Presenter
View
Presentation layer Model
UI domain
db/
cache
U
s
e
C
a
s
e
1
2
5
6
3
4
2. Use case using callback. Asynchronous.
2
Presenter
View
Presentation layer Model
UI domain
db/
cache
U
s
e
C
a
s
e
2. Use case using callback. Asynchronous.
2
Presenter
View
Presentation layer Model
UI domain
db/
cache
U
s
e
C
a
s
e
1
2. Use case using callback. Asynchronous.
2
Presenter
View
Presentation layer Model
UI domain
db/
cache
U
s
e
C
a
s
e
1
2
2. Use case using callback. Asynchronous.
2
Presenter
View
Presentation layer Model
UI domain
db/
cache
U
s
e
C
a
s
e
1
2
3
2. Use case using callback. Asynchronous.
2
Presenter
View
Presentation layer Model
UI domain
db/
cache
U
s
e
C
a
s
e
1
2
3
4
2. Use case using callback. Asynchronous.
2
Presenter
View
Presentation layer Model
UI domain
db/
cache
U
s
e
C
a
s
e
1
2
5
3
4
2. Use case using callback. Asynchronous.
2
Presenter
View
Presentation layer Model
UI domain
db/
cache
U
s
e
C
a
s
e
1
2
5
6
3
4
3. Use case using an event bus.
Presenter
View
Presentation layer Model
UI
domain
db/
cache
U
s
e
C
a
s
e
BUS
3. Use case using an event bus.
Presenter
View
Presentation layer Model
UI
domain
db/
cache
U
s
e
C
a
s
e
1
BUS
3. Use case using an event bus.
Presenter
View
Presentation layer Model
UI
domain
db/
cache
U
s
e
C
a
s
e
1
2
BUS
3. Use case using an event bus.
Presenter
View
Presentation layer Model
UI
domain
db/
cache
U
s
e
C
a
s
e
1
2
BUS
3
3. Use case using an event bus.
Presenter
View
Presentation layer Model
UI
domain
db/
cache
U
s
e
C
a
s
e
1
2
BUS
3
4
3. Use case using an event bus.
Presenter
View
Presentation layer Model
UI
domain
db/
cache
U
s
e
C
a
s
e
1
2
BUS
3
45
3. Use case using an event bus.
Presenter
View
Presentation layer Model
UI
domain
db/
cache
U
s
e
C
a
s
e
1
2
6
BUS
3
45
4. Use case using RxJava
Model
UI
domain
db/
cache
OBSERVABLE
Presentation layer
VIEW
PRESENTER
OBSERVER (USE CASE)
4. Use case using RxJava
Model
UI
domain
db/
cache
OBSERVABLE
Presentation layer
VIEW
PRESENTER
OBSERVER
1
(USE CASE)
4. Use case using RxJava
Model
UI
domain
db/
cache
OBSERVABLE
Presentation layer
VIEW
PRESENTER
OBSERVER
1
2
(USE CASE)
4. Use case using RxJava
Model
UI
domain
db/
cache
OBSERVABLE
Presentation layer
VIEW
PRESENTER
OBSERVER
3
1
2
(USE CASE)
4. Use case using RxJava
Model
UI
domain
db/
cache
OBSERVABLE
Presentation layer
VIEW
PRESENTER
OBSERVER
3
4
1
2
(USE CASE)
4. Use case using RxJava
Model
UI
domain
db/
cache
OBSERVABLE
Presentation layer
VIEW
PRESENTER
OBSERVER
5
3
4
1
2
(USE CASE)
4. Use case using RxJava
Model
UI
domain
db/
cache
OBSERVABLE
Presentation layer
6
VIEW
PRESENTER
OBSERVER
5
3
4
1
2
(USE CASE)
Testing?
Testing?
Views now don’t have business logic and/or data.
Testing?
Views now don’t have business logic and/or data.
Presenters don’t have framework dependencies.
Testing?
Views now don’t have business logic and/or data.
Presenters don’t have framework dependencies.
Dependency injection make testing easier
Testing?
Views now don’t have business logic and/or data.
Presenters don’t have framework dependencies.
Use cases are very small and simple.
Dependency injection make testing easier
Testing?
Views now don’t have business logic and/or data.
Presenters don’t have framework dependencies.
Use cases are very small and simple.
We can test now every component independently.
Dependency injection make testing easier
Testing?
Views now don’t have business logic and/or data.
Presenters don’t have framework dependencies.
Use cases are very small and simple.
We can test now every component independently.
Dependency injection make testing easier
Now testing is easy peasy!
More testing?
More testing?
VIEW
Espresso
Java + Android
Mockito
JUnit
More testing?
VIEW
Espresso
Java + Android
Mockito
JUnit
PRESENTER
TestSubscriber
Mockito
JUnit
Java + RxJava
More testing?
VIEW
Espresso
Java + Android
Mockito
JUnit
PRESENTER
TestSubscriber
Mockito
JUnit
Java + RxJava
USE CASE
TestSubscriber
Mockito
JUnit
Java + RxJava
More testing?
VIEW
Espresso
Java + Android
Mockito
JUnit
PRESENTER
TestSubscriber
Mockito
JUnit
Java + RxJava
USE CASE
TestSubscriber
Mockito
JUnit
Java + RxJava
UI-
DOMAIN
TestSubscriber
Mockito
JUnit
Java + RxJava
More testing?
VIEW
Espresso
Java + Android
Mockito
JUnit
PRESENTER
TestSubscriber
Mockito
JUnit
Java + RxJava
USE CASE
TestSubscriber
Mockito
JUnit
Java + RxJava
UI-
DOMAIN
TestSubscriber
Mockito
JUnit
Java + RxJava
DB/
CACHE
Java + Android
+ RxJava
Robolectric
Mockito
JUnit
TestSubscriber
Lessons learned
Lessons learned
Dependency Inversion Principle is key.
Lessons learned
Dependency Inversion Principle is key.
Following SOLID principles makes MVP easy to build.
Lessons learned
Dependency Inversion Principle is key.
Following SOLID principles makes MVP easy to build.
Small use cases define what you want to do.
Lessons learned
Dependency Inversion Principle is key.
Following SOLID principles makes MVP easy to build.
Small use cases define what you want to do.
We have different alternatives to fetch data, choose yours.
Lessons learned
Dependency Inversion Principle is key.
Following SOLID principles makes MVP easy to build.
Small use cases define what you want to do.
We have different alternatives to fetch data, choose yours.
Decouple components makes testing easier.
?+CesarValiente @CesarValiente
+CesarValiente @CesarValiente
Thanks!
License
(cc) 2016 César Valiente. Some rights reserved. This document is
distributed under the Creative Commons Attribution-ShareAlike 3.0
license, available in http://creativecommons.org/licenses/by-sa/3.0/
Image licenses
Wunderlist (Microsoft): permission granted.
Emojis by Emoji One (CC-BY): http://emojione.com/
Iceberg: http://science-all.com/iceberg.html
All images belong to their owners.

More Related Content

What's hot

CookpadTechConf2018-(Mobile)TestAutomation
CookpadTechConf2018-(Mobile)TestAutomationCookpadTechConf2018-(Mobile)TestAutomation
CookpadTechConf2018-(Mobile)TestAutomationKazuaki Matsuo
 
Git and Git Workflow Models as Catalysts of Software Development
Git and Git Workflow Models as Catalysts of Software DevelopmentGit and Git Workflow Models as Catalysts of Software Development
Git and Git Workflow Models as Catalysts of Software DevelopmentLemi Orhan Ergin
 
MDC2011 Android_ Webdriver Automation Test
MDC2011 Android_ Webdriver Automation TestMDC2011 Android_ Webdriver Automation Test
MDC2011 Android_ Webdriver Automation TestMasud Parvez
 
Vietnam qa meetup
Vietnam qa meetupVietnam qa meetup
Vietnam qa meetupSyam Sasi
 
Spring roo for entrepreneurs
Spring roo for entrepreneursSpring roo for entrepreneurs
Spring roo for entrepreneursMans Jug
 
Android Automation Testing with Selendroid
Android Automation Testing with SelendroidAndroid Automation Testing with Selendroid
Android Automation Testing with SelendroidVikas Thange
 
4 Ways to Speed Up Your Mobile App Dev Daily Grind
4 Ways to Speed Up Your Mobile App Dev Daily Grind4 Ways to Speed Up Your Mobile App Dev Daily Grind
4 Ways to Speed Up Your Mobile App Dev Daily GrindPerfecto by Perforce
 
Cross Platform Application Development Using Flutter
Cross Platform Application Development Using FlutterCross Platform Application Development Using Flutter
Cross Platform Application Development Using FlutterAbhishek Kumar Gupta
 
Android SDK and PhoneGap
Android SDK and PhoneGapAndroid SDK and PhoneGap
Android SDK and PhoneGapDoncho Minkov
 
Mobile WebDriver Selendroid
Mobile WebDriver SelendroidMobile WebDriver Selendroid
Mobile WebDriver SelendroidDominik Dary
 
Make the Shift from Manual to Automation with Open Source
Make the Shift from Manual to Automation with Open SourceMake the Shift from Manual to Automation with Open Source
Make the Shift from Manual to Automation with Open SourcePerfecto by Perforce
 
Lesson 2 introduction in computing
Lesson 2 introduction in computingLesson 2 introduction in computing
Lesson 2 introduction in computingProfessor Thor
 
Getting started with appium
Getting started with appiumGetting started with appium
Getting started with appiumPratik Patel
 
Testing desktop apps with selenium
Testing desktop apps with seleniumTesting desktop apps with selenium
Testing desktop apps with seleniumFilip Braun
 
Android Test Automation – one year later
Android Test Automation – one year laterAndroid Test Automation – one year later
Android Test Automation – one year laterDominik Dary
 

What's hot (20)

CookpadTechConf2018-(Mobile)TestAutomation
CookpadTechConf2018-(Mobile)TestAutomationCookpadTechConf2018-(Mobile)TestAutomation
CookpadTechConf2018-(Mobile)TestAutomation
 
Git and Git Workflow Models as Catalysts of Software Development
Git and Git Workflow Models as Catalysts of Software DevelopmentGit and Git Workflow Models as Catalysts of Software Development
Git and Git Workflow Models as Catalysts of Software Development
 
MDC2011 Android_ Webdriver Automation Test
MDC2011 Android_ Webdriver Automation TestMDC2011 Android_ Webdriver Automation Test
MDC2011 Android_ Webdriver Automation Test
 
Vietnam qa meetup
Vietnam qa meetupVietnam qa meetup
Vietnam qa meetup
 
Spring roo for entrepreneurs
Spring roo for entrepreneursSpring roo for entrepreneurs
Spring roo for entrepreneurs
 
Android Automation Testing with Selendroid
Android Automation Testing with SelendroidAndroid Automation Testing with Selendroid
Android Automation Testing with Selendroid
 
4 Ways to Speed Up Your Mobile App Dev Daily Grind
4 Ways to Speed Up Your Mobile App Dev Daily Grind4 Ways to Speed Up Your Mobile App Dev Daily Grind
4 Ways to Speed Up Your Mobile App Dev Daily Grind
 
Cross Platform Application Development Using Flutter
Cross Platform Application Development Using FlutterCross Platform Application Development Using Flutter
Cross Platform Application Development Using Flutter
 
Android SDK and PhoneGap
Android SDK and PhoneGapAndroid SDK and PhoneGap
Android SDK and PhoneGap
 
Mobile WebDriver Selendroid
Mobile WebDriver SelendroidMobile WebDriver Selendroid
Mobile WebDriver Selendroid
 
Appium overview
Appium overviewAppium overview
Appium overview
 
Summary Of Polycom Cast App
Summary Of Polycom Cast AppSummary Of Polycom Cast App
Summary Of Polycom Cast App
 
Make the Shift from Manual to Automation with Open Source
Make the Shift from Manual to Automation with Open SourceMake the Shift from Manual to Automation with Open Source
Make the Shift from Manual to Automation with Open Source
 
Lesson 2 introduction in computing
Lesson 2 introduction in computingLesson 2 introduction in computing
Lesson 2 introduction in computing
 
Appium solution
Appium solutionAppium solution
Appium solution
 
Appium
AppiumAppium
Appium
 
Getting started with appium
Getting started with appiumGetting started with appium
Getting started with appium
 
Testing desktop apps with selenium
Testing desktop apps with seleniumTesting desktop apps with selenium
Testing desktop apps with selenium
 
Android studio
Android studioAndroid studio
Android studio
 
Android Test Automation – one year later
Android Test Automation – one year laterAndroid Test Automation – one year later
Android Test Automation – one year later
 

Similar to Refactoring Wunderlist for Android presentation layer

Vaadin DevDay 2017 - DI your UI
Vaadin DevDay 2017 - DI your UIVaadin DevDay 2017 - DI your UI
Vaadin DevDay 2017 - DI your UIPeter Lehto
 
From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)Jose Manuel Pereira Garcia
 
React Native +Redux + ES6 (Updated)
React Native +Redux + ES6 (Updated)React Native +Redux + ES6 (Updated)
React Native +Redux + ES6 (Updated)Chiew Carol
 
How to code to code less
How to code to code lessHow to code to code less
How to code to code lessAnton Novikau
 
Spring Roo and the Cloud (Tutorial) [5th IndicThreads.com Conference On Java,...
Spring Roo and the Cloud (Tutorial) [5th IndicThreads.com Conference On Java,...Spring Roo and the Cloud (Tutorial) [5th IndicThreads.com Conference On Java,...
Spring Roo and the Cloud (Tutorial) [5th IndicThreads.com Conference On Java,...IndicThreads
 
Angular js mobile jsday 2014 - Verona 14 may
Angular js mobile   jsday 2014 - Verona 14 mayAngular js mobile   jsday 2014 - Verona 14 may
Angular js mobile jsday 2014 - Verona 14 mayLuciano Amodio
 
Apache Cordova In Action
Apache Cordova In ActionApache Cordova In Action
Apache Cordova In ActionHazem Saleh
 
Beginning Native Android Apps
Beginning Native Android AppsBeginning Native Android Apps
Beginning Native Android AppsGil Irizarry
 
Building a full-stack app with Golang and Google Cloud Platform in one week
Building a full-stack app with Golang and Google Cloud Platform in one weekBuilding a full-stack app with Golang and Google Cloud Platform in one week
Building a full-stack app with Golang and Google Cloud Platform in one weekDr. Felix Raab
 
Testing Big in JavaScript
Testing Big in JavaScriptTesting Big in JavaScript
Testing Big in JavaScriptRobert DeLuca
 
Modular Test-driven SPAs with Spring and AngularJS
Modular Test-driven SPAs with Spring and AngularJSModular Test-driven SPAs with Spring and AngularJS
Modular Test-driven SPAs with Spring and AngularJSGunnar Hillert
 
Indic threads java10-spring-roo-and-the-cloud
Indic threads java10-spring-roo-and-the-cloudIndic threads java10-spring-roo-and-the-cloud
Indic threads java10-spring-roo-and-the-cloudShekhar Gulati
 
The State of Front-end At CrowdTwist
The State of Front-end At CrowdTwistThe State of Front-end At CrowdTwist
The State of Front-end At CrowdTwistMark Fayngersh
 
A gently introduction to AngularJS
A gently introduction to AngularJSA gently introduction to AngularJS
A gently introduction to AngularJSGregor Woiwode
 
Android the Agile way
Android the Agile wayAndroid the Agile way
Android the Agile wayAshwin Raghav
 
From Idea to App (or “How we roll at Small Town Heroes”)
From Idea to App (or “How we roll at Small Town Heroes”)From Idea to App (or “How we roll at Small Town Heroes”)
From Idea to App (or “How we roll at Small Town Heroes”)Bramus Van Damme
 
Yeoman AngularJS and D3 - A solid stack for web apps
Yeoman AngularJS and D3 - A solid stack for web appsYeoman AngularJS and D3 - A solid stack for web apps
Yeoman AngularJS and D3 - A solid stack for web appsclimboid
 

Similar to Refactoring Wunderlist for Android presentation layer (20)

Vaadin DevDay 2017 - DI your UI
Vaadin DevDay 2017 - DI your UIVaadin DevDay 2017 - DI your UI
Vaadin DevDay 2017 - DI your UI
 
Going web native
Going web nativeGoing web native
Going web native
 
From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)
 
React Native +Redux + ES6 (Updated)
React Native +Redux + ES6 (Updated)React Native +Redux + ES6 (Updated)
React Native +Redux + ES6 (Updated)
 
How to code to code less
How to code to code lessHow to code to code less
How to code to code less
 
Spring Roo and the Cloud (Tutorial) [5th IndicThreads.com Conference On Java,...
Spring Roo and the Cloud (Tutorial) [5th IndicThreads.com Conference On Java,...Spring Roo and the Cloud (Tutorial) [5th IndicThreads.com Conference On Java,...
Spring Roo and the Cloud (Tutorial) [5th IndicThreads.com Conference On Java,...
 
Angular js mobile jsday 2014 - Verona 14 may
Angular js mobile   jsday 2014 - Verona 14 mayAngular js mobile   jsday 2014 - Verona 14 may
Angular js mobile jsday 2014 - Verona 14 may
 
Apache Cordova In Action
Apache Cordova In ActionApache Cordova In Action
Apache Cordova In Action
 
Beginning Native Android Apps
Beginning Native Android AppsBeginning Native Android Apps
Beginning Native Android Apps
 
Spring boot
Spring bootSpring boot
Spring boot
 
Building a full-stack app with Golang and Google Cloud Platform in one week
Building a full-stack app with Golang and Google Cloud Platform in one weekBuilding a full-stack app with Golang and Google Cloud Platform in one week
Building a full-stack app with Golang and Google Cloud Platform in one week
 
Testing Big in JavaScript
Testing Big in JavaScriptTesting Big in JavaScript
Testing Big in JavaScript
 
Modular Test-driven SPAs with Spring and AngularJS
Modular Test-driven SPAs with Spring and AngularJSModular Test-driven SPAs with Spring and AngularJS
Modular Test-driven SPAs with Spring and AngularJS
 
Indic threads java10-spring-roo-and-the-cloud
Indic threads java10-spring-roo-and-the-cloudIndic threads java10-spring-roo-and-the-cloud
Indic threads java10-spring-roo-and-the-cloud
 
The State of Front-end At CrowdTwist
The State of Front-end At CrowdTwistThe State of Front-end At CrowdTwist
The State of Front-end At CrowdTwist
 
A gently introduction to AngularJS
A gently introduction to AngularJSA gently introduction to AngularJS
A gently introduction to AngularJS
 
Android the Agile way
Android the Agile wayAndroid the Agile way
Android the Agile way
 
Hands on the Gradle
Hands on the GradleHands on the Gradle
Hands on the Gradle
 
From Idea to App (or “How we roll at Small Town Heroes”)
From Idea to App (or “How we roll at Small Town Heroes”)From Idea to App (or “How we roll at Small Town Heroes”)
From Idea to App (or “How we roll at Small Town Heroes”)
 
Yeoman AngularJS and D3 - A solid stack for web apps
Yeoman AngularJS and D3 - A solid stack for web appsYeoman AngularJS and D3 - A solid stack for web apps
Yeoman AngularJS and D3 - A solid stack for web apps
 

More from UA Mobile

Designing iOS+Android project without using multiplatform frameworks - UA Mob...
Designing iOS+Android project without using multiplatform frameworks - UA Mob...Designing iOS+Android project without using multiplatform frameworks - UA Mob...
Designing iOS+Android project without using multiplatform frameworks - UA Mob...UA Mobile
 
Декларативное программирование клиент-серверных приложений на андроид - UA Mo...
Декларативное программирование клиент-серверных приложений на андроид - UA Mo...Декларативное программирование клиент-серверных приложений на андроид - UA Mo...
Декларативное программирование клиент-серверных приложений на андроид - UA Mo...UA Mobile
 
Leave your Room behind - UA Mobile 2019
Leave your Room behind - UA Mobile 2019Leave your Room behind - UA Mobile 2019
Leave your Room behind - UA Mobile 2019UA Mobile
 
OpenId and OAuth2: Rear, Medium, Well Done - UA Mobile 2019
OpenId and OAuth2: Rear, Medium, Well Done - UA Mobile 2019OpenId and OAuth2: Rear, Medium, Well Done - UA Mobile 2019
OpenId and OAuth2: Rear, Medium, Well Done - UA Mobile 2019UA Mobile
 
Google Wear OS watch faces and applications development - UA Mobile 2019
Google Wear OS watch faces and applications development - UA Mobile 2019Google Wear OS watch faces and applications development - UA Mobile 2019
Google Wear OS watch faces and applications development - UA Mobile 2019UA Mobile
 
Історія декількох проектів та що в них пішло не так - UA Mobile 2019
Історія декількох проектів та що в них пішло не так - UA Mobile 2019Історія декількох проектів та що в них пішло не так - UA Mobile 2019
Історія декількох проектів та що в них пішло не так - UA Mobile 2019UA Mobile
 
Working effectively with ViewModels and TDD - UA Mobile 2019
Working effectively with ViewModels and TDD - UA Mobile 2019Working effectively with ViewModels and TDD - UA Mobile 2019
Working effectively with ViewModels and TDD - UA Mobile 2019UA Mobile
 
Managing State in Reactive applications - UA Mobile 2019
Managing State in Reactive applications - UA Mobile 2019Managing State in Reactive applications - UA Mobile 2019
Managing State in Reactive applications - UA Mobile 2019UA Mobile
 
Ідіоматична ін'єкція залежностей на Kotlin без фреймворків - UA Mobile2019
Ідіоматична ін'єкція залежностей на Kotlin без фреймворків - UA Mobile2019Ідіоматична ін'єкція залежностей на Kotlin без фреймворків - UA Mobile2019
Ідіоматична ін'єкція залежностей на Kotlin без фреймворків - UA Mobile2019UA Mobile
 
Актуальні практики дизайну мобільних додатків - UA Mobile 2019
Актуальні практики дизайну мобільних додатків - UA Mobile 2019Актуальні практики дизайну мобільних додатків - UA Mobile 2019
Актуальні практики дизайну мобільних додатків - UA Mobile 2019UA Mobile
 
До чого прикладати Docker в Android? - UA Mobile 2019
До чого прикладати Docker в Android? - UA Mobile 2019До чого прикладати Docker в Android? - UA Mobile 2019
До чого прикладати Docker в Android? - UA Mobile 2019UA Mobile
 
Building your Flutter apps using Redux - UA Mobile 2019
Building your Flutter apps using Redux - UA Mobile 2019Building your Flutter apps using Redux - UA Mobile 2019
Building your Flutter apps using Redux - UA Mobile 2019UA Mobile
 
Optional. Tips and Tricks - UA Mobile 2019
Optional. Tips and Tricks - UA Mobile 2019Optional. Tips and Tricks - UA Mobile 2019
Optional. Tips and Tricks - UA Mobile 2019UA Mobile
 
Designing iOS+Android project without using multiplatform frameworks - UA Mob...
Designing iOS+Android project without using multiplatform frameworks - UA Mob...Designing iOS+Android project without using multiplatform frameworks - UA Mob...
Designing iOS+Android project without using multiplatform frameworks - UA Mob...UA Mobile
 
Бібліотеки та Інструменти на сторожі коду - UA Mobile 2019
Бібліотеки та Інструменти на сторожі коду - UA Mobile 2019Бібліотеки та Інструменти на сторожі коду - UA Mobile 2019
Бібліотеки та Інструменти на сторожі коду - UA Mobile 2019UA Mobile
 
Flutter: No more boring apps! - UA Mobile 2019
Flutter: No more boring apps! - UA Mobile 2019Flutter: No more boring apps! - UA Mobile 2019
Flutter: No more boring apps! - UA Mobile 2019UA Mobile
 
Долаючи прірву між дизайнерами та розробниками - UA Mobile 2019
Долаючи прірву між дизайнерами та розробниками - UA Mobile 2019Долаючи прірву між дизайнерами та розробниками - UA Mobile 2019
Долаючи прірву між дизайнерами та розробниками - UA Mobile 2019UA Mobile
 
Multiplatform shared codebase with Kotlin/Native - UA Mobile 2019
Multiplatform shared codebase with Kotlin/Native - UA Mobile 2019Multiplatform shared codebase with Kotlin/Native - UA Mobile 2019
Multiplatform shared codebase with Kotlin/Native - UA Mobile 2019UA Mobile
 
Sceneform SDK на практиці - UA Mobile 2019
Sceneform SDK на практиці - UA Mobile 2019Sceneform SDK на практиці - UA Mobile 2019
Sceneform SDK на практиці - UA Mobile 2019UA Mobile
 
Coroutines in Kotlin. UA Mobile 2017.
Coroutines in Kotlin. UA Mobile 2017.Coroutines in Kotlin. UA Mobile 2017.
Coroutines in Kotlin. UA Mobile 2017.UA Mobile
 

More from UA Mobile (20)

Designing iOS+Android project without using multiplatform frameworks - UA Mob...
Designing iOS+Android project without using multiplatform frameworks - UA Mob...Designing iOS+Android project without using multiplatform frameworks - UA Mob...
Designing iOS+Android project without using multiplatform frameworks - UA Mob...
 
Декларативное программирование клиент-серверных приложений на андроид - UA Mo...
Декларативное программирование клиент-серверных приложений на андроид - UA Mo...Декларативное программирование клиент-серверных приложений на андроид - UA Mo...
Декларативное программирование клиент-серверных приложений на андроид - UA Mo...
 
Leave your Room behind - UA Mobile 2019
Leave your Room behind - UA Mobile 2019Leave your Room behind - UA Mobile 2019
Leave your Room behind - UA Mobile 2019
 
OpenId and OAuth2: Rear, Medium, Well Done - UA Mobile 2019
OpenId and OAuth2: Rear, Medium, Well Done - UA Mobile 2019OpenId and OAuth2: Rear, Medium, Well Done - UA Mobile 2019
OpenId and OAuth2: Rear, Medium, Well Done - UA Mobile 2019
 
Google Wear OS watch faces and applications development - UA Mobile 2019
Google Wear OS watch faces and applications development - UA Mobile 2019Google Wear OS watch faces and applications development - UA Mobile 2019
Google Wear OS watch faces and applications development - UA Mobile 2019
 
Історія декількох проектів та що в них пішло не так - UA Mobile 2019
Історія декількох проектів та що в них пішло не так - UA Mobile 2019Історія декількох проектів та що в них пішло не так - UA Mobile 2019
Історія декількох проектів та що в них пішло не так - UA Mobile 2019
 
Working effectively with ViewModels and TDD - UA Mobile 2019
Working effectively with ViewModels and TDD - UA Mobile 2019Working effectively with ViewModels and TDD - UA Mobile 2019
Working effectively with ViewModels and TDD - UA Mobile 2019
 
Managing State in Reactive applications - UA Mobile 2019
Managing State in Reactive applications - UA Mobile 2019Managing State in Reactive applications - UA Mobile 2019
Managing State in Reactive applications - UA Mobile 2019
 
Ідіоматична ін'єкція залежностей на Kotlin без фреймворків - UA Mobile2019
Ідіоматична ін'єкція залежностей на Kotlin без фреймворків - UA Mobile2019Ідіоматична ін'єкція залежностей на Kotlin без фреймворків - UA Mobile2019
Ідіоматична ін'єкція залежностей на Kotlin без фреймворків - UA Mobile2019
 
Актуальні практики дизайну мобільних додатків - UA Mobile 2019
Актуальні практики дизайну мобільних додатків - UA Mobile 2019Актуальні практики дизайну мобільних додатків - UA Mobile 2019
Актуальні практики дизайну мобільних додатків - UA Mobile 2019
 
До чого прикладати Docker в Android? - UA Mobile 2019
До чого прикладати Docker в Android? - UA Mobile 2019До чого прикладати Docker в Android? - UA Mobile 2019
До чого прикладати Docker в Android? - UA Mobile 2019
 
Building your Flutter apps using Redux - UA Mobile 2019
Building your Flutter apps using Redux - UA Mobile 2019Building your Flutter apps using Redux - UA Mobile 2019
Building your Flutter apps using Redux - UA Mobile 2019
 
Optional. Tips and Tricks - UA Mobile 2019
Optional. Tips and Tricks - UA Mobile 2019Optional. Tips and Tricks - UA Mobile 2019
Optional. Tips and Tricks - UA Mobile 2019
 
Designing iOS+Android project without using multiplatform frameworks - UA Mob...
Designing iOS+Android project without using multiplatform frameworks - UA Mob...Designing iOS+Android project without using multiplatform frameworks - UA Mob...
Designing iOS+Android project without using multiplatform frameworks - UA Mob...
 
Бібліотеки та Інструменти на сторожі коду - UA Mobile 2019
Бібліотеки та Інструменти на сторожі коду - UA Mobile 2019Бібліотеки та Інструменти на сторожі коду - UA Mobile 2019
Бібліотеки та Інструменти на сторожі коду - UA Mobile 2019
 
Flutter: No more boring apps! - UA Mobile 2019
Flutter: No more boring apps! - UA Mobile 2019Flutter: No more boring apps! - UA Mobile 2019
Flutter: No more boring apps! - UA Mobile 2019
 
Долаючи прірву між дизайнерами та розробниками - UA Mobile 2019
Долаючи прірву між дизайнерами та розробниками - UA Mobile 2019Долаючи прірву між дизайнерами та розробниками - UA Mobile 2019
Долаючи прірву між дизайнерами та розробниками - UA Mobile 2019
 
Multiplatform shared codebase with Kotlin/Native - UA Mobile 2019
Multiplatform shared codebase with Kotlin/Native - UA Mobile 2019Multiplatform shared codebase with Kotlin/Native - UA Mobile 2019
Multiplatform shared codebase with Kotlin/Native - UA Mobile 2019
 
Sceneform SDK на практиці - UA Mobile 2019
Sceneform SDK на практиці - UA Mobile 2019Sceneform SDK на практиці - UA Mobile 2019
Sceneform SDK на практиці - UA Mobile 2019
 
Coroutines in Kotlin. UA Mobile 2017.
Coroutines in Kotlin. UA Mobile 2017.Coroutines in Kotlin. UA Mobile 2017.
Coroutines in Kotlin. UA Mobile 2017.
 

Recently uploaded

The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionSolGuruz
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...panagenda
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsAndolasoft Inc
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AIABDERRAOUF MEHENNI
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceCALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceanilsa9823
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 

Recently uploaded (20)

The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceCALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 

Refactoring Wunderlist for Android presentation layer

  • 1. Refactoring Wunderlist for Android César Valiente - Episode I. The presentation layer -
  • 2. Who is this guy? Image Placeholder César Valiente Android Engineer @Wunderlist (@Microsoft) Android Google Developer Expert (GDE) +CesarValiente @CesarValiente
  • 3. This is a story of…
  • 9. How is Wunderlist built? Android Layer Presentation layer (UI and Android stuff) Android project
  • 10. How is Wunderlist built? Android Layer Presentation layer (UI and Android stuff) Android project Sync Layer Model layer (Business logic) Java project
  • 11. How is Wunderlist built? Android Layer Presentation layer (UI and Android stuff) Android project Sync Layer Model layer (Business logic) Java project Network Layer Network layer (Accessing to the API data) Java project
  • 12. How is Wunderlist built? Android Layer Presentation layer (UI and Android stuff) Android project Sync Layer Model layer (Business logic) Java project Network Layer Network layer (Accessing to the API data) Java project Sync boundaries
  • 13. How is Wunderlist built? Android Layer Presentation layer (UI and Android stuff) Android project Sync Layer Model layer (Business logic) Java project Network Layer Network layer (Accessing to the API data) Java project Sync boundaries Network boundaries
  • 18. Presentation Sync Network Dependency rule The outer model knows the inner, not viceversa.
  • 21. Problems? Activities/Fragments become GOD classes. Responsibilities are messed up.
  • 22. Problems? Activities/Fragments become GOD classes. Responsibilities are messed up. Database in presentation layer (since it was our only Android related layer).
  • 23. Problems? Activities/Fragments become GOD classes. Responsibilities are messed up. Difficult to test: framework dependencies. Database in presentation layer (since it was our only Android related layer).
  • 24. Problems? Activities/Fragments become GOD classes. Responsibilities are messed up. Difficult to test: framework dependencies. Database in presentation layer (since it was our only Android related layer). Cache in the sync layer.
  • 25. Problems? Activities/Fragments become GOD classes. Responsibilities are messed up. Difficult to test: framework dependencies. Database in presentation layer (since it was our only Android related layer). Cache in the sync layer. Complex data schemes used also in the presentation layer, not needed here.
  • 26. Problems? Activities/Fragments become GOD classes. Responsibilities are messed up. Difficult to test: framework dependencies. Database in presentation layer (since it was our only Android related layer). Cache in the sync layer. Complex data schemes used also in the presentation layer, not needed here. We wanted to do it better!
  • 27. What are we going to do?
  • 28. What are we going to do? We are going to separate responsibilities. Yes, Even more!
  • 29. What are we going to do? We are going to separate responsibilities. Yes, Even more! We are going to decouple the different core elements of our app.
  • 30. What are we going to do? We are going to separate responsibilities. Yes, Even more! We are going to decouple the different core elements of our app. We are going to improve the way we fetch data.
  • 31. What are we going to do? We are going to separate responsibilities. Yes, Even more! We are going to decouple the different core elements of our app. We are going to improve the way we fetch data. We are going to make testing easier to do, and increase our test coverage.
  • 32. What are we going to do? We are going to separate responsibilities. Yes, Even more! We are going to decouple the different core elements of our app. We are going to improve the way we fetch data. We are going to make testing easier to do, and increase our test coverage. We are going to improve our codebase.
  • 33. What are we going to do? We are going to separate responsibilities. Yes, Even more! We are going to REFACTOR We are going to decouple the different core elements of our app. We are going to improve the way we fetch data. We are going to make testing easier to do, and increase our test coverage. We are going to improve our codebase.
  • 37. Presentation layer App/UI (Android project) UI domain (Java project) DB/Cache (Android project)
  • 38. Everything starts with the Model View Presenter (MVP) 😎
  • 39. VIEW Activity/Fragment Everything starts with the Model View Presenter (MVP) 😎
  • 40. VIEW Activity/Fragment PRESENTER Man in the middle Everything starts with the Model View Presenter (MVP) 😎
  • 41. VIEW Activity/Fragment PRESENTER Man in the middle MODEL Business logic Everything starts with the Model View Presenter (MVP) 😎
  • 42. VIEW Activity/Fragment PRESENTER Man in the middle MODEL Business logic User interacts with the app Everything starts with the Model View Presenter (MVP) 😎
  • 43. VIEW Activity/Fragment PRESENTER Man in the middle MODEL Business logic Starts the process User interacts with the app Everything starts with the Model View Presenter (MVP) 😎
  • 44. VIEW Activity/Fragment PRESENTER Man in the middle MODEL Business logic Starts the process Executes use caseUser interacts with the app Everything starts with the Model View Presenter (MVP) 😎
  • 45. VIEW Activity/Fragment PRESENTER Man in the middle MODEL Business logic Starts the process Executes use case Returns the result User interacts with the app Everything starts with the Model View Presenter (MVP) 😎
  • 46. VIEW Activity/Fragment PRESENTER Man in the middle MODEL Business logic Starts the process Executes use case Updates view Returns the result User interacts with the app Everything starts with the Model View Presenter (MVP) 😎
  • 47.
  • 50. VIEW PRESENTER VIEWCALLBACK USE CASE implements and passes it to the presenter
  • 51. VIEW PRESENTER VIEWCALLBACK USE CASE implements and passes it to the presenter creates an instance and passes it to the presenter
  • 52. VIEW PRESENTER VIEWCALLBACK USE CASE implements and passes it to the presenter creates an instance and passes it to the presenter will execute it to start the process
  • 53. VIEW PRESENTER VIEWCALLBACK USE CASE implements and passes it to the presenter creates an instance and passes it to the presenter will invoke it to communicate back (when we have the result) will execute it to start the process
  • 55. public interface ViewCallback {
 void showProgressDialog();
 void hideProgressDialog();
 void updateList(List content);
 }
  • 56. View
  • 57. public class SharingFragmentActivity extends WLFragmentActivity implements ViewCallback {
  • 58. private View progressDialog;
 private Adapter adapter;
 private SharingPresenter sharingPresenter;
 
 public void onCreate (Bundle onSavedInstanceState) {
 super.onCreate(onSavedInstanceState);
 
 bindViews();
 setupPresenters();
 } public class SharingFragmentActivity extends WLFragmentActivity implements ViewCallback {
  • 59. private View progressDialog;
 private Adapter adapter;
 private SharingPresenter sharingPresenter;
 
 public void onCreate (Bundle onSavedInstanceState) {
 super.onCreate(onSavedInstanceState);
 
 bindViews();
 setupPresenters();
 } public class SharingFragmentActivity extends WLFragmentActivity implements ViewCallback { private void setupPresenters () {
 GetListMembershipUseCase getListMembershipUseCase = new GetListMembershipUseCase( listId, appDataController); sharingPresenter = new SharingPresenter ( this, getListMembershipUseCase);
 } //——————— next slides ———————//
  • 60.
  • 61. public class SharingFragmentActivity extends WLFragmentActivity implements ViewCallback { //——————————-— previous slide (setup) ———————————-—// //——————— next slide (presenter invocation) ———————//
  • 62. @Override void showProgressDialog() {
 progressDialog.show();
 }
 
 @Override void hideProgressDialog() {
 progressDialog.hide();
 }
 
 @Override void updateList(List<Memberships> list) {
 adapter.updateContent(list);
 }
 } public class SharingFragmentActivity extends WLFragmentActivity implements ViewCallback { //——————————-— previous slide (setup) ———————————-—// //——————— next slide (presenter invocation) ———————// implements ViewCallback {
  • 63.
  • 64. //——————————— slide 1 (setup) —————————-—// public class SharingFragmentActivity extends WLFragmentActivity implements ViewCallback { //————— slide 2 (ViewCallback impl) ————-//
  • 65. @OnClick private void showListMembers () {
 sharingPresenter.getListMembers();
 } //——————————— slide 1 (setup) —————————-—// public class SharingFragmentActivity extends WLFragmentActivity implements ViewCallback { //————— slide 2 (ViewCallback impl) ————-//
  • 67. public class SharingPresenter extends Presenter {
  • 68. public class SharingPresenter extends Presenter { private ViewCallback viewCallback;
 private GetListMembershipUseCase getListMembershipUseCase;
 
 public SharingPresenter ( ViewCallback viewCallback, GetListMembershipUseCase getListMembershipUseCase) { 
 this.viewCallback = viewCallback;
 this.getListMembershipUseCase = getListMembershipUseCase;
 } //——————— next slides ———————//
  • 69.
  • 70. public class SharingPresenter extends Presenter { //——————————-— previous slide (setup) ———————————-—//
  • 71. @Override public void onStart() {
 EventBus.getDefault().register(this);
 }
 
 @Override public void onStop() {
 EventBus.getDefault().unregister(this);
 } public class SharingPresenter extends Presenter { //——————————-— previous slide (setup) ———————————-—//
  • 72. @Override public void onStart() {
 EventBus.getDefault().register(this);
 }
 
 @Override public void onStop() {
 EventBus.getDefault().unregister(this);
 } public class SharingPresenter extends Presenter { //——————————-— previous slide (setup) ———————————-—// public void onEventMainThread(ListMembershipEvent event) {
 viewCallback.hideProgressDialog();
 viewCallback.updateList(event.getContent());
 } //——————— next slide (Use Case execution) ———————//
  • 73.
  • 74. public class SharingPresenter extends Presenter { //————————————- slide 1 (setup) ———————————————————-—// //———————————— slide 2 (listening for events) ———————//
  • 75. public void showListMembers () {
 viewCallback.showProgressDialog();
 getListMembershipUseCase.execute();
 }
 } public class SharingPresenter extends Presenter { //————————————- slide 1 (setup) ———————————————————-—// //———————————— slide 2 (listening for events) ———————//
  • 76.
  • 81. public class GetListMembershipUseCase implements UseCase<List<WLMembership>> {
  • 82. public class GetListMembershipUseCase implements UseCase<List<WLMembership>> { private String listId;
 private AppDataController appDataController;
 
 public GetListUseCase( String listId, AppDataController appDataController) {
 this.listId = listId;
 this.appDataController = appDataController;
 }
 

  • 83. public class GetListMembershipUseCase implements UseCase<List<WLMembership>> { private String listId;
 private AppDataController appDataController;
 
 public GetListUseCase( String listId, AppDataController appDataController) {
 this.listId = listId;
 this.appDataController = appDataController;
 }
 
 @Override
 public void execute() {
 appDataController.get(ApiObjectType.MEMBERSHIP, listId);
 }
 }
  • 84. How were we fetching data?
  • 88. LOADER Activity/ Fragment BUS Event or data is fired Presentation layer 2. Using loaders + Bus
  • 89. LOADER Activity/ Fragment BUS Subscription Event or data is fired Presentation layer 2. Using loaders + Bus
  • 90. LOADER Activity/ Fragment BUS Subscription Event or data is fired Data Presentation layer 2. Using loaders + Bus
  • 91. LOADER Activity/ Fragment BUS Subscription Data Event or data is fired Data Presentation layer 2. Using loaders + Bus
  • 92. And how do we fetch data now? (an evolution of approaches)
  • 93. 1. Use case that returns data. Synchronous. Presenter View Presentation layer Model UI domain db/ cache U s e C a s e
  • 94. 1. Use case that returns data. Synchronous. Presenter View Presentation layer Model UI domain db/ cache U s e C a s e 1
  • 95. 1. Use case that returns data. Synchronous. Presenter View Presentation layer Model UI domain db/ cache U s e C a s e 1 2
  • 96. 1. Use case that returns data. Synchronous. Presenter View Presentation layer Model UI domain db/ cache U s e C a s e 1 2 3
  • 97. 1. Use case that returns data. Synchronous. Presenter View Presentation layer Model UI domain db/ cache U s e C a s e 1 2 3 4
  • 98. 1. Use case that returns data. Synchronous. Presenter View Presentation layer Model UI domain db/ cache U s e C a s e 1 2 5 3 4
  • 99. 1. Use case that returns data. Synchronous. Presenter View Presentation layer Model UI domain db/ cache U s e C a s e 1 2 5 6 3 4
  • 100. 2. Use case using callback. Asynchronous. 2 Presenter View Presentation layer Model UI domain db/ cache U s e C a s e
  • 101. 2. Use case using callback. Asynchronous. 2 Presenter View Presentation layer Model UI domain db/ cache U s e C a s e 1
  • 102. 2. Use case using callback. Asynchronous. 2 Presenter View Presentation layer Model UI domain db/ cache U s e C a s e 1 2
  • 103. 2. Use case using callback. Asynchronous. 2 Presenter View Presentation layer Model UI domain db/ cache U s e C a s e 1 2 3
  • 104. 2. Use case using callback. Asynchronous. 2 Presenter View Presentation layer Model UI domain db/ cache U s e C a s e 1 2 3 4
  • 105. 2. Use case using callback. Asynchronous. 2 Presenter View Presentation layer Model UI domain db/ cache U s e C a s e 1 2 5 3 4
  • 106. 2. Use case using callback. Asynchronous. 2 Presenter View Presentation layer Model UI domain db/ cache U s e C a s e 1 2 5 6 3 4
  • 107. 3. Use case using an event bus. Presenter View Presentation layer Model UI domain db/ cache U s e C a s e BUS
  • 108. 3. Use case using an event bus. Presenter View Presentation layer Model UI domain db/ cache U s e C a s e 1 BUS
  • 109. 3. Use case using an event bus. Presenter View Presentation layer Model UI domain db/ cache U s e C a s e 1 2 BUS
  • 110. 3. Use case using an event bus. Presenter View Presentation layer Model UI domain db/ cache U s e C a s e 1 2 BUS 3
  • 111. 3. Use case using an event bus. Presenter View Presentation layer Model UI domain db/ cache U s e C a s e 1 2 BUS 3 4
  • 112. 3. Use case using an event bus. Presenter View Presentation layer Model UI domain db/ cache U s e C a s e 1 2 BUS 3 45
  • 113. 3. Use case using an event bus. Presenter View Presentation layer Model UI domain db/ cache U s e C a s e 1 2 6 BUS 3 45
  • 114. 4. Use case using RxJava Model UI domain db/ cache OBSERVABLE Presentation layer VIEW PRESENTER OBSERVER (USE CASE)
  • 115. 4. Use case using RxJava Model UI domain db/ cache OBSERVABLE Presentation layer VIEW PRESENTER OBSERVER 1 (USE CASE)
  • 116. 4. Use case using RxJava Model UI domain db/ cache OBSERVABLE Presentation layer VIEW PRESENTER OBSERVER 1 2 (USE CASE)
  • 117. 4. Use case using RxJava Model UI domain db/ cache OBSERVABLE Presentation layer VIEW PRESENTER OBSERVER 3 1 2 (USE CASE)
  • 118. 4. Use case using RxJava Model UI domain db/ cache OBSERVABLE Presentation layer VIEW PRESENTER OBSERVER 3 4 1 2 (USE CASE)
  • 119. 4. Use case using RxJava Model UI domain db/ cache OBSERVABLE Presentation layer VIEW PRESENTER OBSERVER 5 3 4 1 2 (USE CASE)
  • 120. 4. Use case using RxJava Model UI domain db/ cache OBSERVABLE Presentation layer 6 VIEW PRESENTER OBSERVER 5 3 4 1 2 (USE CASE)
  • 122. Testing? Views now don’t have business logic and/or data.
  • 123. Testing? Views now don’t have business logic and/or data. Presenters don’t have framework dependencies.
  • 124. Testing? Views now don’t have business logic and/or data. Presenters don’t have framework dependencies. Dependency injection make testing easier
  • 125. Testing? Views now don’t have business logic and/or data. Presenters don’t have framework dependencies. Use cases are very small and simple. Dependency injection make testing easier
  • 126. Testing? Views now don’t have business logic and/or data. Presenters don’t have framework dependencies. Use cases are very small and simple. We can test now every component independently. Dependency injection make testing easier
  • 127. Testing? Views now don’t have business logic and/or data. Presenters don’t have framework dependencies. Use cases are very small and simple. We can test now every component independently. Dependency injection make testing easier Now testing is easy peasy!
  • 129. More testing? VIEW Espresso Java + Android Mockito JUnit
  • 130. More testing? VIEW Espresso Java + Android Mockito JUnit PRESENTER TestSubscriber Mockito JUnit Java + RxJava
  • 131. More testing? VIEW Espresso Java + Android Mockito JUnit PRESENTER TestSubscriber Mockito JUnit Java + RxJava USE CASE TestSubscriber Mockito JUnit Java + RxJava
  • 132. More testing? VIEW Espresso Java + Android Mockito JUnit PRESENTER TestSubscriber Mockito JUnit Java + RxJava USE CASE TestSubscriber Mockito JUnit Java + RxJava UI- DOMAIN TestSubscriber Mockito JUnit Java + RxJava
  • 133. More testing? VIEW Espresso Java + Android Mockito JUnit PRESENTER TestSubscriber Mockito JUnit Java + RxJava USE CASE TestSubscriber Mockito JUnit Java + RxJava UI- DOMAIN TestSubscriber Mockito JUnit Java + RxJava DB/ CACHE Java + Android + RxJava Robolectric Mockito JUnit TestSubscriber
  • 136. Lessons learned Dependency Inversion Principle is key. Following SOLID principles makes MVP easy to build.
  • 137. Lessons learned Dependency Inversion Principle is key. Following SOLID principles makes MVP easy to build. Small use cases define what you want to do.
  • 138. Lessons learned Dependency Inversion Principle is key. Following SOLID principles makes MVP easy to build. Small use cases define what you want to do. We have different alternatives to fetch data, choose yours.
  • 139. Lessons learned Dependency Inversion Principle is key. Following SOLID principles makes MVP easy to build. Small use cases define what you want to do. We have different alternatives to fetch data, choose yours. Decouple components makes testing easier.
  • 142. License (cc) 2016 César Valiente. Some rights reserved. This document is distributed under the Creative Commons Attribution-ShareAlike 3.0 license, available in http://creativecommons.org/licenses/by-sa/3.0/
  • 143. Image licenses Wunderlist (Microsoft): permission granted. Emojis by Emoji One (CC-BY): http://emojione.com/ Iceberg: http://science-all.com/iceberg.html All images belong to their owners.