Keeping it Clean:
Clean code, for dirty developers
- Rich King -
Senior Android Developer
100+ million installs
190 countries
100K+ lines of code
185 Activities
23 Services
Architecture
Start of development
ActivitiesLoadersNetwork
Some time passes
Services
ActivitiesLoadersNetwork Global
Cache
And then…..
Services
ActivitiesEvent BusNetwork Global
Cache
GCM
Global
Listener
DB
Technical Debt
Time
Debt
So, what is Clean Architecture?
“ A GOOD ARCHITECTURE
EMPHASIZES THE USE-CASES
AND DECOUPLES THEM FROM
PERIPHERAL CONCERNS
— Robert C. Martin
Clean Architecture
• Coined by Robert C. Martin
• Combination of various ideas
- Hexagonal Architecture (a.k.a. Ports and Adapters)
- Onion Architecture
- Screaming Architecture
- Data, context and interaction paradigm
- Boundary, controller entity objects
- Single responsibility principle
https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html
Clean Architecture
Key points:
1. Use cases
2.Structure
3.Dependancies
4.Models
5.Testable
Use cases
• Use cases capture business rules
Send
Message
Bob Alice
What does it do?
• Structure should indicate what the application is, not how it
does it.
What does it do?
• Structure should indicate what the application is, not how it
does it.
com.myapp
activities
services
presenters
content providers
views
What does it do?
• Structure should indicate what the application is, not how it
does it.
chat
conversations
com.myapp
Dependencies
UI
Business Logic
Data
Infrastructure
Dependencies
Use Cases
PresentersU
I
H
TTP
D
B
C
ontrollers
Services
Dependencies
Inversion of Control
Class A Class B
Dependency
Inversion of Control
Class A Class B
Injected
Inversion of Control
Send
Message
Injected
Inversion of Control
Send
Message
Carrier
Pigeon
Injected
Inversion of Control
Send
Message
HTTP
Injected
Why different models?
Why different models?
Use Case Model
•message
•id
•from
Data Model
•message
•id
•from
•cacheTime
View Model
•message
•id
•from
•itemSpacing
Clean Architecture
Presenter
View
Gateway
Impl
Memory
Cache
Disk
Cache
Network
Gateway
<I>
Use Case
Entity
Entity
Entity
Clean Architecture
Gateway
Use Case
Entity
Entity
Entity
<I>
Clean Architecture
Presenter
View
Gateway
Impl
Memory
Cache
Disk
Cache
Network
Gateway
<I>
Use Case
Entity
Entity
Entity
Clean Architecture
Presenter
View
Model
Clean Architecture
Presenter
View
Gateway
Impl
Memory
Cache
Disk
Cache
Network
Gateway
<I>
Use Case
Entity
Entity
Entity
Clean Architecture
Gateway
Impl
Memory
Cache
Disk
Cache
Network
Clean Architecture
Presenter
View
Gateway
Impl
Memory
Cache
Disk
Cache
Network
Gateway
<I>
Use Case
Entity
Entity
Entity
Clean Architecture
List of
Messages
Open
Conversation
Presenter
View
Gateway
Impl
Memory
Cache
Disk
Cache
Network
Gateway
<I>
Use Case
Entity
Entity
Entity
Bob
Implementation Details
interface MessageGateway {
List<Message> get(String conversationId);
int send(String conversationId, String to, String from,
String message);
boolean delete(String messageId);
void subscribe(Callback callback);
}
Gateway
class GetMessages {
...
List<M> execute(conversationId) {
return mMessageGateway.get(conversationId);
}
}
Use cases
class SendMessage {
...
int execute(conversationId, ...) {
int result = mMessageGateway.send(...);
if(result == SUCCESS)
mConversationGateway.update(conversationId);
return result;
}
}
Use cases
class SendMessage {
...
int execute(conversationId, ...) {
int result = mMessageGateway.send(...);
if(result == SUCCESS)
mConversationGateway.update(conversationId);
return result;
}
}
Use cases
class SendMessage {
...
int execute(conversationId, ...) {
int result = mMessageGateway.send(...);
if(result == SUCCESS)
mConversationGateway.update(conversationId);
return result;
}
}
Use cases
class MessageScreenPresenter {
...
void onSendMessage(message) {
int result = mSendMessage.execute(...);
switch (result) {
case ERROR:
mView.displayError(...)
...
}
}
Presentation
MainThread
RxJava
• Simple to switch threads
• Transformations are convenient
• Comes with a cost
https://github.com/ReactiveX/RxJava
mExecutor.post(new Runnable() {
void run() {
// do something
mHandler.post(new Runnable() {
void run() {
// publish result
}
});
}
});
!RxJava
mExecutor.post(() -> {
// do something
mHandler.post(() -> {
// publish result
}
}
}
}
!RxJava with lambdas
doSomething()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> /* Handle Result */)
RxJava
Rx, Very Nice
interface MessageGateway {
Single<List<M>> get(...);
Single<Integer> send(...);
Single<Boolean> delete(...);
Observable<Update> subscribe(...);
}
Gateway
class GetMessages {
...
Single<List<M>> execute(conversationId) {
return mMessageRepo.get(conversationId);
}
}
Use cases
class SendMessage {
...
Single<Integer> execute(conversationId, ...) {
return mMessageGateway.send(…)
.doOnNext(r -> if(r == SUCCESS)
mConversationGateway.update(conversationId);)
}
}
Use cases
class MessageScreenPresenter {
...
void onStart() {
mSendMessage.execute(mConversationId)
.observeOn(AndroidSchedulers.mainThread())
.filter(result -> result == ERROR)
.subscribe(mView::displayError);
...
}
}
Presentation
class SomeGatewayImpl {
Single<Result> load(…) {
return loadFromMemory()
.flatMap(r -> r != null ?
Single.just(r) : loadFromDB());
}
}
Caching simplified
class SomeGatewayImpl {
Single<Result> load(…) {
return loadFromMemory()
.flatMap(r -> r != null ?
Single.just(r) : loadFromDB());
}
}
Caching simplified
class SomeGatewayImpl {
Single<Result> load(…) {
return loadFromMemory()
.flatMap(r -> r != null ?
Single.just(r) : loadFromDB());
}
}
Caching simplified
class SomeGatewayImpl {
Single<Result> load(…) {
return loadFromMemory()
.flatMap(r -> r != null ?
Single.just(r) : loadFromDB());
}
}
Caching simplified
class SomeGatewayImpl {
Single<Result> load(…) {
return loadFromMemory()
.flatMap(r -> r != null ?
Single.just(r) : loadFromDB());
}
}
Caching simplified
Was it worth it?
• Boilerplate
• Learning curve
• Testing
• Everything has a place
• Decisions can be postponed
• Implementations are replaceable
How can you do it?
• Start small
• Discuss and experiment
• Tech Talks
• Code reviews
Cheers!
github.com/badoo/Chateau
techblog.badoo.com
github.com/kingamajick
@kingamajick

Clean Architecture