SlideShare a Scribd company logo
Reactive Clean Architecture
Viktor Nyblom
@qw4z1
MVP MVC MVVM
What isn’t Architecture
X
X
X
Why clean architecture?
Architecture is about Intent
- Uncle Bob
Showing intent
Showing intent
Key points
! Use Cases
! Dependencies
! Models
! Reactive
! Testable
! Independent of frameworks
What is a Use Case?
! Captures application business rules
! Independent of framework
! Shows WHAT the application does, not HOWX
Interactor
Layered architecture
Interactors
Repositories
UI
DB
HTTP
Presenters
Dependencies
Layered architecture
Use Cases
Repositories
UI
DB
HTTP
Presenters
Data
Domain
Presentation
Three Layers
DataPresentation Domain
Model
PresenterView Interactor
Model
Operation
API
Repository
Cache
DBAbstraction
Presentation data flow
View Presenter
D
O
M
A
I
N
User
interaction
onRefresh() execute()
domainData
format()
showData(data)
Get

Feed

Interactor
fun getFeed():
Single<List<Tweets>>
What if we could observe a stream of data forever
and react to new versions of that data?
Presentation data flow
View Presenter
D
O
M
A
I
N
User
interaction
onRefresh() execute()
domainData
format()
updateData(data)
Refresh

Feed

Interactor
Observe

Feed

Interactor
Create

Tweet

Interactor
execute()onCreateTweet()
interface TweetFeedContract.Presenter

: BasePresenter<TweetFeedContract.View> {
fun onRefresh()
...
}
Presentation
interface TweetFeedContract.View

: BaseView {
fun updateFeed(list: List<DisplayableTweet>)
fun showEmpty()
fun showLoading()
....
}
Presentation
class TweetFeedPresenter @Inject constructor(

private val refreshFeedInteractor: RefreshFeedInteractor,

private val observeFeedInteractor: ObserveFeedInteractor,

private val mapToDisplayableItem: Mapper<DisplayableItem>

) : TweetFeedContract.Presenter {
private val disposables: CompositeDisposable

...
}
Presentation
override fun onRefresh() {

refreshFeedInteractor.excecute()

}
TweetFeedPresenter
override fun onAttach(view: TweetFeedContract.View) {

this.view = view

disposables += bindToFeed()

}
TweetFeedPresenter
override fun bindToFeed(): Disposable =

observeFeedInteractor

.excecute()

.onSubscribe { view?.showLoading() }

.map(mapToDisplayableItem)

.subscribe( 

{ tweets -> 

if (tweets.notEmpty())

view?.updateFeed(tweets)

else

view?.showEmpty()

},

{ throwable -> loge(throwable) } )

