SlideShare ist ein Scribd-Unternehmen logo
1 von 143
Downloaden Sie, um offline zu lesen
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.

Weitere ähnliche Inhalte

Was ist angesagt?

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
 

Was ist angesagt? (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
 

Ähnlich wie Refactoring Wunderlist. UA Mobile 2016.

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
 

Ähnlich wie Refactoring Wunderlist. UA Mobile 2016. (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
 

Mehr von 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
 

Mehr von 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.
 

Kürzlich hochgeladen

Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastPapp Krisztián
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...masabamasaba
 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...chiefasafspells
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareJim McKeeth
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...masabamasaba
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park masabamasaba
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfkalichargn70th171
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxAnnaArtyushina1
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationJuha-Pekka Tolvanen
 
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is insideshinachiaurasa2
 
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...masabamasaba
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...masabamasaba
 
tonesoftg
tonesoftgtonesoftg
tonesoftglanshi9
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfonteinmasabamasaba
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension AidPhilip Schwarz
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisamasabamasaba
 

Kürzlich hochgeladen (20)

Architecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the pastArchitecture decision records - How not to get lost in the past
Architecture decision records - How not to get lost in the past
 
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
%+27788225528 love spells in Boston Psychic Readings, Attraction spells,Bring...
 
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
Love witchcraft +27768521739 Binding love spell in Sandy Springs, GA |psychic...
 
Announcing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK SoftwareAnnouncing Codolex 2.0 from GDK Software
Announcing Codolex 2.0 from GDK Software
 
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
%+27788225528 love spells in Knoxville Psychic Readings, Attraction spells,Br...
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdfPayment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
Payment Gateway Testing Simplified_ A Step-by-Step Guide for Beginners.pdf
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptx
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the Situation
 
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
WSO2CON 2024 - WSO2's Digital Transformation Journey with Choreo: A Platforml...
 
The title is not connected to what is inside
The title is not connected to what is insideThe title is not connected to what is inside
The title is not connected to what is inside
 
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Toronto Psychic Readings, Attraction spells,Brin...
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
tonesoftg
tonesoftgtonesoftg
tonesoftg
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 

Refactoring Wunderlist. UA Mobile 2016.

  • 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.