SlideShare a Scribd company logo
From Legacy to Hexagonal 
(An Unexpected Android Journey) 
Rubén Serrano @Akelael 
Lead Android Developer @RedboothHQ 
José Manuel Pereira @JMPergar 
Android Software Engineer @RedboothHQ
Agenda 
1. From Legacy Code 
2. Towards Hexagonal Architecture 
3. To infinity, and beyond!
1. From Le gacy Code
Meet the team
From Legacy to Hexagonal (An Unexpected Android Journey)
From Legacy to Hexagonal (An Unexpected Android Journey)
One dev from a contractor
One dev from a contractor 
+ one senior iOS dev
One dev from a contractor 
+ one senior iOS dev
One dev from a contractor 
+ one senior iOS dev 
+ one junior iOS dev
One dev from a contractor 
+ one senior iOS dev 
+ one junior iOS dev
A different Android dev 
One dev from a contractor 
+ one senior iOS dev 
+ one junior iOS dev
A different Android dev 
One dev from a contractor 
+ one senior iOS dev 
+ one junior iOS dev 
+ one confused Android team
Meet the code
From Legacy to Hexagonal (An Unexpected Android Journey)
Meet the problem
1. We have a huge technical debt
1. We have a huge technical debt
HUGE
From Legacy to Hexagonal (An Unexpected Android Journey)
1. We have huge technical debt 
2. We can’t stop developing new features
1. We have huge technical debt 
2. We can’t stop developing new features 
3. We can’t remove debt at this point and we 
shouldn’t add any more
2. Towards Hexagonal
Working with 
legacy code
Read this book
What have we 
learnt from pizza?
You just don’t 
eat the whole 
pizza at once
1. Slice the big methods into small 
meaningful methods
1. Slice the big methods into small 
meaningful methods 
2. Identify different responsibilities and move 
them to other classes
1. Slice the big methods into small 
meaningful methods 
2. Identify different responsibilities and move 
them to other classes 
3. Use less coupled framework components 
(or no components at all)
Model View Presenter
In theory
View 
Presenter 
Model
Notifies 
events 
View 
Presenter 
Model
Requests 
data 
View 
Presenter 
Model
Serves data 
View 
Presenter 
Model
Change data 
representation 
View 
Presenter 
Model
View 
Tells how to draw 
Presenter 
Model
Layout 
+ 
Activity/ 
Fragment 
Presenter 
Data 
+ 
Business logic
In code 
(Original code…) 
http://goo.gl/z5Xn2J
listAdapter = 
MainFragment 
new SimpleCursorAdapter(getActivity(), 
android.R.layout.simple_list_item_1, 
null, 
new String[]{FakeDatabase.COLUMN_NAME}, 
new int[]{android.R.id.text1}, 
0); 
listView.setAdapter(listAdapter);
getLoaderManager().initLoader(0, null, new LoaderManager.LoaderCallbacks<Cursor>() { 
@Override 
public Loader<Cursor> onCreateLoader(int id, Bundle args) { 
return new CursorLoader(getActivity(), MainContentProvider.URI, 
null, null, null, null); 
} 
@Override 
public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 
listAdapter.swapCursor(data); 
} 
@Override 
public void onLoaderReset(Loader<Cursor> loader) { 
listAdapter.swapCursor(null); 
} 
}); 
MainFragment
In Code 
(… to MVP) 
http://goo.gl/Retvli
MainView & MainModel 
public interface MainView { 
public void swaplListData(Cursor cursor); 
} 
public interface MainModel { 
public void setPresenter(MainPresenter presenter); 
public void startLoadingData(Context context); 
}
MainFragment 
public class MainFragment extends Fragment implements MainView { 
//... 
@Override 
public void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
presenter = PresenterFactory.getMainPresenter(this); 
} 
@Override 
public void onActivityCreated(Bundle savedInstanceState) { 
//... 
presenter.notifyOnCreate(getActivity()); 
} 
@Override 
public void swaplListData(Cursor cursor) { 
listAdapter.swapCursor(cursor); 
}
MainPresenter 
public class MainPresenter { 
private MainView mainView; 
private MainModel mainModel; 
//... 
public void notifyOnCreate(Context context) { 
mainModel.startLoadingData(context); 
} 
public void notifiyLoadedDataAvailable(Cursor cursor) { 
mainView.swaplListData(cursor); 
} 
}
PresenterFactory 
public class PresenterFactory { 
public static MainPresenter getMainPresenter(MainView view) { 
MainModel model = new MainCursorModel(); 
return MainPresenter.newInstance(view, model); 
} 
}
MainCursorModel 
public class MainCursorModel implements MainModel { 
//... 
@Override 
public void startLoadingData(Context context) { 
new LoadDataAsyncTask().execute(context); 
} 
private class LoadDataAsyncTask extends AsyncTask<Context, Void, Cursor > { 
//... 
@Override 
protected void onPostExecute(Cursor result) { 
super.onPostExecute(result); 
presenter.notifiyLoadedDataAvailable(result); 
} 
} 
}
Pros & Cons 
View decoupled from model 
Cleaner code and smaller fragment/activities 
View and model not really decoupled (cursor) 
All the components use the framework
Hexagonal Architecture
In theory
Layout 
+ 
Activity/ 
Fragment 
Presenter 
Data 
+ 
Business logic
Layout 
+ 
Activity/ 
Fragment 
Data domain 
Business 
logic
Layout 
+ 
Activity/ 
Fragment 
Database 
Business 
logic 
Network 
Sensors
Database 
Network 
Sensors 
Layout 
+ 
Activity/ 
Fragment 
Business 
logic
Business 
logic 
Sensors 
Network 
Database 
Layout 
+ 
Activity/ 
Fragment
Port 
Business 
logic Port Port 
Port 
Sensors 
Network 
Database 
Layout 
+ 
Activity/ 
Fragment
Adapter 
Port 
Business 
logic Port Port 
Sensors 
Network 
Database 
Layout 
+ 
Activity/ 
Fragment 
Adapter Adapter 
Port 
Adapter
Adapter 
Port 
Business 
logic Port Port 
Sensors 
Network 
Database 
Layout 
+ 
Activity/ 
Fragment 
Adapter Adapter 
Port 
Adapter
Boundary 
Port 
Business 
logic Port Port 
Sensors 
Network 
Database 
Layout 
+ 
Activity/ 
Fragment 
Boundary Boundary 
Port 
Boundary
App 
Core 
App App 
Module Core 
Module 
App 
Module 
App 
Module 
App 
Module 
App 
Core Core 
Core 
App
In code 
(Hexagonal) 
http://goo.gl/lIyH0o
MainFragment 
public class MainFragment extends Fragment { 
//... 
private MainFragmentBoundary viewBoundary; 
@Override 
public void onCreate(Bundle savedInstanceState) { 
//... 
viewBoundary = MainFragmentBoundary.newInstance(this); 
} 
@Override 
public void onActivityCreated(Bundle savedInstanceState) { 
//... 
viewBoundary.notifyOnCreate(); 
}
MainFragment 
public void setListAdapter() { 
listAdapter = new ArrayAdapter<String>(getActivity(), 
android.R.layout.simple_list_item_1, 
android.R.id.text1, 
new ArrayList<String>(0)); 
listView.setAdapter(listAdapter); 
} 
public void swapList(List<String> names) { 
listAdapter.clear(); 
listAdapter.addAll(names); 
}
MainFragmentBoundary 
public class MainFragmentBoundary implements MainViewPort { 
private MainFragment mainFragment; 
private MainLogic logic; 
//... 
public void notifyOnCreate() { 
logic.notifyOnCreate(); 
} 
@Override 
public void swaplListData(List<String> names) { 
mainFragment.swapList(names); 
}
MainModelBoundary 
public class MainModelBoundary implements MainModelPort { 
private MainLogic logic; 
private MainRepository repository; 
//... 
@Override 
public void startLoadingData() { 
repository.startLoadingData(new MainRepository.OnDataLoadedListener() { 
@Override 
public void onDataLodaded(Cursor cursor) { 
notifyDataLoaded(cursor); 
} 
}); 
} 
private void notifyDataLoaded(Cursor cursor) { 
List<String> names = mapCursorToList(cursor); 
logic.notifiyLoadedDataAvailable(names); 
}
MainModelBoundary 
private List<String> mapCursorToList(Cursor cursor) { 
List<String> names = new ArrayList<String>(); 
int nameColumnIndex = cursor.getColumnIndex(FakeDatabase.COLUMN_NAME); 
while (cursor.moveToNext()) { 
String name = cursor.getString(nameColumnIndex); 
names.add(name); 
} 
return names; 
}
Pros & Cons 
Logic is not going to be affected by framework changes 
Logic is pure Java: easier to test 
Less changes when replacing a plugin 
Easier for 2 devs to work on the same feature 
More complex architecture 
Need to map each POJO for each layer 
What happens when the plugins need to cooperate?
3. To infinity, and beyond!
One plugin, 
N commands
Boundary 
Port 
Business 
logic Port Port 
Sensors 
Network 
Database 
Layout 
+ 
Activity/ 
Fragment 
Boundary Boundary 
Port 
Boundary
Model 
Plugin 
Layout 
+ 
Activity/ 
Fragment 
Boundary Business Boundary 
logic Port Port
Create task 
Send chat message 
Update note 
Request projects 
Business 
logic 
Port Model 
Plugin 
Boundary
Asynchrony?
Create task 
Send chat message 
Update note 
Request projects 
Business 
logic 
Port Model 
Plugin 
Boundary
We don’t like: 
callback’s hell + AsyncTasks
We don’t like: 
callback’s hell + AsyncTasks 
We don’t mind (but could be a problem): 
only commands in separate threads
We don’t like: 
callback’s hell + AsyncTasks 
We don’t mind (but could be a problem): 
only commands in separate threads 
We would love: 
RxJava
Use cases
Model 
Plugin 
Layout 
+ 
Activity/ 
Fragment 
Boundary Business Boundary 
logic Port Port
Model 
Plugin 
Layout 
+ 
Activity/ 
Fragment 
Presenter 
Use 
Case 
Model 
Plugin 
Use 
Case Repository 
Model 
Plugin 
Use 
Case
Conclusions 
photo by Daniel Sancho
When? 
• If you expect 2+ devs working on the same 
feature 
• Unless you are sure the app is going to die 
in a near future 
• You know for sure you will change your 
plugins
How? 
1. Simple refactors 
2. Model View Presenter 
3. Hexagonal
How? 
1. Simple refactors 
2. Model View Presenter 
3. Hexagonal 
4. Clean Architecture
Thank you!
Questions?

More Related Content

What's hot (20)

PDF
Dove sono i tuoi vertici e di cosa stanno parlando?
Codemotion
 
PDF
Evolving a Clean, Pragmatic Architecture - A Craftsman's Guide
Victor Rentea
 
PDF
The framework as an implementation detail
Marcello Duarte
 
PPTX
API-first development
Vasco Veloso
 
PPT
Architecture | Busy Java Developers Guide to NoSQL | Ted Neward
JAX London
 
PDF
Flutter State Management Using GetX.pdf
Katy Slemon
 
PPTX
Spring @Transactional Explained
Victor Rentea
 
PDF
Clean Lambdas & Streams in Java8
Victor Rentea
 
PPTX
Zend Studio Tips and Tricks
Roy Ganor
 
PDF
AN EXERCISE IN CLEANER CODE - FROM LEGACY TO MAINTAINABLE
Gavin Pickin
 
PPT
Smoothing Your Java with DSLs
intelliyole
 
PPT
Android | Busy Java Developers Guide to Android: UI | Ted Neward
JAX London
 
PDF
[CB19] API-induced SSRF: How Apple Pay Scattered Vulnerabilities Across the W...
CODE BLUE
 
PDF
Porting VisualWorks code to Pharo
ESUG
 
PDF
Professional JavaScript: AntiPatterns
Mike Wilcox
 
DOCX
Article laravel 8
hadeedulhassan
 
PDF
DEF CON 27 - JOSHUA MADDUX - api induced ssrf
Felipe Prado
 
PDF
Tools and Virtualization to Manage our Operations at Puppet Labs - PuppetConf...
Puppet
 
PPTX
Prairie DevCon 2015 - Crafting Evolvable API Responses
darrelmiller71
 
PDF
[제3회 스포카콘] [안드로이드] 클린 아키텍처 적용하기
RyanHKang
 
Dove sono i tuoi vertici e di cosa stanno parlando?
Codemotion
 
Evolving a Clean, Pragmatic Architecture - A Craftsman's Guide
Victor Rentea
 
The framework as an implementation detail
Marcello Duarte
 
API-first development
Vasco Veloso
 
Architecture | Busy Java Developers Guide to NoSQL | Ted Neward
JAX London
 
Flutter State Management Using GetX.pdf
Katy Slemon
 
Spring @Transactional Explained
Victor Rentea
 
Clean Lambdas & Streams in Java8
Victor Rentea
 
Zend Studio Tips and Tricks
Roy Ganor
 
AN EXERCISE IN CLEANER CODE - FROM LEGACY TO MAINTAINABLE
Gavin Pickin
 
Smoothing Your Java with DSLs
intelliyole
 
Android | Busy Java Developers Guide to Android: UI | Ted Neward
JAX London
 
[CB19] API-induced SSRF: How Apple Pay Scattered Vulnerabilities Across the W...
CODE BLUE
 
Porting VisualWorks code to Pharo
ESUG
 
Professional JavaScript: AntiPatterns
Mike Wilcox
 
Article laravel 8
hadeedulhassan
 
DEF CON 27 - JOSHUA MADDUX - api induced ssrf
Felipe Prado
 
Tools and Virtualization to Manage our Operations at Puppet Labs - PuppetConf...
Puppet
 
Prairie DevCon 2015 - Crafting Evolvable API Responses
darrelmiller71
 
[제3회 스포카콘] [안드로이드] 클린 아키텍처 적용하기
RyanHKang
 

Viewers also liked (6)

PDF
Mikado method
pascaldevink
 
PDF
Mikadomethod tad2011
danielbrolund
 
PDF
Axiomas de peano
observatorio2015
 
PDF
Developing for Android (The movie)
Jose Manuel Pereira Garcia
 
PDF
Hexagonal architecture for java applications
Fabricio Epaminondas
 
PDF
Kata: Hexagonal Architecture / Ports and Adapters
holsky
 
Mikado method
pascaldevink
 
Mikadomethod tad2011
danielbrolund
 
Axiomas de peano
observatorio2015
 
Developing for Android (The movie)
Jose Manuel Pereira Garcia
 
Hexagonal architecture for java applications
Fabricio Epaminondas
 
Kata: Hexagonal Architecture / Ports and Adapters
holsky
 
Ad

Similar to From Legacy to Hexagonal (An Unexpected Android Journey) (20)

PPTX
Adding a modern twist to legacy web applications
Jeff Durta
 
PPTX
Adding a modern twist to legacy web applications
Jeff Durta
 
PDF
Overview of Android Infrastructure
Alexey Buzdin
 
PDF
Overview of Android Infrastructure
C.T.Co
 
PDF
TWINS: OOP and FP - Warburton
Codemotion
 
PDF
WebNet Conference 2012 - Designing complex applications using html5 and knock...
Fabio Franzini
 
PDF
How to code to code less
Anton Novikau
 
PPTX
10 ways to make your code rock
martincronje
 
PDF
Building Modern Apps using Android Architecture Components
Hassan Abid
 
PPTX
The Best Way to Become an Android Developer Expert with Android Jetpack
Ahmad Arif Faizin
 
PDF
Refactoring Wunderlist. UA Mobile 2016.
UA Mobile
 
PDF
Android Best Practices
Yekmer Simsek
 
ODP
Bring the fun back to java
ciklum_ods
 
PDF
Jaoo - Open Social A Standard For The Social Web
Patrick Chanezon
 
PPTX
Googleappengineintro 110410190620-phpapp01
Tony Frame
 
PPT
Working Effectively With Legacy Code
Naresh Jain
 
PDF
Five android architecture
Tomislav Homan
 
PPTX
2. Design patterns. part #2
Leonid Maslov
 
PDF
Developer Student Clubs NUK - Flutter for Beginners
Jiaxuan Lin
 
PPTX
Architecting Single Activity Applications (With or Without Fragments)
Gabor Varadi
 
Adding a modern twist to legacy web applications
Jeff Durta
 
Adding a modern twist to legacy web applications
Jeff Durta
 
Overview of Android Infrastructure
Alexey Buzdin
 
Overview of Android Infrastructure
C.T.Co
 
TWINS: OOP and FP - Warburton
Codemotion
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
Fabio Franzini
 
How to code to code less
Anton Novikau
 
10 ways to make your code rock
martincronje
 
Building Modern Apps using Android Architecture Components
Hassan Abid
 
The Best Way to Become an Android Developer Expert with Android Jetpack
Ahmad Arif Faizin
 
Refactoring Wunderlist. UA Mobile 2016.
UA Mobile
 
Android Best Practices
Yekmer Simsek
 
Bring the fun back to java
ciklum_ods
 
Jaoo - Open Social A Standard For The Social Web
Patrick Chanezon
 
Googleappengineintro 110410190620-phpapp01
Tony Frame
 
Working Effectively With Legacy Code
Naresh Jain
 
Five android architecture
Tomislav Homan
 
2. Design patterns. part #2
Leonid Maslov
 
Developer Student Clubs NUK - Flutter for Beginners
Jiaxuan Lin
 
Architecting Single Activity Applications (With or Without Fragments)
Gabor Varadi
 
Ad

Recently uploaded (20)

PDF
SAP Firmaya İade ABAB Kodları - ABAB ile yazılmıl hazır kod örneği
Salih Küçük
 
PDF
Generic or Specific? Making sensible software design decisions
Bert Jan Schrijver
 
PDF
4K Video Downloader Plus Pro Crack for MacOS New Download 2025
bashirkhan333g
 
PDF
Driver Easy Pro 6.1.1 Crack Licensce key 2025 FREE
utfefguu
 
PPTX
Agentic Automation Journey Series Day 2 – Prompt Engineering for UiPath Agents
klpathrudu
 
PPTX
Agentic Automation: Build & Deploy Your First UiPath Agent
klpathrudu
 
PDF
Technical-Careers-Roadmap-in-Software-Market.pdf
Hussein Ali
 
PPTX
Change Common Properties in IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
PPTX
Milwaukee Marketo User Group - Summer Road Trip: Mapping and Personalizing Yo...
bbedford2
 
PPTX
Foundations of Marketo Engage - Powering Campaigns with Marketo Personalization
bbedford2
 
PPTX
Tally_Basic_Operations_Presentation.pptx
AditiBansal54083
 
PDF
[Solution] Why Choose the VeryPDF DRM Protector Custom-Built Solution for You...
Lingwen1998
 
PDF
MiniTool Partition Wizard 12.8 Crack License Key LATEST
hashhshs786
 
PDF
How to Hire AI Developers_ Step-by-Step Guide in 2025.pdf
DianApps Technologies
 
PDF
The 5 Reasons for IT Maintenance - Arna Softech
Arna Softech
 
PPTX
Empowering Asian Contributions: The Rise of Regional User Groups in Open Sour...
Shane Coughlan
 
PDF
Build It, Buy It, or Already Got It? Make Smarter Martech Decisions
bbedford2
 
PDF
SciPy 2025 - Packaging a Scientific Python Project
Henry Schreiner
 
PPTX
Coefficient of Variance in IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
PPTX
Comprehensive Risk Assessment Module for Smarter Risk Management
EHA Soft Solutions
 
SAP Firmaya İade ABAB Kodları - ABAB ile yazılmıl hazır kod örneği
Salih Küçük
 
Generic or Specific? Making sensible software design decisions
Bert Jan Schrijver
 
4K Video Downloader Plus Pro Crack for MacOS New Download 2025
bashirkhan333g
 
Driver Easy Pro 6.1.1 Crack Licensce key 2025 FREE
utfefguu
 
Agentic Automation Journey Series Day 2 – Prompt Engineering for UiPath Agents
klpathrudu
 
Agentic Automation: Build & Deploy Your First UiPath Agent
klpathrudu
 
Technical-Careers-Roadmap-in-Software-Market.pdf
Hussein Ali
 
Change Common Properties in IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
Milwaukee Marketo User Group - Summer Road Trip: Mapping and Personalizing Yo...
bbedford2
 
Foundations of Marketo Engage - Powering Campaigns with Marketo Personalization
bbedford2
 
Tally_Basic_Operations_Presentation.pptx
AditiBansal54083
 
[Solution] Why Choose the VeryPDF DRM Protector Custom-Built Solution for You...
Lingwen1998
 
MiniTool Partition Wizard 12.8 Crack License Key LATEST
hashhshs786
 
How to Hire AI Developers_ Step-by-Step Guide in 2025.pdf
DianApps Technologies
 
The 5 Reasons for IT Maintenance - Arna Softech
Arna Softech
 
Empowering Asian Contributions: The Rise of Regional User Groups in Open Sour...
Shane Coughlan
 
Build It, Buy It, or Already Got It? Make Smarter Martech Decisions
bbedford2
 
SciPy 2025 - Packaging a Scientific Python Project
Henry Schreiner
 
Coefficient of Variance in IBM SPSS Statistics Version 31.pptx
Version 1 Analytics
 
Comprehensive Risk Assessment Module for Smarter Risk Management
EHA Soft Solutions
 

From Legacy to Hexagonal (An Unexpected Android Journey)