TweetFeedPresenter
Models should make sense in the context where
they are being used.
What the map?
public class Item {
private String validTo;

private float price;
private String validFrom;
private int type;
}
What the map?
public class Item {
@SerializedName ("validto")
private String validTo;
@SerializedName ("price")

private float price;
@SerializedName ("validfrom")
private String validFrom;
@SerializedName (value = "type")
private int type;
}
What the map?
@DatabaseTable (name = “item")

public class Item {
@DatabaseField (generatedId = true)
private int _id;
@DatabaseField
@SerializedName ("validto")
private String validTo;
@DatabaseField (canBeNull = false)
@SerializedName ("price")

private float price;
@DatabaseField (canBeNull = false)
@SerializedName ("validfrom")
private String validFrom;
@DatabaseField
@SerializedName (value = "type")
private int type;
}
What the map?
public class APIItem {
private int validto;

private float price;
private int validfrom;
private int type;
}
@DatabaseTable (name = “item")

public class DatabaseItem {
@DatabaseField (generatedId = true)
private int _id;

@DatabaseField
private int validTo;

@DatabaseField

private float price;
@DatabaseField

private int validFrom;
@DatabaseField

private int type;
@DatabaseField

private boolean dirty;
}
What the map?
@DatabaseTable (name = “item")

public class DatabaseItem {
@DatabaseField (generatedId = true)
private int _id;

@DatabaseField
private int validTo;

@DatabaseField

private float price;
@DatabaseField

private int validFrom;
@DatabaseField

private int type;
@DatabaseField

private boolean dirty;
}


public class DisplayableItem {
private int _id;
private DateTime validTo;
private String formattedTo;

private String formattedPrice;

private DateTime validFrom;

private String formattedFrom;

private ItemType type;

private boolean selected;
}
What the map
DataPresentation Domain
Model
PresenterView Interactor
Model
Operation
API
Repository
Cache
DBAbstraction
What the map
DataPresentation Domain
Presentation

Model
PresenterView Interactor
Domain

Model
Operation
API
Repository
Cache
DBAbstraction
API

Model
Cache

Model
Domain data flow
D
A
T
A
execute()
domainDatadomainData
Refresh

Feed

Interactor
Abstraction

: Tweet
Repository
P
R
E
S
E
N
TA
T

I

O
N
Observe

Feed

Interactor
onComplete()
retrieveFeed()
Abstraction

: TweetList

Repository
onNext()
Interactors
abstract class CompletableInteractor<in Params>(
private val executionScheduler: Scheduler,
private val postExecutionScheduler: Scheduler) {
abstract fun buildInteractorCompletable(params: Params): Completable
fun execute(params: Params): Completable =
buildInteractorObservable(params)
.subscribeOn(executionScheduler)
.observeOn(postExecutionScheduler)
.subscribe()
}
Interactors
class RefreshFeedInteractor @Inject constructor(
private val tweetRepository: TweetRepository,
executionScheduler: Scheduler,
postExecutionScheduler: Scheduler)
: CompletableInteractor<FeedSpec>(executionScheduler, postExecutionScheduler) {
override fun buildInteractorCompletable(params: FeedSpec): Completable
= tweetRepository.refreshFeed(params)
}
Interactors
abstract class ObservableInteractor<T, in Params>(
private val executionScheduler: Scheduler,
private val postExecutionScheduler: Scheduler) {
abstract fun buildInteractorCompletable(params: Params): Observable<T>
fun execute(params: Params): Observable<T> =
buildInteractorObservable(params)
.subscribeOn(executionScheduler)
.observeOn(postExecutionScheduler)
.subscribe()
}
Interactors
class RefreshFeedInteractor @Inject constructor(
private val tweetListRepository: TweetListRepository,
executionScheduler: Scheduler,
postExecutionScheduler: Scheduler)
: ObservableInteractor<List<Tweet>, FeedSpec>(executionScheduler, postExecutionScheduler) {
override fun buildInteractorCompletable(params: FeedSpec): Observable<List<Tweet>>
= tweetListRepository.observeFeed(params)
}
.filter { it.createdDate.after(someDate) }
.compose { customTransformer }
interface TweetListRepository {
fun refreshFeed(feedSpec: FeedSpec): Completable
fun observeFeed(feedSpec: FeedSpec): Observable<List<Tweet>>
}
class ReactiveTwitterRepository(
private val apiMapper: ApiToStoreMapper, 

private val api: SomeApi, 

private val store: ReactiveStore)
: TweetRepository {
override fun refreshFeed(): Completable =

api.retrieveTweetList()

.map { apiMapper }

.doOnSuccess { store.storeTweets(it) }

.toCompletable()
...
}
class ReactiveTwitterRepository(
private val apiMapper: ApiToStoreMapper, 

private val domainMapper: StoreToDomainMapper, 

private val api: SomeApi, 

private val store: ReactiveStore)
: TweetRepository {
...
override fun getFeedObservable(feedSpec: FeedSpec):

Observable<List<Tweet> =

store.getFeedObservable()

.map(domainMapper)
...
}
interface ReactiveStore<Key, Value> {
fun storeSingle(item: Value): Completable
fun storeAll(items: List<Value>): Completable
fun replaceAll(items: List<Value>): Completable
fun getSingle(key: Key): Observable<Value>
fun getAll(): Observable<List<Value>>
}
ReactiveStore
ReactiveStore
! Coordinates putting data in persistence and/or cache
! Create, store and feed the stream
! Implementation depends on the application
! Single source of truth
Domain data flow
D
A
T
A
action
P
R
E
S
E
N
TA
T

I

O
N
D
O
M
A
I
N
action
reactionreaction
Final advices
! Be pragmatic
○ Some compromises are ok
○ Perfect isn’t always best
! Beware of technical debt
○ Every debt will be collected some day
! Start out small
○ Get a feel for the structure
○ Decide on whether it’s the best approach for your app
! Don’t forget the tests!
Q&A
(hopefully)
viktor@devies.se
Viktor Nyblom
@qw4z1
Ad

More Related Content

Similar to Reactive clean architecture (20)

EclipseCon2011 Cross-Platform Mobile Development with Eclipse
EclipseCon2011 Cross-Platform Mobile Development with EclipseEclipseCon2011 Cross-Platform Mobile Development with Eclipse
EclipseCon2011 Cross-Platform Mobile Development with Eclipse
Heiko Behrens
 
How to become an Android dev starting from iOS (and vice versa)
How to become an Android dev starting from iOS (and vice versa)How to become an Android dev starting from iOS (and vice versa)
How to become an Android dev starting from iOS (and vice versa)
Giuseppe Filograno
 
9 Python programming notes for ktu physics and computer application semester 4
9 Python programming notes for ktu  physics and computer application semester 49 Python programming notes for ktu  physics and computer application semester 4
9 Python programming notes for ktu physics and computer application semester 4
ebindboby1
 
Creating a Facebook Clone - Part XXXI - Transcript.pdf
Creating a Facebook Clone - Part XXXI - Transcript.pdfCreating a Facebook Clone - Part XXXI - Transcript.pdf
Creating a Facebook Clone - Part XXXI - Transcript.pdf
ShaiAlmog1
 
Cloud native programming model comparison
Cloud native programming model comparisonCloud native programming model comparison
Cloud native programming model comparison
Emily Jiang
 
Net conf BG xamarin lecture
Net conf BG xamarin lectureNet conf BG xamarin lecture
Net conf BG xamarin lecture
Tsvyatko Konov
 
Using the Windows 8 Runtime from C++
Using the Windows 8 Runtime from C++Using the Windows 8 Runtime from C++
Using the Windows 8 Runtime from C++
Microsoft Developer Network (MSDN) - Belgium and Luxembourg
 
Scala on Your Phone
Scala on Your PhoneScala on Your Phone
Scala on Your Phone
Michael Galpin
 
Oleksandr Tolstykh
Oleksandr TolstykhOleksandr Tolstykh
Oleksandr Tolstykh
CodeFest
 
Intake 37 linq3
Intake 37 linq3Intake 37 linq3
Intake 37 linq3
Mahmoud Ouf
 
Building Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture ComponentsBuilding Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture Components
Hassan Abid
 
Android Architecture Components with Kotlin
Android Architecture Components with KotlinAndroid Architecture Components with Kotlin
Android Architecture Components with Kotlin
Adit Lal
 
Taming Core Data by Arek Holko, Macoscope
Taming Core Data by Arek Holko, MacoscopeTaming Core Data by Arek Holko, Macoscope
Taming Core Data by Arek Holko, Macoscope
Macoscope
 
VelocityGraph Introduction
VelocityGraph IntroductionVelocityGraph Introduction
VelocityGraph Introduction
Mats Persson
 
Why Spring <3 Kotlin
Why Spring <3 KotlinWhy Spring <3 Kotlin
Why Spring <3 Kotlin
VMware Tanzu
 
Blending Culture in Twitter Client
Blending Culture in Twitter ClientBlending Culture in Twitter Client
Blending Culture in Twitter Client
Kenji Tanaka
 
Getting the most out of Java [Nordic Coding-2010]
Getting the most out of Java [Nordic Coding-2010]Getting the most out of Java [Nordic Coding-2010]
Getting the most out of Java [Nordic Coding-2010]
Sven Efftinge
 
Extending Retrofit for fun and profit
Extending Retrofit for fun and profitExtending Retrofit for fun and profit
Extending Retrofit for fun and profit
Matthew Clarke
 
MBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&CoMBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&Co
e-Legion
 
Android Design Patterns
Android Design PatternsAndroid Design Patterns
Android Design Patterns
Godfrey Nolan
 
EclipseCon2011 Cross-Platform Mobile Development with Eclipse
EclipseCon2011 Cross-Platform Mobile Development with EclipseEclipseCon2011 Cross-Platform Mobile Development with Eclipse
EclipseCon2011 Cross-Platform Mobile Development with Eclipse
Heiko Behrens
 
How to become an Android dev starting from iOS (and vice versa)
How to become an Android dev starting from iOS (and vice versa)How to become an Android dev starting from iOS (and vice versa)
How to become an Android dev starting from iOS (and vice versa)
Giuseppe Filograno
 
9 Python programming notes for ktu physics and computer application semester 4
9 Python programming notes for ktu  physics and computer application semester 49 Python programming notes for ktu  physics and computer application semester 4
9 Python programming notes for ktu physics and computer application semester 4
ebindboby1
 
Creating a Facebook Clone - Part XXXI - Transcript.pdf
Creating a Facebook Clone - Part XXXI - Transcript.pdfCreating a Facebook Clone - Part XXXI - Transcript.pdf
Creating a Facebook Clone - Part XXXI - Transcript.pdf
ShaiAlmog1
 
Cloud native programming model comparison
Cloud native programming model comparisonCloud native programming model comparison
Cloud native programming model comparison
Emily Jiang
 
Net conf BG xamarin lecture
Net conf BG xamarin lectureNet conf BG xamarin lecture
Net conf BG xamarin lecture
Tsvyatko Konov
 
Oleksandr Tolstykh
Oleksandr TolstykhOleksandr Tolstykh
Oleksandr Tolstykh
CodeFest
 
Building Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture ComponentsBuilding Modern Apps using Android Architecture Components
Building Modern Apps using Android Architecture Components
Hassan Abid
 
Android Architecture Components with Kotlin
Android Architecture Components with KotlinAndroid Architecture Components with Kotlin
Android Architecture Components with Kotlin
Adit Lal
 
Taming Core Data by Arek Holko, Macoscope
Taming Core Data by Arek Holko, MacoscopeTaming Core Data by Arek Holko, Macoscope
Taming Core Data by Arek Holko, Macoscope
Macoscope
 
VelocityGraph Introduction
VelocityGraph IntroductionVelocityGraph Introduction
VelocityGraph Introduction
Mats Persson
 
Why Spring <3 Kotlin
Why Spring <3 KotlinWhy Spring <3 Kotlin
Why Spring <3 Kotlin
VMware Tanzu
 
Blending Culture in Twitter Client
Blending Culture in Twitter ClientBlending Culture in Twitter Client
Blending Culture in Twitter Client
Kenji Tanaka
 
Getting the most out of Java [Nordic Coding-2010]
Getting the most out of Java [Nordic Coding-2010]Getting the most out of Java [Nordic Coding-2010]
Getting the most out of Java [Nordic Coding-2010]
Sven Efftinge
 
Extending Retrofit for fun and profit
Extending Retrofit for fun and profitExtending Retrofit for fun and profit
Extending Retrofit for fun and profit
Matthew Clarke
 
MBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&CoMBLTDev15: Egor Tolstoy, Rambler&Co
MBLTDev15: Egor Tolstoy, Rambler&Co
e-Legion
 
Android Design Patterns
Android Design PatternsAndroid Design Patterns
Android Design Patterns
Godfrey Nolan
 

Recently uploaded (20)

How Valletta helped healthcare SaaS to transform QA and compliance to grow wi...
How Valletta helped healthcare SaaS to transform QA and compliance to grow wi...How Valletta helped healthcare SaaS to transform QA and compliance to grow wi...
How Valletta helped healthcare SaaS to transform QA and compliance to grow wi...
Egor Kaleynik
 
How to Optimize Your AWS Environment for Improved Cloud Performance
How to Optimize Your AWS Environment for Improved Cloud PerformanceHow to Optimize Your AWS Environment for Improved Cloud Performance
How to Optimize Your AWS Environment for Improved Cloud Performance
ThousandEyes
 
Adobe Marketo Engage Champion Deep Dive - SFDC CRM Synch V2 & Usage Dashboards
Adobe Marketo Engage Champion Deep Dive - SFDC CRM Synch V2 & Usage DashboardsAdobe Marketo Engage Champion Deep Dive - SFDC CRM Synch V2 & Usage Dashboards
Adobe Marketo Engage Champion Deep Dive - SFDC CRM Synch V2 & Usage Dashboards
BradBedford3
 
Download Wondershare Filmora Crack [2025] With Latest
Download Wondershare Filmora Crack [2025] With LatestDownload Wondershare Filmora Crack [2025] With Latest
Download Wondershare Filmora Crack [2025] With Latest
tahirabibi60507
 
FL Studio Producer Edition Crack 2025 Full Version
FL Studio Producer Edition Crack 2025 Full VersionFL Studio Producer Edition Crack 2025 Full Version
FL Studio Producer Edition Crack 2025 Full Version
tahirabibi60507
 
Get & Download Wondershare Filmora Crack Latest [2025]
Get & Download Wondershare Filmora Crack Latest [2025]Get & Download Wondershare Filmora Crack Latest [2025]
Get & Download Wondershare Filmora Crack Latest [2025]
saniaaftab72555
 
Adobe Lightroom Classic Crack FREE Latest link 2025
Adobe Lightroom Classic Crack FREE Latest link 2025Adobe Lightroom Classic Crack FREE Latest link 2025
Adobe Lightroom Classic Crack FREE Latest link 2025
kashifyounis067
 
Explaining GitHub Actions Failures with Large Language Models Challenges, In...
Explaining GitHub Actions Failures with Large Language Models Challenges, In...Explaining GitHub Actions Failures with Large Language Models Challenges, In...
Explaining GitHub Actions Failures with Large Language Models Challenges, In...
ssuserb14185
 
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
Andre Hora
 
Who Watches the Watchmen (SciFiDevCon 2025)
Who Watches the Watchmen (SciFiDevCon 2025)Who Watches the Watchmen (SciFiDevCon 2025)
Who Watches the Watchmen (SciFiDevCon 2025)
Allon Mureinik
 
Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...
Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...
Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...
Lionel Briand
 
Adobe Master Collection CC Crack Advance Version 2025
Adobe Master Collection CC Crack Advance Version 2025Adobe Master Collection CC Crack Advance Version 2025
Adobe Master Collection CC Crack Advance Version 2025
kashifyounis067
 
Revolutionizing Residential Wi-Fi PPT.pptx
Revolutionizing Residential Wi-Fi PPT.pptxRevolutionizing Residential Wi-Fi PPT.pptx
Revolutionizing Residential Wi-Fi PPT.pptx
nidhisingh691197
 
Microsoft AI Nonprofit Use Cases and Live Demo_2025.04.30.pdf
Microsoft AI Nonprofit Use Cases and Live Demo_2025.04.30.pdfMicrosoft AI Nonprofit Use Cases and Live Demo_2025.04.30.pdf
Microsoft AI Nonprofit Use Cases and Live Demo_2025.04.30.pdf
TechSoup
 
Avast Premium Security Crack FREE Latest Version 2025
Avast Premium Security Crack FREE Latest Version 2025Avast Premium Security Crack FREE Latest Version 2025
Avast Premium Security Crack FREE Latest Version 2025
mu394968
 
How to Batch Export Lotus Notes NSF Emails to Outlook PST Easily?
How to Batch Export Lotus Notes NSF Emails to Outlook PST Easily?How to Batch Export Lotus Notes NSF Emails to Outlook PST Easily?
How to Batch Export Lotus Notes NSF Emails to Outlook PST Easily?
steaveroggers
 
Meet the Agents: How AI Is Learning to Think, Plan, and Collaborate
Meet the Agents: How AI Is Learning to Think, Plan, and CollaborateMeet the Agents: How AI Is Learning to Think, Plan, and Collaborate
Meet the Agents: How AI Is Learning to Think, Plan, and Collaborate
Maxim Salnikov
 
Top 10 Client Portal Software Solutions for 2025.docx
Top 10 Client Portal Software Solutions for 2025.docxTop 10 Client Portal Software Solutions for 2025.docx
Top 10 Client Portal Software Solutions for 2025.docx
Portli
 
Download YouTube By Click 2025 Free Full Activated
Download YouTube By Click 2025 Free Full ActivatedDownload YouTube By Click 2025 Free Full Activated
Download YouTube By Click 2025 Free Full Activated
saniamalik72555
 
Not So Common Memory Leaks in Java Webinar
Not So Common Memory Leaks in Java WebinarNot So Common Memory Leaks in Java Webinar
Not So Common Memory Leaks in Java Webinar
Tier1 app
 
How Valletta helped healthcare SaaS to transform QA and compliance to grow wi...
How Valletta helped healthcare SaaS to transform QA and compliance to grow wi...How Valletta helped healthcare SaaS to transform QA and compliance to grow wi...
How Valletta helped healthcare SaaS to transform QA and compliance to grow wi...
Egor Kaleynik
 
How to Optimize Your AWS Environment for Improved Cloud Performance
How to Optimize Your AWS Environment for Improved Cloud PerformanceHow to Optimize Your AWS Environment for Improved Cloud Performance
How to Optimize Your AWS Environment for Improved Cloud Performance
ThousandEyes
 
Adobe Marketo Engage Champion Deep Dive - SFDC CRM Synch V2 & Usage Dashboards
Adobe Marketo Engage Champion Deep Dive - SFDC CRM Synch V2 & Usage DashboardsAdobe Marketo Engage Champion Deep Dive - SFDC CRM Synch V2 & Usage Dashboards
Adobe Marketo Engage Champion Deep Dive - SFDC CRM Synch V2 & Usage Dashboards
BradBedford3
 
Download Wondershare Filmora Crack [2025] With Latest
Download Wondershare Filmora Crack [2025] With LatestDownload Wondershare Filmora Crack [2025] With Latest
Download Wondershare Filmora Crack [2025] With Latest
tahirabibi60507
 
FL Studio Producer Edition Crack 2025 Full Version
FL Studio Producer Edition Crack 2025 Full VersionFL Studio Producer Edition Crack 2025 Full Version
FL Studio Producer Edition Crack 2025 Full Version
tahirabibi60507
 
Get & Download Wondershare Filmora Crack Latest [2025]
Get & Download Wondershare Filmora Crack Latest [2025]Get & Download Wondershare Filmora Crack Latest [2025]
Get & Download Wondershare Filmora Crack Latest [2025]
saniaaftab72555
 
Adobe Lightroom Classic Crack FREE Latest link 2025
Adobe Lightroom Classic Crack FREE Latest link 2025Adobe Lightroom Classic Crack FREE Latest link 2025
Adobe Lightroom Classic Crack FREE Latest link 2025
kashifyounis067
 
Explaining GitHub Actions Failures with Large Language Models Challenges, In...
Explaining GitHub Actions Failures with Large Language Models Challenges, In...Explaining GitHub Actions Failures with Large Language Models Challenges, In...
Explaining GitHub Actions Failures with Large Language Models Challenges, In...
ssuserb14185
 
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
TestMigrationsInPy: A Dataset of Test Migrations from Unittest to Pytest (MSR...
Andre Hora
 
Who Watches the Watchmen (SciFiDevCon 2025)
Who Watches the Watchmen (SciFiDevCon 2025)Who Watches the Watchmen (SciFiDevCon 2025)
Who Watches the Watchmen (SciFiDevCon 2025)
Allon Mureinik
 
Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...
Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...
Requirements in Engineering AI- Enabled Systems: Open Problems and Safe AI Sy...
Lionel Briand
 
Adobe Master Collection CC Crack Advance Version 2025
Adobe Master Collection CC Crack Advance Version 2025Adobe Master Collection CC Crack Advance Version 2025
Adobe Master Collection CC Crack Advance Version 2025
kashifyounis067
 
Revolutionizing Residential Wi-Fi PPT.pptx
Revolutionizing Residential Wi-Fi PPT.pptxRevolutionizing Residential Wi-Fi PPT.pptx
Revolutionizing Residential Wi-Fi PPT.pptx
nidhisingh691197
 
Microsoft AI Nonprofit Use Cases and Live Demo_2025.04.30.pdf
Microsoft AI Nonprofit Use Cases and Live Demo_2025.04.30.pdfMicrosoft AI Nonprofit Use Cases and Live Demo_2025.04.30.pdf
Microsoft AI Nonprofit Use Cases and Live Demo_2025.04.30.pdf
TechSoup
 
Avast Premium Security Crack FREE Latest Version 2025
Avast Premium Security Crack FREE Latest Version 2025Avast Premium Security Crack FREE Latest Version 2025
Avast Premium Security Crack FREE Latest Version 2025
mu394968
 
How to Batch Export Lotus Notes NSF Emails to Outlook PST Easily?
How to Batch Export Lotus Notes NSF Emails to Outlook PST Easily?How to Batch Export Lotus Notes NSF Emails to Outlook PST Easily?
How to Batch Export Lotus Notes NSF Emails to Outlook PST Easily?
steaveroggers
 
Meet the Agents: How AI Is Learning to Think, Plan, and Collaborate
Meet the Agents: How AI Is Learning to Think, Plan, and CollaborateMeet the Agents: How AI Is Learning to Think, Plan, and Collaborate
Meet the Agents: How AI Is Learning to Think, Plan, and Collaborate
Maxim Salnikov
 
Top 10 Client Portal Software Solutions for 2025.docx
Top 10 Client Portal Software Solutions for 2025.docxTop 10 Client Portal Software Solutions for 2025.docx
Top 10 Client Portal Software Solutions for 2025.docx
Portli
 
Download YouTube By Click 2025 Free Full Activated
Download YouTube By Click 2025 Free Full ActivatedDownload YouTube By Click 2025 Free Full Activated
Download YouTube By Click 2025 Free Full Activated
saniamalik72555
 
Not So Common Memory Leaks in Java Webinar
Not So Common Memory Leaks in Java WebinarNot So Common Memory Leaks in Java Webinar
Not So Common Memory Leaks in Java Webinar
Tier1 app
 
Ad

Reactive clean architecture

  • 2. MVP MVC MVVM What isn’t Architecture X X X
  • 4. Architecture is about Intent - Uncle Bob
  • 7. Key points ! Use Cases ! Dependencies ! Models ! Reactive ! Testable ! Independent of frameworks
  • 8. What is a Use Case? ! Captures application business rules ! Independent of framework ! Shows WHAT the application does, not HOWX Interactor
  • 11. Three Layers DataPresentation Domain Model PresenterView Interactor Model Operation API Repository Cache DBAbstraction
  • 12. Presentation data flow View Presenter D O M A I N User interaction onRefresh() execute() domainData format() showData(data) Get
 Feed
 Interactor fun getFeed(): Single<List<Tweets>>
  • 13. What if we could observe a stream of data forever and react to new versions of that data?
  • 14. Presentation data flow View Presenter D O M A I N User interaction onRefresh() execute() domainData format() updateData(data) Refresh
 Feed
 Interactor Observe
 Feed
 Interactor Create
 Tweet
 Interactor execute()onCreateTweet()
  • 16. interface TweetFeedContract.View
 : BaseView { fun updateFeed(list: List<DisplayableTweet>) fun showEmpty() fun showLoading() .... } Presentation
  • 17. class TweetFeedPresenter @Inject constructor(
 private val refreshFeedInteractor: RefreshFeedInteractor,
 private val observeFeedInteractor: ObserveFeedInteractor,
 private val mapToDisplayableItem: Mapper<DisplayableItem>
 ) : TweetFeedContract.Presenter { private val disposables: CompositeDisposable
 ... } Presentation
  • 18. override fun onRefresh() {
 refreshFeedInteractor.excecute()
 } TweetFeedPresenter
  • 19. override fun onAttach(view: TweetFeedContract.View) {
 this.view = view
 disposables += bindToFeed()
 } TweetFeedPresenter
  • 20. override fun bindToFeed(): Disposable =
 observeFeedInteractor
 .excecute()
 .onSubscribe { view?.showLoading() }
 .map(mapToDisplayableItem)
 .subscribe( 
 { tweets -> 
 if (tweets.notEmpty())
 view?.updateFeed(tweets)
 else
 view?.showEmpty()
 },
 { throwable -> loge(throwable) } )
 TweetFeedPresenter
  • 21. Models should make sense in the context where they are being used.
  • 22. What the map? public class Item { private String validTo;
 private float price; private String validFrom; private int type; }
  • 23. What the map? public class Item { @SerializedName ("validto") private String validTo; @SerializedName ("price")
 private float price; @SerializedName ("validfrom") private String validFrom; @SerializedName (value = "type") private int type; }
  • 24. What the map? @DatabaseTable (name = “item")
 public class Item { @DatabaseField (generatedId = true) private int _id; @DatabaseField @SerializedName ("validto") private String validTo; @DatabaseField (canBeNull = false) @SerializedName ("price")
 private float price; @DatabaseField (canBeNull = false) @SerializedName ("validfrom") private String validFrom; @DatabaseField @SerializedName (value = "type") private int type; }
  • 25. What the map? public class APIItem { private int validto;
 private float price; private int validfrom; private int type; } @DatabaseTable (name = “item")
 public class DatabaseItem { @DatabaseField (generatedId = true) private int _id;
 @DatabaseField private int validTo;
 @DatabaseField
 private float price; @DatabaseField
 private int validFrom; @DatabaseField
 private int type; @DatabaseField
 private boolean dirty; }
  • 26. What the map? @DatabaseTable (name = “item")
 public class DatabaseItem { @DatabaseField (generatedId = true) private int _id;
 @DatabaseField private int validTo;
 @DatabaseField
 private float price; @DatabaseField
 private int validFrom; @DatabaseField
 private int type; @DatabaseField
 private boolean dirty; } 
 public class DisplayableItem { private int _id; private DateTime validTo; private String formattedTo;
 private String formattedPrice;
 private DateTime validFrom;
 private String formattedFrom;
 private ItemType type;
 private boolean selected; }
  • 27. What the map DataPresentation Domain Model PresenterView Interactor Model Operation API Repository Cache DBAbstraction
  • 28. What the map DataPresentation Domain Presentation
 Model PresenterView Interactor Domain
 Model Operation API Repository Cache DBAbstraction API
 Model Cache
 Model
  • 29. Domain data flow D A T A execute() domainDatadomainData Refresh
 Feed
 Interactor Abstraction
 : Tweet Repository P R E S E N TA T
 I
 O N Observe
 Feed
 Interactor onComplete() retrieveFeed() Abstraction
 : TweetList
 Repository onNext()
  • 30. Interactors abstract class CompletableInteractor<in Params>( private val executionScheduler: Scheduler, private val postExecutionScheduler: Scheduler) { abstract fun buildInteractorCompletable(params: Params): Completable fun execute(params: Params): Completable = buildInteractorObservable(params) .subscribeOn(executionScheduler) .observeOn(postExecutionScheduler) .subscribe() }
  • 31. Interactors class RefreshFeedInteractor @Inject constructor( private val tweetRepository: TweetRepository, executionScheduler: Scheduler, postExecutionScheduler: Scheduler) : CompletableInteractor<FeedSpec>(executionScheduler, postExecutionScheduler) { override fun buildInteractorCompletable(params: FeedSpec): Completable = tweetRepository.refreshFeed(params) }
  • 32. Interactors abstract class ObservableInteractor<T, in Params>( private val executionScheduler: Scheduler, private val postExecutionScheduler: Scheduler) { abstract fun buildInteractorCompletable(params: Params): Observable<T> fun execute(params: Params): Observable<T> = buildInteractorObservable(params) .subscribeOn(executionScheduler) .observeOn(postExecutionScheduler) .subscribe() }
  • 33. Interactors class RefreshFeedInteractor @Inject constructor( private val tweetListRepository: TweetListRepository, executionScheduler: Scheduler, postExecutionScheduler: Scheduler) : ObservableInteractor<List<Tweet>, FeedSpec>(executionScheduler, postExecutionScheduler) { override fun buildInteractorCompletable(params: FeedSpec): Observable<List<Tweet>> = tweetListRepository.observeFeed(params) } .filter { it.createdDate.after(someDate) } .compose { customTransformer }
  • 34. interface TweetListRepository { fun refreshFeed(feedSpec: FeedSpec): Completable fun observeFeed(feedSpec: FeedSpec): Observable<List<Tweet>> }
  • 35. class ReactiveTwitterRepository( private val apiMapper: ApiToStoreMapper, 
 private val api: SomeApi, 
 private val store: ReactiveStore) : TweetRepository { override fun refreshFeed(): Completable =
 api.retrieveTweetList()
 .map { apiMapper }
 .doOnSuccess { store.storeTweets(it) }
 .toCompletable() ... }
  • 36. class ReactiveTwitterRepository( private val apiMapper: ApiToStoreMapper, 
 private val domainMapper: StoreToDomainMapper, 
 private val api: SomeApi, 
 private val store: ReactiveStore) : TweetRepository { ... override fun getFeedObservable(feedSpec: FeedSpec):
 Observable<List<Tweet> =
 store.getFeedObservable()
 .map(domainMapper) ... }
  • 37. interface ReactiveStore<Key, Value> { fun storeSingle(item: Value): Completable fun storeAll(items: List<Value>): Completable fun replaceAll(items: List<Value>): Completable fun getSingle(key: Key): Observable<Value> fun getAll(): Observable<List<Value>> } ReactiveStore
  • 38. ReactiveStore ! Coordinates putting data in persistence and/or cache ! Create, store and feed the stream ! Implementation depends on the application ! Single source of truth
  • 40. Final advices ! Be pragmatic ○ Some compromises are ok ○ Perfect isn’t always best ! Beware of technical debt ○ Every debt will be collected some day ! Start out small ○ Get a feel for the structure ○ Decide on whether it’s the best approach for your app ! Don’t forget the tests!