  • 1. From Legacy to Hexagonal (An Unexpected Android Journey) Rubén Serrano @Akelael Lead Android Developer @RedboothHQ José Manuel Pereira @JMPergar Android Software Engineer @RedboothHQ
  • 2. Agenda 1. From Legacy Code 2. Towards Hexagonal Architecture 3. To infinity, and beyond!
  • 3. 1. From Le gacy Code
  • 7. One dev from a contractor
  • 8. One dev from a contractor + one senior iOS dev
  • 9. One dev from a contractor + one senior iOS dev
  • 10. One dev from a contractor + one senior iOS dev + one junior iOS dev
  • 11. One dev from a contractor + one senior iOS dev + one junior iOS dev
  • 12. A different Android dev One dev from a contractor + one senior iOS dev + one junior iOS dev
  • 13. A different Android dev One dev from a contractor + one senior iOS dev + one junior iOS dev + one confused Android team
  • 17. 1. We have a huge technical debt
  • 18. 1. We have a huge technical debt
  • 19. HUGE
  • 21. 1. We have huge technical debt 2. We can’t stop developing new features
  • 22. 1. We have huge technical debt 2. We can’t stop developing new features 3. We can’t remove debt at this point and we shouldn’t add any more
  • 26. What have we learnt from pizza?
  • 27. You just don’t eat the whole pizza at once
  • 28. 1. Slice the big methods into small meaningful methods
  • 29. 1. Slice the big methods into small meaningful methods 2. Identify different responsibilities and move them to other classes
  • 30. 1. Slice the big methods into small meaningful methods 2. Identify different responsibilities and move them to other classes 3. Use less coupled framework components (or no components at all)
  • 34. Notifies events View Presenter Model
  • 35. Requests data View Presenter Model
  • 36. Serves data View Presenter Model
  • 37. Change data representation View Presenter Model
  • 38. View Tells how to draw Presenter Model
  • 39. Layout + Activity/ Fragment Presenter Data + Business logic
  • 40. In code (Original code…) http://goo.gl/z5Xn2J
  • 41. listAdapter = MainFragment new SimpleCursorAdapter(getActivity(), android.R.layout.simple_list_item_1, null, new String[]{FakeDatabase.COLUMN_NAME}, new int[]{android.R.id.text1}, 0); listView.setAdapter(listAdapter);
  • 42. getLoaderManager().initLoader(0, null, new LoaderManager.LoaderCallbacks<Cursor>() { @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { return new CursorLoader(getActivity(), MainContentProvider.URI, null, null, null, null); } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { listAdapter.swapCursor(data); } @Override public void onLoaderReset(Loader<Cursor> loader) { listAdapter.swapCursor(null); } }); MainFragment
  • 43. In Code (… to MVP) http://goo.gl/Retvli
  • 44. MainView & MainModel public interface MainView { public void swaplListData(Cursor cursor); } public interface MainModel { public void setPresenter(MainPresenter presenter); public void startLoadingData(Context context); }
  • 45. MainFragment public class MainFragment extends Fragment implements MainView { //... @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); presenter = PresenterFactory.getMainPresenter(this); } @Override public void onActivityCreated(Bundle savedInstanceState) { //... presenter.notifyOnCreate(getActivity()); } @Override public void swaplListData(Cursor cursor) { listAdapter.swapCursor(cursor); }
  • 46. MainPresenter public class MainPresenter { private MainView mainView; private MainModel mainModel; //... public void notifyOnCreate(Context context) { mainModel.startLoadingData(context); } public void notifiyLoadedDataAvailable(Cursor cursor) { mainView.swaplListData(cursor); } }
  • 47. PresenterFactory public class PresenterFactory { public static MainPresenter getMainPresenter(MainView view) { MainModel model = new MainCursorModel(); return MainPresenter.newInstance(view, model); } }
  • 48. MainCursorModel public class MainCursorModel implements MainModel { //... @Override public void startLoadingData(Context context) { new LoadDataAsyncTask().execute(context); } private class LoadDataAsyncTask extends AsyncTask<Context, Void, Cursor > { //... @Override protected void onPostExecute(Cursor result) { super.onPostExecute(result); presenter.notifiyLoadedDataAvailable(result); } } }
  • 49. Pros & Cons View decoupled from model Cleaner code and smaller fragment/activities View and model not really decoupled (cursor) All the components use the framework
  • 52. Layout + Activity/ Fragment Presenter Data + Business logic
  • 53. Layout + Activity/ Fragment Data domain Business logic
  • 54. Layout + Activity/ Fragment Database Business logic Network Sensors
  • 55. Database Network Sensors Layout + Activity/ Fragment Business logic
  • 56. Business logic Sensors Network Database Layout + Activity/ Fragment
  • 57. Port Business logic Port Port Port Sensors Network Database Layout + Activity/ Fragment
  • 58. Adapter Port Business logic Port Port Sensors Network Database Layout + Activity/ Fragment Adapter Adapter Port Adapter
  • 59. Adapter Port Business logic Port Port Sensors Network Database Layout + Activity/ Fragment Adapter Adapter Port Adapter
  • 60. Boundary Port Business logic Port Port Sensors Network Database Layout + Activity/ Fragment Boundary Boundary Port Boundary
  • 61. App Core App App Module Core Module App Module App Module App Module App Core Core Core App
  • 62. In code (Hexagonal) http://goo.gl/lIyH0o
  • 63. MainFragment public class MainFragment extends Fragment { //... private MainFragmentBoundary viewBoundary; @Override public void onCreate(Bundle savedInstanceState) { //... viewBoundary = MainFragmentBoundary.newInstance(this); } @Override public void onActivityCreated(Bundle savedInstanceState) { //... viewBoundary.notifyOnCreate(); }
  • 64. MainFragment public void setListAdapter() { listAdapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, android.R.id.text1, new ArrayList<String>(0)); listView.setAdapter(listAdapter); } public void swapList(List<String> names) { listAdapter.clear(); listAdapter.addAll(names); }
  • 65. MainFragmentBoundary public class MainFragmentBoundary implements MainViewPort { private MainFragment mainFragment; private MainLogic logic; //... public void notifyOnCreate() { logic.notifyOnCreate(); } @Override public void swaplListData(List<String> names) { mainFragment.swapList(names); }
  • 66. MainModelBoundary public class MainModelBoundary implements MainModelPort { private MainLogic logic; private MainRepository repository; //... @Override public void startLoadingData() { repository.startLoadingData(new MainRepository.OnDataLoadedListener() { @Override public void onDataLodaded(Cursor cursor) { notifyDataLoaded(cursor); } }); } private void notifyDataLoaded(Cursor cursor) { List<String> names = mapCursorToList(cursor); logic.notifiyLoadedDataAvailable(names); }
  • 67. MainModelBoundary private List<String> mapCursorToList(Cursor cursor) { List<String> names = new ArrayList<String>(); int nameColumnIndex = cursor.getColumnIndex(FakeDatabase.COLUMN_NAME); while (cursor.moveToNext()) { String name = cursor.getString(nameColumnIndex); names.add(name); } return names; }
  • 68. Pros & Cons Logic is not going to be affected by framework changes Logic is pure Java: easier to test Less changes when replacing a plugin Easier for 2 devs to work on the same feature More complex architecture Need to map each POJO for each layer What happens when the plugins need to cooperate?
  • 69. 3. To infinity, and beyond!
  • 70. One plugin, N commands
  • 71. Boundary Port Business logic Port Port Sensors Network Database Layout + Activity/ Fragment Boundary Boundary Port Boundary
  • 72. Model Plugin Layout + Activity/ Fragment Boundary Business Boundary logic Port Port
  • 73. Create task Send chat message Update note Request projects Business logic Port Model Plugin Boundary
  • 75. Create task Send chat message Update note Request projects Business logic Port Model Plugin Boundary
  • 76. We don’t like: callback’s hell + AsyncTasks
  • 77. We don’t like: callback’s hell + AsyncTasks We don’t mind (but could be a problem): only commands in separate threads
  • 78. We don’t like: callback’s hell + AsyncTasks We don’t mind (but could be a problem): only commands in separate threads We would love: RxJava
  • 80. Model Plugin Layout + Activity/ Fragment Boundary Business Boundary logic Port Port
  • 81. Model Plugin Layout + Activity/ Fragment Presenter Use Case Model Plugin Use Case Repository Model Plugin Use Case
  • 82. Conclusions photo by Daniel Sancho
  • 83. When? • If you expect 2+ devs working on the same feature • Unless you are sure the app is going to die in a near future • You know for sure you will change your plugins
  • 84. How? 1. Simple refactors 2. Model View Presenter 3. Hexagonal
  • 85. How? 1. Simple refactors 2. Model View Presenter 3. Hexagonal 4. Clean Architecture