SlideShare a Scribd company logo
1 of 218
Download to read offline
(Large-Scale App을 위한) 

안드로이드 아키텍처 총정리
Speaker. 강사룡
Slide Link: https://www.slideshare.net/saryongkang/droid-knights-2019-largescale-app-android-architecture
Who is this guy?
• 경력 19년차 SW 엔지니어

• 폐업 전문가: 미국에서 한 번, 한국에서 두 번 스타트업 창업 경험

• IBM iX Japan에서 Android/iOS 담당 Senior Specialist로 근무 중

• Droid Knights 2018 - 내가 안드로이드 엔지니어가 되었을 때 아무도 알려주
지 않은 것들
IBM iX Japan - We’re building business by design

• Design Thinking, Mobile Interaction, Digital
Strategy, …

• 좌우지간 새롭고 재밌고, 유저 지향적인 신 기술/사업을
구현해주는 컨설팅 조직

• 주요 고객: 일본 10대 그룹, 은행사, 양대 항공사
목차
• Part I. 서론

1. 주의사항

2. 선수 지식: 안드로이드 아키텍처 4분만에 벼락치기 - MVC, Clean Architecture, Testability, Reusability

• Part II. Non-MVC 아키텍처 총정리

1. Non-MVC 아키텍처의 기본 설계 전략

2. MVP

3. MVVM

4. Redux

• Part III. New Trend in 2019

1. Rx vs non-Rx

2. Multi-module

• Part IV. Best Practices
Part I. 서론
1. 시작하기 전 주의사항
• 지나친 기대 금지 - 45분 강의에 너무 많은 걸 기대하시면 매우 곤란..

• 암기 금지 - 원리를 이해하는 것이 더 중요

• 무턱대고 납득하기 금지 - 왜 저런 얘기를 하는가를 이해하고, 판단은 여러분 스
스로

• 사진 촬영 무쓸모: 슬라이드는 아래 링크에서 다운 받으실 수 있습니다

• https://www.slideshare.net/saryongkang/droid-knights-2019-
largescale-app-android-architecture
왜, 특별히 안드로이드 아키텍처 설계/구현에 있어서, 비판적 사고
가 중요한가?
왜, 특별히 안드로이드 아키텍처 설계/구현에 있어서, 비판적 사고
가 중요한가?
• General Practice는 많은데 Best Practice는 찾아보기 어렵다
왜, 특별히 안드로이드 아키텍처 설계/구현에 있어서, 비판적 사고
가 중요한가?
• General Practice는 많은데 Best Practice는 찾아보기 어렵다
• 심지어 G사가 만든 샘플조차 갑론을박의 여지가..
왜, 특별히 안드로이드 아키텍처 설계/구현에 있어서, 비판적 사고
가 중요한가?
• General Practice는 많은데 Best Practice는 찾아보기 어렵다
• 심지어 G사가 만든 샘플조차 갑론을박의 여지가..
• 아키텍처 패턴의 겉을 맛보게 해주는 글은 많지만 핵심 철학에 대해 얘기하
는 글은 매우 희박하다
왜, 특별히 안드로이드 아키텍처 설계/구현에 있어서, 비판적 사고
가 중요한가?
• General Practice는 많은데 Best Practice는 찾아보기 어렵다
• 심지어 G사가 만든 샘플조차 갑론을박의 여지가..
• 아키텍처 패턴의 겉을 맛보게 해주는 글은 많지만 핵심 철학에 대해 얘기하
는 글은 매우 희박하다
• 같은 이름을 가진 아키텍처 패턴도 각자 상황에 따라 매우 이질적으로 구현될
수 있다
2. 선수지식
• Architecture의 기본 중의 기본: MVC란 무엇인가?
2. 선수지식
• Architecture의 기본 중의 기본: MVC란 무엇인가?
• Model = State + 비즈니스 로직 + 데이터 저장소
2. 선수지식
• Architecture의 기본 중의 기본: MVC란 무엇인가?
• Model = State + 비즈니스 로직 + 데이터 저장소
• View = UI (보통 declarative하게 구현됨)
2. 선수지식
• Architecture의 기본 중의 기본: MVC란 무엇인가?
• Model = State + 비즈니스 로직 + 데이터 저장소
• View = UI (보통 declarative하게 구현됨)
• Controller = Flow 로직 + [비즈니스 로직] +
[State]
(30초만에 이해하는) Clean Architecture의 기본
출처: https://qiita.com/koutalou/items/07a4f9cf51a2d13e4cdc
(30초만에 이해하는) Clean Architecture의 기본
• MVC에서 Model을 분해 → Domain Layer + Data Layer
출처: https://qiita.com/koutalou/items/07a4f9cf51a2d13e4cdc
(30초만에 이해하는) Clean Architecture의 기본
• MVC에서 Model을 분해 → Domain Layer + Data Layer
• MVC에서 비즈니스 로직을 분해 → Presentational Logic (in Presenter) / Domain Logic (in UseCase)
출처: https://qiita.com/koutalou/items/07a4f9cf51a2d13e4cdc
더 자세한 건…
Clean Architecture 적용에 대한 철학과 원칙에 내한 내용
을 들으실 수 있습니다.
• 그런데, 아주 작은 부분처럼 보이는 Presentation Logic에 주로 주목하는 이유는?
• 그런데, 아주 작은 부분처럼 보이는 Presentation Logic에 주로 주목하는 이유는?
• 도메인 로직이 차지하는 부분이 (상대적으로) 적음 - 대부분의 앱의 경우, 가장 복
잡한 비즈니스 로직은 백엔드 서버에 존재함
• 그런데, 아주 작은 부분처럼 보이는 Presentation Logic에 주로 주목하는 이유는?
• 도메인 로직이 차지하는 부분이 (상대적으로) 적음 - 대부분의 앱의 경우, 가장 복
잡한 비즈니스 로직은 백엔드 서버에 존재함
• 복잡하고 (대부분) 비동기적인 상태의 관리, 그리고 라이프 사이클 연동이 훨씬 복
잡하고 중요한 문제
• 그런데, 아주 작은 부분처럼 보이는 Presentation Logic에 주로 주목하는 이유는?
• 도메인 로직이 차지하는 부분이 (상대적으로) 적음 - 대부분의 앱의 경우, 가장 복
잡한 비즈니스 로직은 백엔드 서버에 존재함
• 복잡하고 (대부분) 비동기적인 상태의 관리, 그리고 라이프 사이클 연동이 훨씬 복
잡하고 중요한 문제
• 바꿔 얘기하면 모바일 아키텍처에서 가장 큰 난제는 tight coupling between
ui and state changes 를 어떻게 해소할 것인가의 문제
아키텍처 관점에서 아래 두 개념은 왜 그리 중요한가?
• 테스트 가능성
• 재사용성



아키텍처 관점에서 아래 두 개념은 왜 그리 중요한가?
• 테스트 가능성
• 재사용성



• “난 유닛테스트 따윈 필요 없어!”라고 차마 말하기 전에..

• Testablility가 떨어지는 코드란 무엇인가 생각해 봅시다 → Tightly-coupled

• 테스트 가능성이 떨어지는 코드는 중요 라이브러리 변경, 기반 구조 변경에 대응하기가 어렵다
아키텍처 관점에서 아래 두 개념은 왜 그리 중요한가?
• 테스트 가능성
• 재사용성



• “난 유닛테스트 따윈 필요 없어!”라고 차마 말하기 전에..

• Testablility가 떨어지는 코드란 무엇인가 생각해 봅시다 → Tightly-coupled

• 테스트 가능성이 떨어지는 코드는 중요 라이브러리 변경, 기반 구조 변경에 대응하기가 어렵다
• “현실적으로 한 번 짠 코드를 클래스/Fragment 단위로 재사용 가능한 경우가 얼마나 돼?”라고 차마
말하기 전에..

• Re-usability란 게 애초에 무엇이었나 생각해봅시다 → 적절한 모듈화, 캡슐화

• 재사용성이 떨어지는 구조는 기능 변경 / 확장성이 떨어진다 ≒ 코드 가독성이 떨어진다
참 쉽죠?
조금전 여러분은 안드로이드 아키텍처 초급과정을 수료하셨습니다. 

🎉🎉🎉
Part II. Non-MVC 아키텍처 총정리
쉬어가는 코너.. 이럴 때 안드로이드 개발자인 게 부끄럽다
쉬어가는 코너.. 이럴 때 안드로이드 개발자인 게 부끄럽다
어느 날,

옆집 친구 아들 옆 동네 CTO를 만나고 온 이사님이

나를 부르셨다.
자네...
Activity는 몇 줄까지 짜봤나?
Dilbert © 2018, Andrews McMeel Syndication
네?!
고수라면 보통 몇 천줄 정도
는 짜봤다던데..
헐.. WTF?!
뭐야 그 정도도 못 해본 거였어?
Dilbert © 2018, Andrews McMeel Syndication
Fat Activity/Fragment - 만악의 근원
여기서 작년의 복습: 왜 Android MVC는 나쁜가?
Fat Activity/Fragment - 만악의 근원
여기서 작년의 복습: 왜 Android MVC는 나쁜가?
• Activity가 할 수 있는 일
• 라이프사이클 관리, 모든 UI 로직 - 레이아웃 생성, 렌더링, 애니메이션, Shared
Preferences, 파일 IO, 화면 전환, 권한 설정, Loader, 그 외에 수 백 가지
Fat Activity/Fragment - 만악의 근원
여기서 작년의 복습: 왜 Android MVC는 나쁜가?
• Activity가 할 수 있는 일
• 라이프사이클 관리, 모든 UI 로직 - 레이아웃 생성, 렌더링, 애니메이션, Shared
Preferences, 파일 IO, 화면 전환, 권한 설정, Loader, 그 외에 수 백 가지
• 기본 Android Architecture에서 Activity란?
• Controller + View + alpha + omega = god
• Fragment도 그냥 작은 신일뿐..
😱
Non-MVC의 설계 전략
Non-MVC의 설계 전략
• Non-MVC에서 Activity는 무엇인가? → Activity는 컨트롤러! (그것도 아주 제한적인..)
Non-MVC의 설계 전략
• Non-MVC에서 Activity는 무엇인가? → Activity는 컨트롤러! (그것도 아주 제한적인..)
• MVP의 (궁극적) 접근법
Non-MVC의 설계 전략
• Non-MVC에서 Activity는 무엇인가? → Activity는 컨트롤러! (그것도 아주 제한적인..)
• MVP의 (궁극적) 접근법
• Activity에서 View와 Controller의 역할을 최대한 빼앗아 View와 Presenter로 넘김. 

Activity는 순수 flow 관리 역할 위주
Non-MVC의 설계 전략
• Non-MVC에서 Activity는 무엇인가? → Activity는 컨트롤러! (그것도 아주 제한적인..)
• MVP의 (궁극적) 접근법
• Activity에서 View와 Controller의 역할을 최대한 빼앗아 View와 Presenter로 넘김. 

Activity는 순수 flow 관리 역할 위주
• MVVM/Redux 등의 접근법
Non-MVC의 설계 전략
• Non-MVC에서 Activity는 무엇인가? → Activity는 컨트롤러! (그것도 아주 제한적인..)
• MVP의 (궁극적) 접근법
• Activity에서 View와 Controller의 역할을 최대한 빼앗아 View와 Presenter로 넘김. 

Activity는 순수 flow 관리 역할 위주
• MVVM/Redux 등의 접근법
• 마찬가지로 Activity는 최대한 일부 context 의존 기능만 하도록.. 

View logic은 최대한 data binding으로 구현
Non-MVC의 설계 전략
• Non-MVC에서 Activity는 무엇인가? → Activity는 컨트롤러! (그것도 아주 제한적인..)
• MVP의 (궁극적) 접근법
• Activity에서 View와 Controller의 역할을 최대한 빼앗아 View와 Presenter로 넘김. 

Activity는 순수 flow 관리 역할 위주
• MVVM/Redux 등의 접근법
• 마찬가지로 Activity는 최대한 일부 context 의존 기능만 하도록.. 

View logic은 최대한 data binding으로 구현
• 여기서 의문: 왜 구글은 (배우기도 어렵고 Rx가 없으면 제대로 구현도 안 되는) ViewModel만을 AAC(Android
Architecture Component)에서 지원하는가?
Non-MVC의 설계 전략
• Non-MVC에서 Activity는 무엇인가? → Activity는 컨트롤러! (그것도 아주 제한적인..)
• MVP의 (궁극적) 접근법
• Activity에서 View와 Controller의 역할을 최대한 빼앗아 View와 Presenter로 넘김. 

Activity는 순수 flow 관리 역할 위주
• MVVM/Redux 등의 접근법
• 마찬가지로 Activity는 최대한 일부 context 의존 기능만 하도록.. 

View logic은 최대한 data binding으로 구현
• 여기서 의문: 왜 구글은 (배우기도 어렵고 Rx가 없으면 제대로 구현도 안 되는) ViewModel만을 AAC(Android
Architecture Component)에서 지원하는가?
• 기존 Activity/Fragment의 형태를 깨뜨리지 않으면서 재사용성/생산성 높은 아키텍처를 구현 가능하기 때문*
Non-MVC의 설계 전략
• Non-MVC에서 Activity는 무엇인가? → Activity는 컨트롤러! (그것도 아주 제한적인..)
• MVP의 (궁극적) 접근법
• Activity에서 View와 Controller의 역할을 최대한 빼앗아 View와 Presenter로 넘김. 

Activity는 순수 flow 관리 역할 위주
• MVVM/Redux 등의 접근법
• 마찬가지로 Activity는 최대한 일부 context 의존 기능만 하도록.. 

View logic은 최대한 data binding으로 구현
• 여기서 의문: 왜 구글은 (배우기도 어렵고 Rx가 없으면 제대로 구현도 안 되는) ViewModel만을 AAC(Android
Architecture Component)에서 지원하는가?
• 기존 Activity/Fragment의 형태를 깨뜨리지 않으면서 재사용성/생산성 높은 아키텍처를 구현 가능하기 때문*
※주의: 어디까지나 추측입니다.
Model-View-Presenter?
Model-View-Presenter?
• 1990년대 초 IBM에서 최초로 구현
Model-View-Presenter?
• 1990년대 초 IBM에서 최초로 구현
• 2006년 Martin Fowler의 소개로 널리 알려짐

참조: GUI Architectures

https://martinfowler.com/eaaDev/uiArchs.html
Model-View-Presenter?
• 1990년대 초 IBM에서 최초로 구현
• 2006년 Martin Fowler의 소개로 널리 알려짐

참조: GUI Architectures

https://martinfowler.com/eaaDev/uiArchs.html
• 사실 안드로이드 초기부터 구전으로 전해져 왔던 아키텍처
Model-View-Presenter?
• 1990년대 초 IBM에서 최초로 구현
• 2006년 Martin Fowler의 소개로 널리 알려짐

참조: GUI Architectures

https://martinfowler.com/eaaDev/uiArchs.html
• 사실 안드로이드 초기부터 구전으로 전해져 왔던 아키텍처
• 근데 이미 한물 간 구조 아닌가? 아직도 쓰나요?
Model-View-Presenter?
• 1990년대 초 IBM에서 최초로 구현
• 2006년 Martin Fowler의 소개로 널리 알려짐

참조: GUI Architectures

https://martinfowler.com/eaaDev/uiArchs.html
• 사실 안드로이드 초기부터 구전으로 전해져 왔던 아키텍처
• 근데 이미 한물 간 구조 아닌가? 아직도 쓰나요?
• 예, 아직도 많이 씁니다. 예를 들면, 같은 회사가요.
Model-View-Presenter?
• 1990년대 초 IBM에서 최초로 구현
• 2006년 Martin Fowler의 소개로 널리 알려짐

참조: GUI Architectures

https://martinfowler.com/eaaDev/uiArchs.html
• 사실 안드로이드 초기부터 구전으로 전해져 왔던 아키텍처
• 근데 이미 한물 간 구조 아닌가? 아직도 쓰나요?
• 예, 아직도 많이 씁니다. 예를 들면, 같은 회사가요.
Presenter
View
Model
사용자 입력을 통보
데이터 갱신 요청
데이터 변경 통보
뷰 변경 요청
Presenter
View
Model
사용자 입력을 통보
데이터 갱신 요청
데이터 변경 통보
뷰 변경 요청
• 모든 Presentational Business Logic을 Presenter에서 처리
Presenter
View
Model
사용자 입력을 통보
데이터 갱신 요청
데이터 변경 통보
뷰 변경 요청
• 모든 Presentational Business Logic을 Presenter에서 처리
• View는 Presenter의 요청에 따라 수동적으로 UI를 처리함
Google Architecture Blueprint로 분석해보는 MVP의 핵심
• https://github.com/googlesamples/android-architecture/tree/todo-
mvp/
Google Architecture Blueprint로 분석해보는 MVP의 핵심
• https://github.com/googlesamples/android-architecture/tree/todo-
mvp/
• Contractor Pattern
Google Architecture Blueprint로 분석해보는 MVP의 핵심
• https://github.com/googlesamples/android-architecture/tree/todo-
mvp/
• Contractor Pattern
• View, Presenter는 interface 형태로 서로를 참조
Google Architecture Blueprint로 분석해보는 MVP의 핵심
• https://github.com/googlesamples/android-architecture/tree/todo-
mvp/
• Contractor Pattern
• View, Presenter는 interface 형태로 서로를 참조
• V와 P의 구현이 섞이거나, P가 플랫폼 의존적인 API를 직접 접근할 여지를
원천 봉쇄
/**
* This specifies the contract between the view and the presenter.
*/
public interface TasksContract {
interface View extends BaseView<Presenter> {
// ...
void setLoadingIndicator(boolean active);
void showTasks(List<Task> tasks);
void showAddTask();
void showTaskDetailsUi(String taskId);
}
interface Presenter extends BasePresenter {
// ...
void loadTasks(boolean forceUpdate);
void addNewTask();
void openTaskDetails(@NonNull Task requestedTask);
void completeTask(@NonNull Task completedTask);
void activateTask(@NonNull Task activeTask);
void clearCompletedTasks();
void setFiltering(TasksFilterType requestType);
TasksFilterType getFiltering();
}
}
/**
* This specifies the contract between the view and the presenter.
*/
public interface TasksContract {
interface View extends BaseView<Presenter> {
// ...
void setLoadingIndicator(boolean active);
void showTasks(List<Task> tasks);
void showAddTask();
void showTaskDetailsUi(String taskId);
}
interface Presenter extends BasePresenter {
// ...
void loadTasks(boolean forceUpdate);
void addNewTask();
void openTaskDetails(@NonNull Task requestedTask);
void completeTask(@NonNull Task completedTask);
void activateTask(@NonNull Task activeTask);
void clearCompletedTasks();
void setFiltering(TasksFilterType requestType);
TasksFilterType getFiltering();
}
}
• TODO 앱의 각 작업(task)를 보여주고 추가
하는 화면을 위한 TasksContractor
interface 정의
/**
* This specifies the contract between the view and the presenter.
*/
public interface TasksContract {
interface View extends BaseView<Presenter> {
// ...
void setLoadingIndicator(boolean active);
void showTasks(List<Task> tasks);
void showAddTask();
void showTaskDetailsUi(String taskId);
}
interface Presenter extends BasePresenter {
// ...
void loadTasks(boolean forceUpdate);
void addNewTask();
void openTaskDetails(@NonNull Task requestedTask);
void completeTask(@NonNull Task completedTask);
void activateTask(@NonNull Task activeTask);
void clearCompletedTasks();
void setFiltering(TasksFilterType requestType);
TasksFilterType getFiltering();
}
}
• TODO 앱의 각 작업(task)를 보여주고 추가
하는 화면을 위한 TasksContractor
interface 정의
• View-Presenter 간의 직접 연결을 끊음
/**
* This specifies the contract between the view and the presenter.
*/
public interface TasksContract {
interface View extends BaseView<Presenter> {
// ...
void setLoadingIndicator(boolean active);
void showTasks(List<Task> tasks);
void showAddTask();
void showTaskDetailsUi(String taskId);
}
interface Presenter extends BasePresenter {
// ...
void loadTasks(boolean forceUpdate);
void addNewTask();
void openTaskDetails(@NonNull Task requestedTask);
void completeTask(@NonNull Task completedTask);
void activateTask(@NonNull Task activeTask);
void clearCompletedTasks();
void setFiltering(TasksFilterType requestType);
TasksFilterType getFiltering();
}
}
• TODO 앱의 각 작업(task)를 보여주고 추가
하는 화면을 위한 TasksContractor
interface 정의
• View-Presenter 간의 직접 연결을 끊음
• Good?!
• 다시 한 번 자세히 봅시다.
🤔/**
* This specifies the contract between the view and the presenter.
*/
public interface TasksContract {
interface View extends BaseView<Presenter> {
// ...
void setLoadingIndicator(boolean active);
void showTasks(List<Task> tasks);
void showAddTask();
void showTaskDetailsUi(String taskId);
}
interface Presenter extends BasePresenter {
// ...
void loadTasks(boolean forceUpdate);
void addNewTask();
void openTaskDetails(@NonNull Task requestedTask);
void completeTask(@NonNull Task completedTask);
void activateTask(@NonNull Task activeTask);
void clearCompletedTasks();
void setFiltering(TasksFilterType requestType);
TasksFilterType getFiltering();
}
}
• 다시 한 번 자세히 봅시다.
• 어라? Presenter의 메소드들을 보니 데
이터를 넘겨주는 것들이 있네?
🤔/**
* This specifies the contract between the view and the presenter.
*/
public interface TasksContract {
interface View extends BaseView<Presenter> {
// ...
void setLoadingIndicator(boolean active);
void showTasks(List<Task> tasks);
void showAddTask();
void showTaskDetailsUi(String taskId);
}
interface Presenter extends BasePresenter {
// ...
void loadTasks(boolean forceUpdate);
void addNewTask();
void openTaskDetails(@NonNull Task requestedTask);
void completeTask(@NonNull Task completedTask);
void activateTask(@NonNull Task activeTask);
void clearCompletedTasks();
void setFiltering(TasksFilterType requestType);
TasksFilterType getFiltering();
}
}
• 다시 한 번 자세히 봅시다.
• 어라? Presenter의 메소드들을 보니 데
이터를 넘겨주는 것들이 있네?
• 그럼 상태 정보를 View가 갖는다는 얘
기?!
🤔/**
* This specifies the contract between the view and the presenter.
*/
public interface TasksContract {
interface View extends BaseView<Presenter> {
// ...
void setLoadingIndicator(boolean active);
void showTasks(List<Task> tasks);
void showAddTask();
void showTaskDetailsUi(String taskId);
}
interface Presenter extends BasePresenter {
// ...
void loadTasks(boolean forceUpdate);
void addNewTask();
void openTaskDetails(@NonNull Task requestedTask);
void completeTask(@NonNull Task completedTask);
void activateTask(@NonNull Task activeTask);
void clearCompletedTasks();
void setFiltering(TasksFilterType requestType);
TasksFilterType getFiltering();
}
}
/**
* Display a grid of {@link Task}s. User can choose to view all, active or completed tasks.
*/
public class TasksFragment extends Fragment implements TasksContract.View {
private TasksContract.Presenter mPresenter;
//...
TaskItemListener mItemListener = new TaskItemListener() {
@Override
public void onTaskClick(Task clickedTask) {
mPresenter.openTaskDetails(clickedTask);
}
@Override
public void onCompleteTaskClick(Task completedTask) {
mPresenter.completeTask(completedTask);
}
@Override
public void onActivateTaskClick(Task activatedTask) {
mPresenter.activateTask(activatedTask);
}
};
//...
private static class TasksAdapter extends BaseAdapter {
private List<Task> mTasks;
private TaskItemListener mItemListener;
public TasksAdapter(List<Task> tasks, TaskItemListener itemListener) {
setList(tasks);
mItemListener = itemListener;
}
}
}
• Bingo! - 각 상태에 따른 태스크를 view가
판단해서 보내주고 있음
/**
* Display a grid of {@link Task}s. User can choose to view all, active or completed tasks.
*/
public class TasksFragment extends Fragment implements TasksContract.View {
private TasksContract.Presenter mPresenter;
//...
TaskItemListener mItemListener = new TaskItemListener() {
@Override
public void onTaskClick(Task clickedTask) {
mPresenter.openTaskDetails(clickedTask);
}
@Override
public void onCompleteTaskClick(Task completedTask) {
mPresenter.completeTask(completedTask);
}
@Override
public void onActivateTaskClick(Task activatedTask) {
mPresenter.activateTask(activatedTask);
}
};
//...
private static class TasksAdapter extends BaseAdapter {
private List<Task> mTasks;
private TaskItemListener mItemListener;
public TasksAdapter(List<Task> tasks, TaskItemListener itemListener) {
setList(tasks);
mItemListener = itemListener;
}
}
}
• Bingo! - 각 상태에 따른 태스크를 view가
판단해서 보내주고 있음
• 그 item listener를 호출하는 부분을 거
슬러 올라갔더니..
/**
* Display a grid of {@link Task}s. User can choose to view all, active or completed tasks.
*/
public class TasksFragment extends Fragment implements TasksContract.View {
private TasksContract.Presenter mPresenter;
//...
TaskItemListener mItemListener = new TaskItemListener() {
@Override
public void onTaskClick(Task clickedTask) {
mPresenter.openTaskDetails(clickedTask);
}
@Override
public void onCompleteTaskClick(Task completedTask) {
mPresenter.completeTask(completedTask);
}
@Override
public void onActivateTaskClick(Task activatedTask) {
mPresenter.activateTask(activatedTask);
}
};
//...
private static class TasksAdapter extends BaseAdapter {
private List<Task> mTasks;
private TaskItemListener mItemListener;
public TasksAdapter(List<Task> tasks, TaskItemListener itemListener) {
setList(tasks);
mItemListener = itemListener;
}
}
}
• Bingo! - 각 상태에 따른 태스크를 view가
판단해서 보내주고 있음
• 그 item listener를 호출하는 부분을 거
슬러 올라갔더니..
• Task 객체의 상태를 View가 갖고 있고,
어떤 presenter 함수가 호출되어야 할 지
를 View 결정한다?!
• 헐?! 이건 MVP가 아니잖아!

• View가 passive하지 않다!

• 애초에 Activity가 Controller, Fragment
가 View의 역할을 하도록 만든 것 자체가, 일
정 규모 이상의 앱에서는 문제가 될 수 있는
설계
😒
• 이런 오해 때문에 Martin Fowler는 Presenter라는 이름을 폐기하고
Supervising Controller라고 부를 것을 제안. (그리고 View는 Passive View
로 부름)
• Ref: Retirement note for Model View Presenter Pattern

https://martinfowler.com/eaaDev/ModelViewPresenter.html .
더 자세한 건…
왜 View는 Passive 해야하는가, 그리고 바람직한 View와
Presenter의 역할은 무엇인가?
속시원하게 알려드립니다… (아마도)
• 타 아키텍처에도 적용되는 얘기만 하자면,
P
V
M
Home MVP*
P
V
M
Banner MVP
P
V
M
Original List MVP
P
V
M
Preview List MVP
※주의: 어디까지나 추측입니다.
• 타 아키텍처에도 적용되는 얘기만 하자면,
• Android의 경우, nested 구조로 갈 수밖에
없음.
P
V
M
Home MVP*
P
V
M
Banner MVP
P
V
M
Original List MVP
P
V
M
Preview List MVP
※주의: 어디까지나 추측입니다.
• 타 아키텍처에도 적용되는 얘기만 하자면,
• Android의 경우, nested 구조로 갈 수밖에
없음.
• 그럼 구글은 왜 아키텍처 청사진을 이렇게 짰을
까?
P
V
M
Home MVP*
P
V
M
Banner MVP
P
V
M
Original List MVP
P
V
M
Preview List MVP
※주의: 어디까지나 추측입니다.
• 타 아키텍처에도 적용되는 얘기만 하자면,
• Android의 경우, nested 구조로 갈 수밖에
없음.
• 그럼 구글은 왜 아키텍처 청사진을 이렇게 짰을
까?
• 주의점: 특정 회사의 공식 샘플은 어떤 의도를
가지고 만들어 질 수도 있다는 점을 미리 염두
에 둘 필요가 있음
P
V
M
Home MVP*
P
V
M
Banner MVP
P
V
M
Original List MVP
P
V
M
Preview List MVP
※주의: 어디까지나 추측입니다.
MVVM
http://kyubid.com/blog/understanding-mvvm-on-android-tutorial-05-introduction-to-reactive-programming-with-rxjava/
MVVM
• MVVM에서 View는 누구인가?
http://kyubid.com/blog/understanding-mvvm-on-android-tutorial-05-introduction-to-reactive-programming-with-rxjava/
MVVM
• MVVM에서 View는 누구인가?
• XML! DataBinding!
http://kyubid.com/blog/understanding-mvvm-on-android-tutorial-05-introduction-to-reactive-programming-with-rxjava/
MVVM
• MVVM에서 View는 누구인가?
• XML! DataBinding!
• XML에 view logic을 포함 

→ Declarative한 UI 로직 구현이 가능

→ BindingAdapter 조합, RxJava/
RxBinding의 도움으로 View의 상당수
구현을 Activity/Fragment로부터 빼앗
아 올 수 있음
http://kyubid.com/blog/understanding-mvvm-on-android-tutorial-05-introduction-to-reactive-programming-with-rxjava/
• ViewModel

• 그 자체로 독립적인 시스템

• View에 접근할 수도 없고, 존재 자체도 모름
• ViewModel

• 그 자체로 독립적인 시스템

• View에 접근할 수도 없고, 존재 자체도 모름
• AAC의 ViewModel

• LifeCycle 지원 기능 이외에 특별한 기능 없음 (차기 버전에서도 SavedState가 추가되는 정
도)

• 직접 Life Cycle 처리를 구현하고 AAC-ViewModel을 사용하지 않아도 무방

• Pro tip: MVVM 구조 설명에서 AAC 그림부터 나오는 글이라면 믿고 거르시면 됩니다
Redux - 출발점
Redux - 출발점
• Part I.에서 얘기했듯, 모바일 앱에서 가장 큰 난제 중의 하나는 복잡한 상태
들을 어떻게 깔끔하고 유지보수성 높게 구현할 것인가의 문제
Redux - 출발점
• Part I.에서 얘기했듯, 모바일 앱에서 가장 큰 난제 중의 하나는 복잡한 상태
들을 어떻게 깔끔하고 유지보수성 높게 구현할 것인가의 문제
• 발상을 바꿔서 앱 전체의 이벤트를 State Machine으로 처리한다면 어떨까?
Redux - 출발점
• Part I.에서 얘기했듯, 모바일 앱에서 가장 큰 난제 중의 하나는 복잡한 상태
들을 어떻게 깔끔하고 유지보수성 높게 구현할 것인가의 문제
• 발상을 바꿔서 앱 전체의 이벤트를 State Machine으로 처리한다면 어떨까?
• Life Cycle 처리로 골머리 앓을 일이 급격히 줄어듦
Redux - 출발점
• Part I.에서 얘기했듯, 모바일 앱에서 가장 큰 난제 중의 하나는 복잡한 상태
들을 어떻게 깔끔하고 유지보수성 높게 구현할 것인가의 문제
• 발상을 바꿔서 앱 전체의 이벤트를 State Machine으로 처리한다면 어떨까?
• Life Cycle 처리로 골머리 앓을 일이 급격히 줄어듦
• 상태에 따라 다르게 동작하는 UI를 보다 직관적으로 관리 가능
Redux - 출발점
• Part I.에서 얘기했듯, 모바일 앱에서 가장 큰 난제 중의 하나는 복잡한 상태
들을 어떻게 깔끔하고 유지보수성 높게 구현할 것인가의 문제
• 발상을 바꿔서 앱 전체의 이벤트를 State Machine으로 처리한다면 어떨까?
• Life Cycle 처리로 골머리 앓을 일이 급격히 줄어듦
• 상태에 따라 다르게 동작하는 UI를 보다 직관적으로 관리 가능
• 특정화면에서 수정 된 내용 (예: “좋아요” 상태 변경)이 다른 곳에서 저절로
적용
• 그런데..
• 그런데..
• State Machine을 직접 구현하다 보면.. 각 로직의 추상화를 어떻게 할 지 많은 고민
을 하게 됨
• 그런데..
• State Machine을 직접 구현하다 보면.. 각 로직의 추상화를 어떻게 할 지 많은 고민
을 하게 됨
• 상태: 먼저 상태를 저장하는 부분은 보통 enum class 아니면, sealed class로 구현
• 그런데..
• State Machine을 직접 구현하다 보면.. 각 로직의 추상화를 어떻게 할 지 많은 고민
을 하게 됨
• 상태: 먼저 상태를 저장하는 부분은 보통 enum class 아니면, sealed class로 구현
• 상태 천이(transition/flow): 어떤 조건에서는 B로, 또 다른 조건에서는 C로 변경
• 그런데..
• State Machine을 직접 구현하다 보면.. 각 로직의 추상화를 어떻게 할 지 많은 고민
을 하게 됨
• 상태: 먼저 상태를 저장하는 부분은 보통 enum class 아니면, sealed class로 구현
• 상태 천이(transition/flow): 어떤 조건에서는 B로, 또 다른 조건에서는 C로 변경
• 로직 수행: 각 상태가 변경 되었을 때 수행해야할 실제 로직
• 그런데..
• State Machine을 직접 구현하다 보면.. 각 로직의 추상화를 어떻게 할 지 많은 고민
을 하게 됨
• 상태: 먼저 상태를 저장하는 부분은 보통 enum class 아니면, sealed class로 구현
• 상태 천이(transition/flow): 어떤 조건에서는 B로, 또 다른 조건에서는 C로 변경
• 로직 수행: 각 상태가 변경 되었을 때 수행해야할 실제 로직
• 위 세 요소의 복잡도에 따라 상황에 맞게 구현해야하지만 가장 범용적인 방법 중 하나
는 uni-directional한 pipeline 형태 -> 바로 Flux 구조!
MVI? Flux? Redux?
MVI? Flux? Redux?
• Flux: Facebook에서, 웹 프론트엔드의 상태 처리를 직관적이고 깔끔하게 하기 위
해 고안한 Architectural Pattern. 단방향의 pipelined loop를 통해 이벤트를 처리

• MVI: Flux에 View 처리 등 모바일 관련 내용을 추가해서 부르는 이름. 안드로이드
개발에선 Flux와 같은 용어라고 생각해도 무방

• Redux: Flux 패턴의 변형 구현체 중 가장 효율적이라고 알려진 구현체. (물론 Java
Script로..) - immutable state, single source of truth를 실현한 단순한 구현

• Dan Abramov라는 젊은 개발자가 고안. 100여 줄에 불과한 라이브러리로 모든
Flux 구현체를 평정 -> flux 원 고안자에게 인정 받은 후, 바로 Facebook에서 스
카웃
• Action: 상태를 변경하라는 명령만을 가짐
그림 출처: https://speakerdeck.com/yuyakaido/droidkaigi-2019
• Action: 상태를 변경하라는 명령만을 가짐
• 보통은 Action Creator를 통해 만들어짐
그림 출처: https://speakerdeck.com/yuyakaido/droidkaigi-2019
• Action: 상태를 변경하라는 명령만을 가짐
• 보통은 Action Creator를 통해 만들어짐
• State: 상태의 데이터만을 가짐. no logic
그림 출처: https://speakerdeck.com/yuyakaido/droidkaigi-2019
• Action: 상태를 변경하라는 명령만을 가짐
• 보통은 Action Creator를 통해 만들어짐
• State: 상태의 데이터만을 가짐. no logic
• immutable (flux는 mutable)
그림 출처: https://speakerdeck.com/yuyakaido/droidkaigi-2019
• Action: 상태를 변경하라는 명령만을 가짐
• 보통은 Action Creator를 통해 만들어짐
• State: 상태의 데이터만을 가짐. no logic
• immutable (flux는 mutable)
• Store
그림 출처: https://speakerdeck.com/yuyakaido/droidkaigi-2019
• Action: 상태를 변경하라는 명령만을 가짐
• 보통은 Action Creator를 통해 만들어짐
• State: 상태의 데이터만을 가짐. no logic
• immutable (flux는 mutable)
• Store
• 상태의 저장소
그림 출처: https://speakerdeck.com/yuyakaido/droidkaigi-2019
• Action: 상태를 변경하라는 명령만을 가짐
• 보통은 Action Creator를 통해 만들어짐
• State: 상태의 데이터만을 가짐. no logic
• immutable (flux는 mutable)
• Store
• 상태의 저장소
• 상태를 변경시키고, 통지 하는 역할
그림 출처: https://speakerdeck.com/yuyakaido/droidkaigi-2019
• Action: 상태를 변경하라는 명령만을 가짐
• 보통은 Action Creator를 통해 만들어짐
• State: 상태의 데이터만을 가짐. no logic
• immutable (flux는 mutable)
• Store
• 상태의 저장소
• 상태를 변경시키고, 통지 하는 역할
• RxJava 혹은 Coroutine으로 손쉽게 구현 가능
그림 출처: https://speakerdeck.com/yuyakaido/droidkaigi-2019
• Action: 상태를 변경하라는 명령만을 가짐
• 보통은 Action Creator를 통해 만들어짐
• State: 상태의 데이터만을 가짐. no logic
• immutable (flux는 mutable)
• Store
• 상태의 저장소
• 상태를 변경시키고, 통지 하는 역할
• RxJava 혹은 Coroutine으로 손쉽게 구현 가능
• Reducer
그림 출처: https://speakerdeck.com/yuyakaido/droidkaigi-2019
• Action: 상태를 변경하라는 명령만을 가짐
• 보통은 Action Creator를 통해 만들어짐
• State: 상태의 데이터만을 가짐. no logic
• immutable (flux는 mutable)
• Store
• 상태의 저장소
• 상태를 변경시키고, 통지 하는 역할
• RxJava 혹은 Coroutine으로 손쉽게 구현 가능
• Reducer
• 순수 함수(pure function) 형태로 상태 변경을 구
현: (State, Action) -> new State그림 출처: https://speakerdeck.com/yuyakaido/droidkaigi-2019
그럼 side effect 처리는 대체 누가? → Middleware!
그림 출처: https://speakerdeck.com/yuyakaido/droidkaigi-2019
Redux의 장단점
• 장점
Redux의 장단점
• 장점
• 상태 처리에서의 라이프 사이클의 영향을 어느 정도 배제할 수 있음
Redux의 장단점
• 장점
• 상태 처리에서의 라이프 사이클의 영향을 어느 정도 배제할 수 있음
• 화면에서 back 버튼 누른 후에 뒤늦게 발생한 API 에러.. 같은 애매하고 난해한 상황도 효과적으로 대처 가능
Redux의 장단점
• 장점
• 상태 처리에서의 라이프 사이클의 영향을 어느 정도 배제할 수 있음
• 화면에서 back 버튼 누른 후에 뒤늦게 발생한 API 에러.. 같은 애매하고 난해한 상황도 효과적으로 대처 가능
• 상태의 정의 부분, 저장 부분, 처리 부분이 완벽히 나눠져 있기 때문에 수정/확장이 극도로 편함
Redux의 장단점
• 장점
• 상태 처리에서의 라이프 사이클의 영향을 어느 정도 배제할 수 있음
• 화면에서 back 버튼 누른 후에 뒤늦게 발생한 API 에러.. 같은 애매하고 난해한 상황도 효과적으로 대처 가능
• 상태의 정의 부분, 저장 부분, 처리 부분이 완벽히 나눠져 있기 때문에 수정/확장이 극도로 편함
• Functional한 구조의 특성상 유닛 테스트를 작성하는 것이 극도로 편리함
Redux의 장단점
• 장점
• 상태 처리에서의 라이프 사이클의 영향을 어느 정도 배제할 수 있음
• 화면에서 back 버튼 누른 후에 뒤늦게 발생한 API 에러.. 같은 애매하고 난해한 상황도 효과적으로 대처 가능
• 상태의 정의 부분, 저장 부분, 처리 부분이 완벽히 나눠져 있기 때문에 수정/확장이 극도로 편함
• Functional한 구조의 특성상 유닛 테스트를 작성하는 것이 극도로 편리함
• Debugging의 신세계! 현재의 모든 전역적 상태를 확인할 수 있고, 상태 변수 값을 직접 수정해서 전체 상태를 바꿔볼
수도 있음
Redux의 장단점
• 장점
• 상태 처리에서의 라이프 사이클의 영향을 어느 정도 배제할 수 있음
• 화면에서 back 버튼 누른 후에 뒤늦게 발생한 API 에러.. 같은 애매하고 난해한 상황도 효과적으로 대처 가능
• 상태의 정의 부분, 저장 부분, 처리 부분이 완벽히 나눠져 있기 때문에 수정/확장이 극도로 편함
• Functional한 구조의 특성상 유닛 테스트를 작성하는 것이 극도로 편리함
• Debugging의 신세계! 현재의 모든 전역적 상태를 확인할 수 있고, 상태 변수 값을 직접 수정해서 전체 상태를 바꿔볼
수도 있음
• 단점
Redux의 장단점
• 장점
• 상태 처리에서의 라이프 사이클의 영향을 어느 정도 배제할 수 있음
• 화면에서 back 버튼 누른 후에 뒤늦게 발생한 API 에러.. 같은 애매하고 난해한 상황도 효과적으로 대처 가능
• 상태의 정의 부분, 저장 부분, 처리 부분이 완벽히 나눠져 있기 때문에 수정/확장이 극도로 편함
• Functional한 구조의 특성상 유닛 테스트를 작성하는 것이 극도로 편리함
• Debugging의 신세계! 현재의 모든 전역적 상태를 확인할 수 있고, 상태 변수 값을 직접 수정해서 전체 상태를 바꿔볼
수도 있음
• 단점
• 상당한 수준의 학습 비용이 소요
Redux의 장단점
• 장점
• 상태 처리에서의 라이프 사이클의 영향을 어느 정도 배제할 수 있음
• 화면에서 back 버튼 누른 후에 뒤늦게 발생한 API 에러.. 같은 애매하고 난해한 상황도 효과적으로 대처 가능
• 상태의 정의 부분, 저장 부분, 처리 부분이 완벽히 나눠져 있기 때문에 수정/확장이 극도로 편함
• Functional한 구조의 특성상 유닛 테스트를 작성하는 것이 극도로 편리함
• Debugging의 신세계! 현재의 모든 전역적 상태를 확인할 수 있고, 상태 변수 값을 직접 수정해서 전체 상태를 바꿔볼
수도 있음
• 단점
• 상당한 수준의 학습 비용이 소요
• 코드량 증가, 특히 boiler plate 코드의 반복적 생산은 피하기 어려움
Flux / Redux의 현재와 미래
• 현재
Flux / Redux의 현재와 미래
• 현재
• ReKotlin, RxRedux이 있으나 현재로선 직접 구현을 추천
Flux / Redux의 현재와 미래
• 현재
• ReKotlin, RxRedux이 있으나 현재로선 직접 구현을 추천
• State / Action의 접점을 View로 할 수도 있지만 ViewModel로도 가능
Flux / Redux의 현재와 미래
• 현재
• ReKotlin, RxRedux이 있으나 현재로선 직접 구현을 추천
• State / Action의 접점을 View로 할 수도 있지만 ViewModel로도 가능
• 그리고 Flux의 경우는 Store를 ViewModel로 구현!
Flux / Redux의 현재와 미래
• 현재
• ReKotlin, RxRedux이 있으나 현재로선 직접 구현을 추천
• State / Action의 접점을 View로 할 수도 있지만 ViewModel로도 가능
• 그리고 Flux의 경우는 Store를 ViewModel로 구현!
• RxJava로 Store, 그리고 side effect를 처리하는 middleware를 구현 vs Coroutine + LiveData 조합
Flux / Redux의 현재와 미래
• 현재
• ReKotlin, RxRedux이 있으나 현재로선 직접 구현을 추천
• State / Action의 접점을 View로 할 수도 있지만 ViewModel로도 가능
• 그리고 Flux의 경우는 Store를 ViewModel로 구현!
• RxJava로 Store, 그리고 side effect를 처리하는 middleware를 구현 vs Coroutine + LiveData 조합
• 미래?
Flux / Redux의 현재와 미래
• 현재
• ReKotlin, RxRedux이 있으나 현재로선 직접 구현을 추천
• State / Action의 접점을 View로 할 수도 있지만 ViewModel로도 가능
• 그리고 Flux의 경우는 Store를 ViewModel로 구현!
• RxJava로 Store, 그리고 side effect를 처리하는 middleware를 구현 vs Coroutine + LiveData 조합
• 미래?
• Rx를 굳이 쓰지 않아도 되는 use case가 대부분이고, coroutine 환경이 성숙/안정화 됨에 따라 급격히 coroutine으로
중심이 넘어갈 듯
Flux / Redux의 현재와 미래
• 현재
• ReKotlin, RxRedux이 있으나 현재로선 직접 구현을 추천
• State / Action의 접점을 View로 할 수도 있지만 ViewModel로도 가능
• 그리고 Flux의 경우는 Store를 ViewModel로 구현!
• RxJava로 Store, 그리고 side effect를 처리하는 middleware를 구현 vs Coroutine + LiveData 조합
• 미래?
• Rx를 굳이 쓰지 않아도 되는 use case가 대부분이고, coroutine 환경이 성숙/안정화 됨에 따라 급격히 coroutine으로
중심이 넘어갈 듯
• 현재 주류인 Redux-Thunk middleware를 Redux-Saga가 대체할 것으로 예상
Flux / Redux의 현재와 미래
• 현재
• ReKotlin, RxRedux이 있으나 현재로선 직접 구현을 추천
• State / Action의 접점을 View로 할 수도 있지만 ViewModel로도 가능
• 그리고 Flux의 경우는 Store를 ViewModel로 구현!
• RxJava로 Store, 그리고 side effect를 처리하는 middleware를 구현 vs Coroutine + LiveData 조합
• 미래?
• Rx를 굳이 쓰지 않아도 되는 use case가 대부분이고, coroutine 환경이 성숙/안정화 됨에 따라 급격히 coroutine으로
중심이 넘어갈 듯
• 현재 주류인 Redux-Thunk middleware를 Redux-Saga가 대체할 것으로 예상
• Coroutine과 완벽하게 매치 되는 async loop 구조
Flux / Redux의 현재와 미래
• 현재
• ReKotlin, RxRedux이 있으나 현재로선 직접 구현을 추천
• State / Action의 접점을 View로 할 수도 있지만 ViewModel로도 가능
• 그리고 Flux의 경우는 Store를 ViewModel로 구현!
• RxJava로 Store, 그리고 side effect를 처리하는 middleware를 구현 vs Coroutine + LiveData 조합
• 미래?
• Rx를 굳이 쓰지 않아도 되는 use case가 대부분이고, coroutine 환경이 성숙/안정화 됨에 따라 급격히 coroutine으로
중심이 넘어갈 듯
• 현재 주류인 Redux-Thunk middleware를 Redux-Saga가 대체할 것으로 예상
• Coroutine과 완벽하게 매치 되는 async loop 구조
• 극도로 아름답고 깔끔한 테스트 코드 작성 가능
Part III. 

New Trends in 2019
1. Multi-module!
1. Multi-module!
• 여기서 잠시 질문
1. Multi-module!
• 여기서 잠시 질문
• internal class (inner class 아님)가 무엇인지 아시나요?
1. Multi-module!
• 여기서 잠시 질문
• internal class (inner class 아님)가 무엇인지 아시나요?
• private / protected / internal / public 중 internal과 public의 차이는?
1. Multi-module!
• 여기서 잠시 질문
• internal class (inner class 아님)가 무엇인지 아시나요?
• private / protected / internal / public 중 internal과 public의 차이는?
• internal 식별자 -> 다른 module (package가 아님) 에서 보이지 않게 함
1. Multi-module!
• 여기서 잠시 질문
• internal class (inner class 아님)가 무엇인지 아시나요?
• private / protected / internal / public 중 internal과 public의 차이는?
• internal 식별자 -> 다른 module (package가 아님) 에서 보이지 않게 함
• android gradle plugin 3.0.0부터 compile -> implementation으로 바뀐 이유
가 무엇인지 아시나요?
1. Multi-module!
• 여기서 잠시 질문
• internal class (inner class 아님)가 무엇인지 아시나요?
• private / protected / internal / public 중 internal과 public의 차이는?
• internal 식별자 -> 다른 module (package가 아님) 에서 보이지 않게 함
• android gradle plugin 3.0.0부터 compile -> implementation으로 바뀐 이유
가 무엇인지 아시나요?
• 멀티 모듈 지원 기능이 강화 되면서 추가된 개념
1. Multi-module!
• 여기서 잠시 질문
• internal class (inner class 아님)가 무엇인지 아시나요?
• private / protected / internal / public 중 internal과 public의 차이는?
• internal 식별자 -> 다른 module (package가 아님) 에서 보이지 않게 함
• android gradle plugin 3.0.0부터 compile -> implementation으로 바뀐 이유
가 무엇인지 아시나요?
• 멀티 모듈 지원 기능이 강화 되면서 추가된 개념
• 정확히는, compile == api 로 바뀜
참조 가능
• Compile (== api) 식별자
그림 출처: https://speakerdeck.com/sansanbuildersbox/multi-module-android-application
참조 가능
• Compile (== api) 식별자
• 특별히 지정하지 않아도
손자 모듈까지 참조 가능
그림 출처: https://speakerdeck.com/sansanbuildersbox/multi-module-android-application
참조 가능
• Compile (== api) 식별자
• 특별히 지정하지 않아도
손자 모듈까지 참조 가능
• 바꿔 얘기하면,
module2가 변경이 되
면 app 모듈도 재컴파
일 해야함
그림 출처: https://speakerdeck.com/sansanbuildersbox/multi-module-android-application
참조 불가
• implementation 식별자
그림 출처: https://speakerdeck.com/sansanbuildersbox/multi-module-android-application
참조 불가
• implementation 식별자
• 명시적으로 지정하지 않
은 손자 모듈 참조 불가
그림 출처: https://speakerdeck.com/sansanbuildersbox/multi-module-android-application
참조 불가
• implementation 식별자
• 명시적으로 지정하지 않
은 손자 모듈 참조 불가
• 바꿔 얘기하면,
module2가 변경이 되
어도 app 모듈은 컴파
일할 필요가 없음
그림 출처: https://speakerdeck.com/sansanbuildersbox/multi-module-android-application
멀티모듈의 기초는 여기서..
• 멀티 모듈은 왜 쓰는가?
• 멀티 모듈은 왜 쓰는가?
• 현실적인 이유: 빌드 속도
• 멀티 모듈은 왜 쓰는가?
• 현실적인 이유: 빌드 속도
• 풀 빌드: 36.4s → 30s, incremental build: 14.2s → 7s
• 멀티 모듈은 왜 쓰는가?
• 현실적인 이유: 빌드 속도
• 풀 빌드: 36.4s → 30s, incremental build: 14.2s → 7s
• Ref: https://speakerdeck.com/sansanbuildersbox/multi-module-android-
application
• 멀티 모듈은 왜 쓰는가?
• 현실적인 이유: 빌드 속도
• 풀 빌드: 36.4s → 30s, incremental build: 14.2s → 7s
• Ref: https://speakerdeck.com/sansanbuildersbox/multi-module-android-
application
• incremental이야 그렇다쳐도 왜 풀빌드도 빠르지? 주된 이유는 annotation
processing. kapt의 경우는 아직도 incremental processing을 지원하지 않음.
• 멀티 모듈은 왜 쓰는가?
• 현실적인 이유: 빌드 속도
• 풀 빌드: 36.4s → 30s, incremental build: 14.2s → 7s
• Ref: https://speakerdeck.com/sansanbuildersbox/multi-module-android-
application
• incremental이야 그렇다쳐도 왜 풀빌드도 빠르지? 주된 이유는 annotation
processing. kapt의 경우는 아직도 incremental processing을 지원하지 않음.
• 그외 realm과 같이 byte code weaving을 하는 라이브러리를 별도 모듈로 빼는 것
만으로 30% 빌드 성능 향상
• 멀티 모듈은 왜 쓰는가?
• 현실적인 이유: 빌드 속도
• 풀 빌드: 36.4s → 30s, incremental build: 14.2s → 7s
• Ref: https://speakerdeck.com/sansanbuildersbox/multi-module-android-
application
• incremental이야 그렇다쳐도 왜 풀빌드도 빠르지? 주된 이유는 annotation
processing. kapt의 경우는 아직도 incremental processing을 지원하지 않음.
• 그외 realm과 같이 byte code weaving을 하는 라이브러리를 별도 모듈로 빼는 것
만으로 30% 빌드 성능 향상
• 효율적인 분업 프로세스 가능: 모듈 별로 구현의 격리 / 테스트가 가능
• 멀티 모듈은 왜 쓰는가?
• 현실적인 이유: 빌드 속도
• 풀 빌드: 36.4s → 30s, incremental build: 14.2s → 7s
• Ref: https://speakerdeck.com/sansanbuildersbox/multi-module-android-
application
• incremental이야 그렇다쳐도 왜 풀빌드도 빠르지? 주된 이유는 annotation
processing. kapt의 경우는 아직도 incremental processing을 지원하지 않음.
• 그외 realm과 같이 byte code weaving을 하는 라이브러리를 별도 모듈로 빼는 것
만으로 30% 빌드 성능 향상
• 효율적인 분업 프로세스 가능: 모듈 별로 구현의 격리 / 테스트가 가능
• 독립적인 설계를 촉진
• 모듈은 어떻게 나누는가? - (1) Layer 별 수직 분리
• 모듈은 어떻게 나누는가? - (1) Layer 별 수직 분리
• Presentation / Domain / Data Layer
• 모듈은 어떻게 나누는가? - (1) Layer 별 수직 분리
• Presentation / Domain / Data Layer
• 단, Application에서 DB를 생성해야 하기 때문에, Presentation -> Domain ->
Data 형태의 배치는 불가능
• 모듈은 어떻게 나누는가? - (1) Layer 별 수직 분리
• Presentation / Domain / Data Layer
• 단, Application에서 DB를 생성해야 하기 때문에, Presentation -> Domain ->
Data 형태의 배치는 불가능
• app은 DI를 정의, ui / data 모듈에 domain 모듈이 주입될 수 있도록 함
• 모듈은 어떻게 나누는가? - (1) Layer 별 수직 분리
• Presentation / Domain / Data Layer
• 단, Application에서 DB를 생성해야 하기 때문에, Presentation -> Domain ->
Data 형태의 배치는 불가능
• app은 DI를 정의, ui / data 모듈에 domain 모듈이 주입될 수 있도록 함
그림 출처: https://speakerdeck.com/sansanbuildersbox/multi-module-android-application
• 모듈은 어떻게 나누는가? - (2) 수평 분리
• 모듈은 어떻게 나누는가? - (2) 수평 분리
• 화면별 / 기능별로 분리 → feature별 독립성 확보
• 모듈은 어떻게 나누는가? - (2) 수평 분리
• 화면별 / 기능별로 분리 → feature별 독립성 확보
• 라이브러리 기준 분리: Realm 등 black magic 계의 기술이 사용된 부분은 극력 별도 모듈로 분리
• 모듈은 어떻게 나누는가? - (2) 수평 분리
• 화면별 / 기능별로 분리 → feature별 독립성 확보
• 라이브러리 기준 분리: Realm 등 black magic 계의 기술이 사용된 부분은 극력 별도 모듈로 분리
• → 결과적으로 10~30 개 정도의 모듈로 앱이 구성됨 (주의: 중규모 이상의 팀의 경우)
• 모듈은 어떻게 나누는가? - (2) 수평 분리
• 화면별 / 기능별로 분리 → feature별 독립성 확보
• 라이브러리 기준 분리: Realm 등 black magic 계의 기술이 사용된 부분은 극력 별도 모듈로 분리
• → 결과적으로 10~30 개 정도의 모듈로 앱이 구성됨 (주의: 중규모 이상의 팀의 경우)
• 주의점: 상호 참조
• 모듈은 어떻게 나누는가? - (2) 수평 분리
• 화면별 / 기능별로 분리 → feature별 독립성 확보
• 라이브러리 기준 분리: Realm 등 black magic 계의 기술이 사용된 부분은 극력 별도 모듈로 분리
• → 결과적으로 10~30 개 정도의 모듈로 앱이 구성됨 (주의: 중규모 이상의 팀의 경우)
• 주의점: 상호 참조
• 안드로이드 모듈의 참조는 단방향만 허용하므로 양방향의 참조가 불가
• 모듈은 어떻게 나누는가? - (2) 수평 분리
• 화면별 / 기능별로 분리 → feature별 독립성 확보
• 라이브러리 기준 분리: Realm 등 black magic 계의 기술이 사용된 부분은 극력 별도 모듈로 분리
• → 결과적으로 10~30 개 정도의 모듈로 앱이 구성됨 (주의: 중규모 이상의 팀의 경우)
• 주의점: 상호 참조
• 안드로이드 모듈의 참조는 단방향만 허용하므로 양방향의 참조가 불가
• 두 개의 화면이 각자 서로를 시작할 수 있는 경우는, 각자의 intent를 가져야 하므로 분리가 불가능해짐
• 모듈은 어떻게 나누는가? - (2) 수평 분리
• 화면별 / 기능별로 분리 → feature별 독립성 확보
• 라이브러리 기준 분리: Realm 등 black magic 계의 기술이 사용된 부분은 극력 별도 모듈로 분리
• → 결과적으로 10~30 개 정도의 모듈로 앱이 구성됨 (주의: 중규모 이상의 팀의 경우)
• 주의점: 상호 참조
• 안드로이드 모듈의 참조는 단방향만 허용하므로 양방향의 참조가 불가
• 두 개의 화면이 각자 서로를 시작할 수 있는 경우는, 각자의 intent를 가져야 하므로 분리가 불가능해짐
• Intent 생성 인터페이스만을 갖고 구현은 최상위 모듈(:app)이 소유 → DI로 얻어오기
• 모듈은 어떻게 나누는가? - (2) 수평 분리
• 화면별 / 기능별로 분리 → feature별 독립성 확보
• 라이브러리 기준 분리: Realm 등 black magic 계의 기술이 사용된 부분은 극력 별도 모듈로 분리
• → 결과적으로 10~30 개 정도의 모듈로 앱이 구성됨 (주의: 중규모 이상의 팀의 경우)
• 주의점: 상호 참조
• 안드로이드 모듈의 참조는 단방향만 허용하므로 양방향의 참조가 불가
• 두 개의 화면이 각자 서로를 시작할 수 있는 경우는, 각자의 intent를 가져야 하므로 분리가 불가능해짐
• Intent 생성 인터페이스만을 갖고 구현은 최상위 모듈(:app)이 소유 → DI로 얻어오기
• 중앙집중식 navigation 클래스를 만들고 각 모듈은 인터페이스만 갖도록 구현 (DroidKaigi 2018 앱
참조)
• 모듈은 어떻게 나누는가? - (2) 수평 분리
• 화면별 / 기능별로 분리 → feature별 독립성 확보
• 라이브러리 기준 분리: Realm 등 black magic 계의 기술이 사용된 부분은 극력 별도 모듈로 분리
• → 결과적으로 10~30 개 정도의 모듈로 앱이 구성됨 (주의: 중규모 이상의 팀의 경우)
• 주의점: 상호 참조
• 안드로이드 모듈의 참조는 단방향만 허용하므로 양방향의 참조가 불가
• 두 개의 화면이 각자 서로를 시작할 수 있는 경우는, 각자의 intent를 가져야 하므로 분리가 불가능해짐
• Intent 생성 인터페이스만을 갖고 구현은 최상위 모듈(:app)이 소유 → DI로 얻어오기
• 중앙집중식 navigation 클래스를 만들고 각 모듈은 인터페이스만 갖도록 구현 (DroidKaigi 2018 앱
참조)
• Tip: Dagger를 이용한 주입 + 사용자 파라미터가 동시에 필요한 경우라면, AssistedInjection 을 사용
• Dependency Inversion Principle: 이제까지 Android에서 중요시 된 적 없던 설계 원칙
• Dependency Inversion Principle: 이제까지 Android에서 중요시 된 적 없던 설계 원칙
• 상위 모듈은 하위 모듈에 의존성이 있어서는 안 된다 & 상위 모듈 하위 모듈 모두 인터페이스에만 의존한다
• Dependency Inversion Principle: 이제까지 Android에서 중요시 된 적 없던 설계 원칙
• 상위 모듈은 하위 모듈에 의존성이 있어서는 안 된다 & 상위 모듈 하위 모듈 모두 인터페이스에만 의존한다
• 의존성이 생기는 클래스가 volatile 하다면 인터페이스로만 참조가 일어나야 한다
• Dependency Inversion Principle: 이제까지 Android에서 중요시 된 적 없던 설계 원칙
• 상위 모듈은 하위 모듈에 의존성이 있어서는 안 된다 & 상위 모듈 하위 모듈 모두 인터페이스에만 의존한다
• 의존성이 생기는 클래스가 volatile 하다면 인터페이스로만 참조가 일어나야 한다
• A 객체가 B 객체의 레퍼런스를 직접 참조하는 대신, interface를 참조하여 구현 의존성을 끊음
• Dependency Inversion Principle: 이제까지 Android에서 중요시 된 적 없던 설계 원칙
• 상위 모듈은 하위 모듈에 의존성이 있어서는 안 된다 & 상위 모듈 하위 모듈 모두 인터페이스에만 의존한다
• 의존성이 생기는 클래스가 volatile 하다면 인터페이스로만 참조가 일어나야 한다
• A 객체가 B 객체의 레퍼런스를 직접 참조하는 대신, interface를 참조하여 구현 의존성을 끊음
• B가 변경되어도 A는 컴파일할 필요가 없음
• Dependency Inversion Principle: 이제까지 Android에서 중요시 된 적 없던 설계 원칙
• 상위 모듈은 하위 모듈에 의존성이 있어서는 안 된다 & 상위 모듈 하위 모듈 모두 인터페이스에만 의존한다
• 의존성이 생기는 클래스가 volatile 하다면 인터페이스로만 참조가 일어나야 한다
• A 객체가 B 객체의 레퍼런스를 직접 참조하는 대신, interface를 참조하여 구현 의존성을 끊음
• B가 변경되어도 A는 컴파일할 필요가 없음
• 동일한 인터페이스를 갖지만 전혀 다른 로직으로 구현된 제3의 모듈로 쉽게 변경 가능 

→ Dependency Injection의 도움을 받으면 각 모듈 별 설정을 일관된 방식으로 손쉽게 수정 가능
DIP + DI 도입전
DIP + DI 도입전
그림 출처: https://speakerdeck.com/sansanbuildersbox/multi-module-android-application
DIP + DI 도입후
DIP + DI 도입후
그림 출처: https://speakerdeck.com/sansanbuildersbox/multi-module-android-application
결과적으로..
결과적으로..
그림 출처: https://speakerdeck.com/sansanbuildersbox/multi-module-android-application
메인 리스트 화면 관련 컨텐츠 상세 화면 관련
사실 의존성 주입에 대해 할 말이 많지만..
떠오르는 꿈나무에 양보하겠습니다.
2. RxJava vs Coroutine vs LiveData
• 왜 필요한가?
2. RxJava vs Coroutine vs LiveData
• 왜 필요한가?
• Reactive: 비동기적인 처리를 imperative하게 처리할 수 있게 해줌
2. RxJava vs Coroutine vs LiveData
• 왜 필요한가?
• Reactive: 비동기적인 처리를 imperative하게 처리할 수 있게 해줌
• RxJava
2. RxJava vs Coroutine vs LiveData
• 왜 필요한가?
• Reactive: 비동기적인 처리를 imperative하게 처리할 수 있게 해줌
• RxJava
• 여전히, Android에서의 비동기 처리 위한 현존하는 가장 강력하고 편리한 수단
2. RxJava vs Coroutine vs LiveData
• 왜 필요한가?
• Reactive: 비동기적인 처리를 imperative하게 처리할 수 있게 해줌
• RxJava
• 여전히, Android에서의 비동기 처리 위한 현존하는 가장 강력하고 편리한 수단
• Android에서의 복잡한 상태처리를 직관적으로 구현 가능
2. RxJava vs Coroutine vs LiveData
• 왜 필요한가?
• Reactive: 비동기적인 처리를 imperative하게 처리할 수 있게 해줌
• RxJava
• 여전히, Android에서의 비동기 처리 위한 현존하는 가장 강력하고 편리한 수단
• Android에서의 복잡한 상태처리를 직관적으로 구현 가능
• View - ViewModel과의 가교를 위한 black magic 스러운 다양한 구현도 가능
2. RxJava vs Coroutine vs LiveData
• 왜 필요한가?
• Reactive: 비동기적인 처리를 imperative하게 처리할 수 있게 해줌
• RxJava
• 여전히, Android에서의 비동기 처리 위한 현존하는 가장 강력하고 편리한 수단
• Android에서의 복잡한 상태처리를 직관적으로 구현 가능
• View - ViewModel과의 가교를 위한 black magic 스러운 다양한 구현도 가능
• eg. 상황에 따라 순차적으로 실행해야 하는 애니메이션들을 각각
Completable로 정의한 후, Combine해서 실행
• 이런 것도 가능!

• ViewGroup의 중점이 바뀔 때마다 ViewModel이 통지를 받을 수 있도록 View 측에서 호
출할 수 있는 헬퍼 함수

fun createVerticalCenterPublisher(layout: View): Observable<Int> =
Observable.create<Int> { emitter ->
emitter.onNext(layout.bottom - layout.top)
val callback = View.OnLayoutChangeListener { _, _, top, _, bottom, _, _, _, _ ->
emitter.onNext(bottom - top)
}
layout.addOnLayoutChangeListener(callback)
emitter.setCancellable {
layout.removeOnLayoutChangeListener(callback)
}
}.subscribeOn(AndroidSchedulers.mainThread())
.throttleLatest(100, TimeUnit.MILLISECONDS, true)
.map { it / 2 }
더 자세한 건…
헐!? 그 명강의를 안 들었다고요?! 😱

YouTube 다시보기를 강추드립니다.
Coroutine
• 뭐가 좋은가?
Coroutine
• 뭐가 좋은가?
• 성능 이점: coroutine is light-weight threads
Coroutine
• 뭐가 좋은가?
• 성능 이점: coroutine is light-weight threads
• Rx보다 덜 어렵다
Coroutine
• 뭐가 좋은가?
• 성능 이점: coroutine is light-weight threads
• Rx보다 덜 어렵다
• 보다 functional한 구현 - Saga 패턴 같은 형태의 구현에 탁월
Coroutine
• 뭐가 좋은가?
• 성능 이점: coroutine is light-weight threads
• Rx보다 덜 어렵다
• 보다 functional한 구현 - Saga 패턴 같은 형태의 구현에 탁월
• 이제는 안정기에 접어들었음 - Kotlin 1.3과 함께 정식 버전이 되었고, 최신 사양에 맞춘 다양한 지
원이 예정되어 있음.
Coroutine
• 뭐가 좋은가?
• 성능 이점: coroutine is light-weight threads
• Rx보다 덜 어렵다
• 보다 functional한 구현 - Saga 패턴 같은 형태의 구현에 탁월
• 이제는 안정기에 접어들었음 - Kotlin 1.3과 함께 정식 버전이 되었고, 최신 사양에 맞춘 다양한 지
원이 예정되어 있음.
• lifecycle-viewModel-ktx 2.1.0 (현재 alpha03)부터 lifecycle-aware한 Coroutine Scope
인 viewmodelScope를 공식 지원
Coroutine
• 뭐가 좋은가?
• 성능 이점: coroutine is light-weight threads
• Rx보다 덜 어렵다
• 보다 functional한 구현 - Saga 패턴 같은 형태의 구현에 탁월
• 이제는 안정기에 접어들었음 - Kotlin 1.3과 함께 정식 버전이 되었고, 최신 사양에 맞춘 다양한 지
원이 예정되어 있음.
• lifecycle-viewModel-ktx 2.1.0 (현재 alpha03)부터 lifecycle-aware한 Coroutine Scope
인 viewmodelScope를 공식 지원
• retrofit 차기 버전에서 “suspend fun”을 형태로 api interface 정의 (현재 “Deferred”를 리턴
하는 형태)
더 자세한 건…
더 자세한 건…
지금이라도 늦지 않았습니다.

옆 강의실로 고고~ ☺
LiveData
• LiveData에 대해 논하기 전에..
LiveData
• LiveData에 대해 논하기 전에..
• View - ViewModel (or Presenter) 간의 이벤트 통지에 있어서 가장 이상적인 이
벤트 통지 전달자는 어떤 특징을 가져야할까?
LiveData
• LiveData에 대해 논하기 전에..
• View - ViewModel (or Presenter) 간의 이벤트 통지에 있어서 가장 이상적인 이
벤트 통지 전달자는 어떤 특징을 가져야할까?
• 이벤트 전달이 UI 스레드에서 이뤄져야 한다
LiveData
• LiveData에 대해 논하기 전에..
• View - ViewModel (or Presenter) 간의 이벤트 통지에 있어서 가장 이상적인 이
벤트 통지 전달자는 어떤 특징을 가져야할까?
• 이벤트 전달이 UI 스레드에서 이뤄져야 한다
• Side Effect의 공유가 가능해야한다. -> 쉬운 말로 하면 하나의 이벤트를 여러 이
벤트 핸들러가 공유할 수 있어야 한다
LiveData
• LiveData에 대해 논하기 전에..
• View - ViewModel (or Presenter) 간의 이벤트 통지에 있어서 가장 이상적인 이
벤트 통지 전달자는 어떤 특징을 가져야할까?
• 이벤트 전달이 UI 스레드에서 이뤄져야 한다
• Side Effect의 공유가 가능해야한다. -> 쉬운 말로 하면 하나의 이벤트를 여러 이
벤트 핸들러가 공유할 수 있어야 한다
• 에러를 skip 할 수 있어야 한다
LiveData
• LiveData에 대해 논하기 전에..
• View - ViewModel (or Presenter) 간의 이벤트 통지에 있어서 가장 이상적인 이
벤트 통지 전달자는 어떤 특징을 가져야할까?
• 이벤트 전달이 UI 스레드에서 이뤄져야 한다
• Side Effect의 공유가 가능해야한다. -> 쉬운 말로 하면 하나의 이벤트를 여러 이
벤트 핸들러가 공유할 수 있어야 한다
• 에러를 skip 할 수 있어야 한다
• → RxSwift의 경우, Signal/Driver가 이에 해당
• LiveData의 특징
• LiveData의 특징
• 기본적으로 UI thread에서 동작
• LiveData의 특징
• 기본적으로 UI thread에서 동작
• Side Effect(값의 변화, 이벤트)의 공유가 가능
• LiveData의 특징
• 기본적으로 UI thread에서 동작
• Side Effect(값의 변화, 이벤트)의 공유가 가능
• Configuration 변경 시 마지막 발생한 이벤트를 replay 해줌 (단, 의도치 않은 버그가 생길 여지
있음)
• LiveData의 특징
• 기본적으로 UI thread에서 동작
• Side Effect(값의 변화, 이벤트)의 공유가 가능
• Configuration 변경 시 마지막 발생한 이벤트를 replay 해줌 (단, 의도치 않은 버그가 생길 여지
있음)
• transformation을 통해 RxJava의 combine과 비슷하게 구현 가능
• LiveData의 특징
• 기본적으로 UI thread에서 동작
• Side Effect(값의 변화, 이벤트)의 공유가 가능
• Configuration 변경 시 마지막 발생한 이벤트를 replay 해줌 (단, 의도치 않은 버그가 생길 여지
있음)
• transformation을 통해 RxJava의 combine과 비슷하게 구현 가능
• → RxSwift의 Driver와 유사한 개념 + LifeCycle-awareness
• LiveData의 특징
• 기본적으로 UI thread에서 동작
• Side Effect(값의 변화, 이벤트)의 공유가 가능
• Configuration 변경 시 마지막 발생한 이벤트를 replay 해줌 (단, 의도치 않은 버그가 생길 여지
있음)
• transformation을 통해 RxJava의 combine과 비슷하게 구현 가능
• → RxSwift의 Driver와 유사한 개념 + LifeCycle-awareness
• LiveData는 언제 쓰는가?
• LiveData의 특징
• 기본적으로 UI thread에서 동작
• Side Effect(값의 변화, 이벤트)의 공유가 가능
• Configuration 변경 시 마지막 발생한 이벤트를 replay 해줌 (단, 의도치 않은 버그가 생길 여지
있음)
• transformation을 통해 RxJava의 combine과 비슷하게 구현 가능
• → RxSwift의 Driver와 유사한 개념 + LifeCycle-awareness
• LiveData는 언제 쓰는가?
• Rx의 대체재가 아닌 보완재
• LiveData의 특징
• 기본적으로 UI thread에서 동작
• Side Effect(값의 변화, 이벤트)의 공유가 가능
• Configuration 변경 시 마지막 발생한 이벤트를 replay 해줌 (단, 의도치 않은 버그가 생길 여지
있음)
• transformation을 통해 RxJava의 combine과 비슷하게 구현 가능
• → RxSwift의 Driver와 유사한 개념 + LifeCycle-awareness
• LiveData는 언제 쓰는가?
• Rx의 대체재가 아닌 보완재
• DataBinding 용도로 ObservableField보다 적합할 수도 있으나.. 있으나.. ;;;
더 자세한 건…
개인적으로는 large-scale app이라면 LiveData를 일부 소
극적으로 쓰고, RxBinding을 적극적으로 사용합니다.
Part IV. 

Best Examples
선정 조건
• 앱 규모: Toy project가 아니고 실제 Play Store에 올라온 앱인가

• 설계: Clean Architecture 등이 잘 적용되어 있는가

• 테스트: Unit Test가 요소요소 잘 구현되어 있는가

• 코드 품질: 내 프로젝트에도 갖다 쓸만한 표현이 많은가
Google IO 2018
• https://github.com/google/iosched 

• Clean Architecture - Domain layer의 UseCase 구현 및 테스트

• LiveData 사용의 진수: RxJava 아니면 안 될 것 같은 기능들까지도 몽땅
MediatorLiveData로 구현!

• 주의할 점: LiveData를 실제로 저렇게 쓰는 것은 극력 비추천

• 기타 아키텍처 외적으로 세부 코드 구현에 참고할 점이 매우 많음
DroidKaigi 2018
• https://github.com/DroidKaigi/conference-app-2018 

• 가장 모범적인 MVVM 구조

• 가장 훌륭하고 깔끔한 Dagger 정의

• Domain - Data 레이어를 특별히 나누지 않고 Repository 패턴으로 구현

• NavigationController - 매우 훌륭한 coordination 대안

• gradle kts
DroidKaigi 2019
• https://github.com/DroidKaigi/conference-app-2019 

• 멀티 모듈 구현

• + iOS도 지원

• Flux 구조: Store를 ViewModel로 구현

• Dagger 확장: AssistInjection!

• 최신 UI 구현! - Custom LayoutManager의 좋은 예를 볼 수 있다!
I’ll be back!
• DroidKnights 2020 안드로이드 아키텍처 세번째 시리즈로 돌아옵니다. 

내용은 아마도..

• Coroutine + Arrow로 구현한 functional한 Redux 구조 심층 분석

• 대규모 Multi-module 프로젝트 구축

• 기타 등등

• (개점휴업 중이던) 블로그 재개합니다! - 4/20부터

• 실제 프로젝트에서 의미있는 Test-Driven Development

• Dagger 2 Dependency Injection 구현 전략 총정리
강사룡
Email: justfaceit@gmail.com
Blog: https://medium.com/@justfaceit
Slide: https://slideshare.net/saryongkang

More Related Content

What's hot

131 deview 2013 yobi-채수원
131 deview 2013 yobi-채수원131 deview 2013 yobi-채수원
131 deview 2013 yobi-채수원
NAVER D2
 
[D2 fest 2014]yobi hands on lab
[D2 fest 2014]yobi hands on lab[D2 fest 2014]yobi hands on lab
[D2 fest 2014]yobi hands on lab
NAVER D2
 
1.openseminar
1.openseminar1.openseminar
1.openseminar
NAVER D2
 

What's hot (20)

[124] 하이브리드 앱 개발기 김한솔
[124] 하이브리드 앱 개발기 김한솔[124] 하이브리드 앱 개발기 김한솔
[124] 하이브리드 앱 개발기 김한솔
 
[Tech meet up] 2018 프론트엔드 트렌드&인사이트
[Tech meet up] 2018 프론트엔드 트렌드&인사이트[Tech meet up] 2018 프론트엔드 트렌드&인사이트
[Tech meet up] 2018 프론트엔드 트렌드&인사이트
 
React vac pattern
React vac patternReact vac pattern
React vac pattern
 
[TECHCON 2019: MOBILE - Android]3.안드로이드 개발자 로드맵
[TECHCON 2019: MOBILE - Android]3.안드로이드 개발자 로드맵[TECHCON 2019: MOBILE - Android]3.안드로이드 개발자 로드맵
[TECHCON 2019: MOBILE - Android]3.안드로이드 개발자 로드맵
 
학교에선 알려주지 않는 오픈소스이야기 - 박치완님
학교에선 알려주지 않는 오픈소스이야기 - 박치완님학교에선 알려주지 않는 오픈소스이야기 - 박치완님
학교에선 알려주지 않는 오픈소스이야기 - 박치완님
 
모바일앱개발 교육자료
모바일앱개발 교육자료모바일앱개발 교육자료
모바일앱개발 교육자료
 
[143] 모바일 혈액진단기기 개발 삽질기
[143] 모바일 혈액진단기기 개발 삽질기[143] 모바일 혈액진단기기 개발 삽질기
[143] 모바일 혈액진단기기 개발 삽질기
 
deview2014
deview2014deview2014
deview2014
 
How_to_choose_the_right_framework
How_to_choose_the_right_frameworkHow_to_choose_the_right_framework
How_to_choose_the_right_framework
 
제 5회 D2 CAMPUS FEST O.T - billboard.js 차트오픈소스개발기
제 5회 D2 CAMPUS FEST O.T -  billboard.js 차트오픈소스개발기제 5회 D2 CAMPUS FEST O.T -  billboard.js 차트오픈소스개발기
제 5회 D2 CAMPUS FEST O.T - billboard.js 차트오픈소스개발기
 
131 deview 2013 yobi-채수원
131 deview 2013 yobi-채수원131 deview 2013 yobi-채수원
131 deview 2013 yobi-채수원
 
BEM을 깨우치다.
BEM을 깨우치다.BEM을 깨우치다.
BEM을 깨우치다.
 
웹-프론트엔드 프레임워크를 고르기 위한 팁
웹-프론트엔드 프레임워크를 고르기 위한 팁웹-프론트엔드 프레임워크를 고르기 위한 팁
웹-프론트엔드 프레임워크를 고르기 위한 팁
 
최전방 생존법 - 프론트엔드 개발자로 살아가기
최전방 생존법 - 프론트엔드 개발자로 살아가기최전방 생존법 - 프론트엔드 개발자로 살아가기
최전방 생존법 - 프론트엔드 개발자로 살아가기
 
Fuse소개
Fuse소개Fuse소개
Fuse소개
 
진보한 개발 환경에서 품질 좋은 코드 생산 (WebStorm)
진보한 개발 환경에서 품질 좋은 코드 생산 (WebStorm)진보한 개발 환경에서 품질 좋은 코드 생산 (WebStorm)
진보한 개발 환경에서 품질 좋은 코드 생산 (WebStorm)
 
구글 인박스 히드라 프로그래밍
구글 인박스 히드라 프로그래밍구글 인박스 히드라 프로그래밍
구글 인박스 히드라 프로그래밍
 
[D2 fest 2014]yobi hands on lab
[D2 fest 2014]yobi hands on lab[D2 fest 2014]yobi hands on lab
[D2 fest 2014]yobi hands on lab
 
1.openseminar
1.openseminar1.openseminar
1.openseminar
 
Atlassian 및 오픈소스를 이용한 DevOps 구축 - 한국정보컨설팅
Atlassian 및 오픈소스를 이용한 DevOps 구축 - 한국정보컨설팅Atlassian 및 오픈소스를 이용한 DevOps 구축 - 한국정보컨설팅
Atlassian 및 오픈소스를 이용한 DevOps 구축 - 한국정보컨설팅
 

Similar to Droid knights 2019 - (Large-scale App을 위한) Android Architecture 총정리

아키텍트가 알아야 할 12/97가지
아키텍트가 알아야 할 12/97가지아키텍트가 알아야 할 12/97가지
아키텍트가 알아야 할 12/97가지
YoungSu Son
 

Similar to Droid knights 2019 - (Large-scale App을 위한) Android Architecture 총정리 (20)

[네이버오픈소스세미나] egjs-view360 개발기 - 김희재
[네이버오픈소스세미나] egjs-view360 개발기 - 김희재[네이버오픈소스세미나] egjs-view360 개발기 - 김희재
[네이버오픈소스세미나] egjs-view360 개발기 - 김희재
 
꿀밋업1탄_왜_마이크로서비스인가
꿀밋업1탄_왜_마이크로서비스인가꿀밋업1탄_왜_마이크로서비스인가
꿀밋업1탄_왜_마이크로서비스인가
 
기술적 변화를 이끌어가기
기술적 변화를 이끌어가기기술적 변화를 이끌어가기
기술적 변화를 이끌어가기
 
2014 공개소프트웨어 대회 소프트웨어 개발 트렌드의 변화
2014 공개소프트웨어 대회 소프트웨어 개발 트렌드의 변화2014 공개소프트웨어 대회 소프트웨어 개발 트렌드의 변화
2014 공개소프트웨어 대회 소프트웨어 개발 트렌드의 변화
 
주니어 입장에서 바라보는 디자인패턴 & 아키텍쳐.pdf
주니어 입장에서 바라보는 디자인패턴 & 아키텍쳐.pdf주니어 입장에서 바라보는 디자인패턴 & 아키텍쳐.pdf
주니어 입장에서 바라보는 디자인패턴 & 아키텍쳐.pdf
 
소프트웨어 개발 트랜드 및 MSA (마이크로 서비스 아키텍쳐)의 이해
소프트웨어 개발 트랜드 및 MSA (마이크로 서비스 아키텍쳐)의 이해소프트웨어 개발 트랜드 및 MSA (마이크로 서비스 아키텍쳐)의 이해
소프트웨어 개발 트랜드 및 MSA (마이크로 서비스 아키텍쳐)의 이해
 
회사에서 새로운 기술_적용하기
회사에서 새로운 기술_적용하기회사에서 새로운 기술_적용하기
회사에서 새로운 기술_적용하기
 
꿀밋업시리즈3탄_Spring Boot를 활용한 마이크로서비스 개발과 페어프로그래밍(TDD)
꿀밋업시리즈3탄_Spring Boot를 활용한 마이크로서비스 개발과 페어프로그래밍(TDD)꿀밋업시리즈3탄_Spring Boot를 활용한 마이크로서비스 개발과 페어프로그래밍(TDD)
꿀밋업시리즈3탄_Spring Boot를 활용한 마이크로서비스 개발과 페어프로그래밍(TDD)
 
How to implement your dream 20150427
How to implement your dream 20150427How to implement your dream 20150427
How to implement your dream 20150427
 
아키텍트가 알아야 할 12/97가지
아키텍트가 알아야 할 12/97가지아키텍트가 알아야 할 12/97가지
아키텍트가 알아야 할 12/97가지
 
Event storming based msa training commerce example add_handson_v3
Event storming based msa training commerce example add_handson_v3Event storming based msa training commerce example add_handson_v3
Event storming based msa training commerce example add_handson_v3
 
MVC, MVVM, ReactorKit, VIPER를 거쳐 RIB 정착기
MVC, MVVM, ReactorKit, VIPER를 거쳐 RIB 정착기MVC, MVVM, ReactorKit, VIPER를 거쳐 RIB 정착기
MVC, MVVM, ReactorKit, VIPER를 거쳐 RIB 정착기
 
[오픈소스컨설팅]Session 6. scrum과 jira 기반의 소프트웨어 개발 프로세스
[오픈소스컨설팅]Session 6. scrum과 jira 기반의 소프트웨어 개발 프로세스[오픈소스컨설팅]Session 6. scrum과 jira 기반의 소프트웨어 개발 프로세스
[오픈소스컨설팅]Session 6. scrum과 jira 기반의 소프트웨어 개발 프로세스
 
2016 Staccato track3 Android를 더 잘 개발하려면? (MVP, MVVM, Clean Architecture)
2016 Staccato track3 Android를 더 잘 개발하려면? (MVP, MVVM, Clean Architecture)2016 Staccato track3 Android를 더 잘 개발하려면? (MVP, MVVM, Clean Architecture)
2016 Staccato track3 Android를 더 잘 개발하려면? (MVP, MVVM, Clean Architecture)
 
객체지향프로그래밍 특강
객체지향프로그래밍 특강객체지향프로그래밍 특강
객체지향프로그래밍 특강
 
초고속 웹사이트 개발을 위한 Codeigniter PHP Framework
초고속 웹사이트 개발을 위한 Codeigniter PHP Framework초고속 웹사이트 개발을 위한 Codeigniter PHP Framework
초고속 웹사이트 개발을 위한 Codeigniter PHP Framework
 
ALM과 DevOps 그리고 Azure DevOps
ALM과 DevOps 그리고 Azure DevOpsALM과 DevOps 그리고 Azure DevOps
ALM과 DevOps 그리고 Azure DevOps
 
2021년 2월 6일 개발자 이야기
2021년 2월 6일 개발자 이야기2021년 2월 6일 개발자 이야기
2021년 2월 6일 개발자 이야기
 
예비 개발자를 위한 소프트웨어 세상 이야기
예비 개발자를 위한 소프트웨어 세상 이야기예비 개발자를 위한 소프트웨어 세상 이야기
예비 개발자를 위한 소프트웨어 세상 이야기
 
모바일환경과 개발방향
모바일환경과 개발방향 모바일환경과 개발방향
모바일환경과 개발방향
 

Droid knights 2019 - (Large-scale App을 위한) Android Architecture 총정리

  • 1. (Large-Scale App을 위한) 
 안드로이드 아키텍처 총정리 Speaker. 강사룡 Slide Link: https://www.slideshare.net/saryongkang/droid-knights-2019-largescale-app-android-architecture
  • 2. Who is this guy? • 경력 19년차 SW 엔지니어 • 폐업 전문가: 미국에서 한 번, 한국에서 두 번 스타트업 창업 경험 • IBM iX Japan에서 Android/iOS 담당 Senior Specialist로 근무 중 • Droid Knights 2018 - 내가 안드로이드 엔지니어가 되었을 때 아무도 알려주 지 않은 것들
  • 3. IBM iX Japan - We’re building business by design • Design Thinking, Mobile Interaction, Digital Strategy, … • 좌우지간 새롭고 재밌고, 유저 지향적인 신 기술/사업을 구현해주는 컨설팅 조직 • 주요 고객: 일본 10대 그룹, 은행사, 양대 항공사
  • 4. 목차 • Part I. 서론 1. 주의사항 2. 선수 지식: 안드로이드 아키텍처 4분만에 벼락치기 - MVC, Clean Architecture, Testability, Reusability • Part II. Non-MVC 아키텍처 총정리 1. Non-MVC 아키텍처의 기본 설계 전략 2. MVP 3. MVVM 4. Redux • Part III. New Trend in 2019 1. Rx vs non-Rx 2. Multi-module • Part IV. Best Practices
  • 6. 1. 시작하기 전 주의사항 • 지나친 기대 금지 - 45분 강의에 너무 많은 걸 기대하시면 매우 곤란.. • 암기 금지 - 원리를 이해하는 것이 더 중요 • 무턱대고 납득하기 금지 - 왜 저런 얘기를 하는가를 이해하고, 판단은 여러분 스 스로 • 사진 촬영 무쓸모: 슬라이드는 아래 링크에서 다운 받으실 수 있습니다 • https://www.slideshare.net/saryongkang/droid-knights-2019- largescale-app-android-architecture
  • 7. 왜, 특별히 안드로이드 아키텍처 설계/구현에 있어서, 비판적 사고 가 중요한가?
  • 8. 왜, 특별히 안드로이드 아키텍처 설계/구현에 있어서, 비판적 사고 가 중요한가? • General Practice는 많은데 Best Practice는 찾아보기 어렵다
  • 9. 왜, 특별히 안드로이드 아키텍처 설계/구현에 있어서, 비판적 사고 가 중요한가? • General Practice는 많은데 Best Practice는 찾아보기 어렵다 • 심지어 G사가 만든 샘플조차 갑론을박의 여지가..
  • 10. 왜, 특별히 안드로이드 아키텍처 설계/구현에 있어서, 비판적 사고 가 중요한가? • General Practice는 많은데 Best Practice는 찾아보기 어렵다 • 심지어 G사가 만든 샘플조차 갑론을박의 여지가.. • 아키텍처 패턴의 겉을 맛보게 해주는 글은 많지만 핵심 철학에 대해 얘기하 는 글은 매우 희박하다
  • 11. 왜, 특별히 안드로이드 아키텍처 설계/구현에 있어서, 비판적 사고 가 중요한가? • General Practice는 많은데 Best Practice는 찾아보기 어렵다 • 심지어 G사가 만든 샘플조차 갑론을박의 여지가.. • 아키텍처 패턴의 겉을 맛보게 해주는 글은 많지만 핵심 철학에 대해 얘기하 는 글은 매우 희박하다 • 같은 이름을 가진 아키텍처 패턴도 각자 상황에 따라 매우 이질적으로 구현될 수 있다
  • 12. 2. 선수지식 • Architecture의 기본 중의 기본: MVC란 무엇인가?
  • 13. 2. 선수지식 • Architecture의 기본 중의 기본: MVC란 무엇인가? • Model = State + 비즈니스 로직 + 데이터 저장소
  • 14. 2. 선수지식 • Architecture의 기본 중의 기본: MVC란 무엇인가? • Model = State + 비즈니스 로직 + 데이터 저장소 • View = UI (보통 declarative하게 구현됨)
  • 15. 2. 선수지식 • Architecture의 기본 중의 기본: MVC란 무엇인가? • Model = State + 비즈니스 로직 + 데이터 저장소 • View = UI (보통 declarative하게 구현됨) • Controller = Flow 로직 + [비즈니스 로직] + [State]
  • 16. (30초만에 이해하는) Clean Architecture의 기본 출처: https://qiita.com/koutalou/items/07a4f9cf51a2d13e4cdc
  • 17. (30초만에 이해하는) Clean Architecture의 기본 • MVC에서 Model을 분해 → Domain Layer + Data Layer 출처: https://qiita.com/koutalou/items/07a4f9cf51a2d13e4cdc
  • 18. (30초만에 이해하는) Clean Architecture의 기본 • MVC에서 Model을 분해 → Domain Layer + Data Layer • MVC에서 비즈니스 로직을 분해 → Presentational Logic (in Presenter) / Domain Logic (in UseCase) 출처: https://qiita.com/koutalou/items/07a4f9cf51a2d13e4cdc
  • 19. 더 자세한 건… Clean Architecture 적용에 대한 철학과 원칙에 내한 내용 을 들으실 수 있습니다.
  • 20. • 그런데, 아주 작은 부분처럼 보이는 Presentation Logic에 주로 주목하는 이유는?
  • 21. • 그런데, 아주 작은 부분처럼 보이는 Presentation Logic에 주로 주목하는 이유는? • 도메인 로직이 차지하는 부분이 (상대적으로) 적음 - 대부분의 앱의 경우, 가장 복 잡한 비즈니스 로직은 백엔드 서버에 존재함
  • 22. • 그런데, 아주 작은 부분처럼 보이는 Presentation Logic에 주로 주목하는 이유는? • 도메인 로직이 차지하는 부분이 (상대적으로) 적음 - 대부분의 앱의 경우, 가장 복 잡한 비즈니스 로직은 백엔드 서버에 존재함 • 복잡하고 (대부분) 비동기적인 상태의 관리, 그리고 라이프 사이클 연동이 훨씬 복 잡하고 중요한 문제
  • 23. • 그런데, 아주 작은 부분처럼 보이는 Presentation Logic에 주로 주목하는 이유는? • 도메인 로직이 차지하는 부분이 (상대적으로) 적음 - 대부분의 앱의 경우, 가장 복 잡한 비즈니스 로직은 백엔드 서버에 존재함 • 복잡하고 (대부분) 비동기적인 상태의 관리, 그리고 라이프 사이클 연동이 훨씬 복 잡하고 중요한 문제 • 바꿔 얘기하면 모바일 아키텍처에서 가장 큰 난제는 tight coupling between ui and state changes 를 어떻게 해소할 것인가의 문제
  • 24. 아키텍처 관점에서 아래 두 개념은 왜 그리 중요한가? • 테스트 가능성 • 재사용성
 

  • 25. 아키텍처 관점에서 아래 두 개념은 왜 그리 중요한가? • 테스트 가능성 • 재사용성
 
 • “난 유닛테스트 따윈 필요 없어!”라고 차마 말하기 전에.. • Testablility가 떨어지는 코드란 무엇인가 생각해 봅시다 → Tightly-coupled • 테스트 가능성이 떨어지는 코드는 중요 라이브러리 변경, 기반 구조 변경에 대응하기가 어렵다
  • 26. 아키텍처 관점에서 아래 두 개념은 왜 그리 중요한가? • 테스트 가능성 • 재사용성
 
 • “난 유닛테스트 따윈 필요 없어!”라고 차마 말하기 전에.. • Testablility가 떨어지는 코드란 무엇인가 생각해 봅시다 → Tightly-coupled • 테스트 가능성이 떨어지는 코드는 중요 라이브러리 변경, 기반 구조 변경에 대응하기가 어렵다 • “현실적으로 한 번 짠 코드를 클래스/Fragment 단위로 재사용 가능한 경우가 얼마나 돼?”라고 차마 말하기 전에.. • Re-usability란 게 애초에 무엇이었나 생각해봅시다 → 적절한 모듈화, 캡슐화 • 재사용성이 떨어지는 구조는 기능 변경 / 확장성이 떨어진다 ≒ 코드 가독성이 떨어진다
  • 27. 참 쉽죠? 조금전 여러분은 안드로이드 아키텍처 초급과정을 수료하셨습니다. 
 🎉🎉🎉
  • 28. Part II. Non-MVC 아키텍처 총정리
  • 29. 쉬어가는 코너.. 이럴 때 안드로이드 개발자인 게 부끄럽다
  • 30. 쉬어가는 코너.. 이럴 때 안드로이드 개발자인 게 부끄럽다 어느 날,
 옆집 친구 아들 옆 동네 CTO를 만나고 온 이사님이
 나를 부르셨다.
  • 31. 자네... Activity는 몇 줄까지 짜봤나? Dilbert © 2018, Andrews McMeel Syndication 네?!
  • 32. 고수라면 보통 몇 천줄 정도 는 짜봤다던데.. 헐.. WTF?! 뭐야 그 정도도 못 해본 거였어? Dilbert © 2018, Andrews McMeel Syndication
  • 33. Fat Activity/Fragment - 만악의 근원 여기서 작년의 복습: 왜 Android MVC는 나쁜가?
  • 34. Fat Activity/Fragment - 만악의 근원 여기서 작년의 복습: 왜 Android MVC는 나쁜가? • Activity가 할 수 있는 일 • 라이프사이클 관리, 모든 UI 로직 - 레이아웃 생성, 렌더링, 애니메이션, Shared Preferences, 파일 IO, 화면 전환, 권한 설정, Loader, 그 외에 수 백 가지
  • 35. Fat Activity/Fragment - 만악의 근원 여기서 작년의 복습: 왜 Android MVC는 나쁜가? • Activity가 할 수 있는 일 • 라이프사이클 관리, 모든 UI 로직 - 레이아웃 생성, 렌더링, 애니메이션, Shared Preferences, 파일 IO, 화면 전환, 권한 설정, Loader, 그 외에 수 백 가지 • 기본 Android Architecture에서 Activity란? • Controller + View + alpha + omega = god • Fragment도 그냥 작은 신일뿐.. 😱
  • 37. Non-MVC의 설계 전략 • Non-MVC에서 Activity는 무엇인가? → Activity는 컨트롤러! (그것도 아주 제한적인..)
  • 38. Non-MVC의 설계 전략 • Non-MVC에서 Activity는 무엇인가? → Activity는 컨트롤러! (그것도 아주 제한적인..) • MVP의 (궁극적) 접근법
  • 39. Non-MVC의 설계 전략 • Non-MVC에서 Activity는 무엇인가? → Activity는 컨트롤러! (그것도 아주 제한적인..) • MVP의 (궁극적) 접근법 • Activity에서 View와 Controller의 역할을 최대한 빼앗아 View와 Presenter로 넘김. 
 Activity는 순수 flow 관리 역할 위주
  • 40. Non-MVC의 설계 전략 • Non-MVC에서 Activity는 무엇인가? → Activity는 컨트롤러! (그것도 아주 제한적인..) • MVP의 (궁극적) 접근법 • Activity에서 View와 Controller의 역할을 최대한 빼앗아 View와 Presenter로 넘김. 
 Activity는 순수 flow 관리 역할 위주 • MVVM/Redux 등의 접근법
  • 41. Non-MVC의 설계 전략 • Non-MVC에서 Activity는 무엇인가? → Activity는 컨트롤러! (그것도 아주 제한적인..) • MVP의 (궁극적) 접근법 • Activity에서 View와 Controller의 역할을 최대한 빼앗아 View와 Presenter로 넘김. 
 Activity는 순수 flow 관리 역할 위주 • MVVM/Redux 등의 접근법 • 마찬가지로 Activity는 최대한 일부 context 의존 기능만 하도록.. 
 View logic은 최대한 data binding으로 구현
  • 42. Non-MVC의 설계 전략 • Non-MVC에서 Activity는 무엇인가? → Activity는 컨트롤러! (그것도 아주 제한적인..) • MVP의 (궁극적) 접근법 • Activity에서 View와 Controller의 역할을 최대한 빼앗아 View와 Presenter로 넘김. 
 Activity는 순수 flow 관리 역할 위주 • MVVM/Redux 등의 접근법 • 마찬가지로 Activity는 최대한 일부 context 의존 기능만 하도록.. 
 View logic은 최대한 data binding으로 구현 • 여기서 의문: 왜 구글은 (배우기도 어렵고 Rx가 없으면 제대로 구현도 안 되는) ViewModel만을 AAC(Android Architecture Component)에서 지원하는가?
  • 43. Non-MVC의 설계 전략 • Non-MVC에서 Activity는 무엇인가? → Activity는 컨트롤러! (그것도 아주 제한적인..) • MVP의 (궁극적) 접근법 • Activity에서 View와 Controller의 역할을 최대한 빼앗아 View와 Presenter로 넘김. 
 Activity는 순수 flow 관리 역할 위주 • MVVM/Redux 등의 접근법 • 마찬가지로 Activity는 최대한 일부 context 의존 기능만 하도록.. 
 View logic은 최대한 data binding으로 구현 • 여기서 의문: 왜 구글은 (배우기도 어렵고 Rx가 없으면 제대로 구현도 안 되는) ViewModel만을 AAC(Android Architecture Component)에서 지원하는가? • 기존 Activity/Fragment의 형태를 깨뜨리지 않으면서 재사용성/생산성 높은 아키텍처를 구현 가능하기 때문*
  • 44. Non-MVC의 설계 전략 • Non-MVC에서 Activity는 무엇인가? → Activity는 컨트롤러! (그것도 아주 제한적인..) • MVP의 (궁극적) 접근법 • Activity에서 View와 Controller의 역할을 최대한 빼앗아 View와 Presenter로 넘김. 
 Activity는 순수 flow 관리 역할 위주 • MVVM/Redux 등의 접근법 • 마찬가지로 Activity는 최대한 일부 context 의존 기능만 하도록.. 
 View logic은 최대한 data binding으로 구현 • 여기서 의문: 왜 구글은 (배우기도 어렵고 Rx가 없으면 제대로 구현도 안 되는) ViewModel만을 AAC(Android Architecture Component)에서 지원하는가? • 기존 Activity/Fragment의 형태를 깨뜨리지 않으면서 재사용성/생산성 높은 아키텍처를 구현 가능하기 때문* ※주의: 어디까지나 추측입니다.
  • 46. Model-View-Presenter? • 1990년대 초 IBM에서 최초로 구현
  • 47. Model-View-Presenter? • 1990년대 초 IBM에서 최초로 구현 • 2006년 Martin Fowler의 소개로 널리 알려짐
 참조: GUI Architectures
 https://martinfowler.com/eaaDev/uiArchs.html
  • 48. Model-View-Presenter? • 1990년대 초 IBM에서 최초로 구현 • 2006년 Martin Fowler의 소개로 널리 알려짐
 참조: GUI Architectures
 https://martinfowler.com/eaaDev/uiArchs.html • 사실 안드로이드 초기부터 구전으로 전해져 왔던 아키텍처
  • 49. Model-View-Presenter? • 1990년대 초 IBM에서 최초로 구현 • 2006년 Martin Fowler의 소개로 널리 알려짐
 참조: GUI Architectures
 https://martinfowler.com/eaaDev/uiArchs.html • 사실 안드로이드 초기부터 구전으로 전해져 왔던 아키텍처 • 근데 이미 한물 간 구조 아닌가? 아직도 쓰나요?
  • 50. Model-View-Presenter? • 1990년대 초 IBM에서 최초로 구현 • 2006년 Martin Fowler의 소개로 널리 알려짐
 참조: GUI Architectures
 https://martinfowler.com/eaaDev/uiArchs.html • 사실 안드로이드 초기부터 구전으로 전해져 왔던 아키텍처 • 근데 이미 한물 간 구조 아닌가? 아직도 쓰나요? • 예, 아직도 많이 씁니다. 예를 들면, 같은 회사가요.
  • 51. Model-View-Presenter? • 1990년대 초 IBM에서 최초로 구현 • 2006년 Martin Fowler의 소개로 널리 알려짐
 참조: GUI Architectures
 https://martinfowler.com/eaaDev/uiArchs.html • 사실 안드로이드 초기부터 구전으로 전해져 왔던 아키텍처 • 근데 이미 한물 간 구조 아닌가? 아직도 쓰나요? • 예, 아직도 많이 씁니다. 예를 들면, 같은 회사가요.
  • 52. Presenter View Model 사용자 입력을 통보 데이터 갱신 요청 데이터 변경 통보 뷰 변경 요청
  • 53. Presenter View Model 사용자 입력을 통보 데이터 갱신 요청 데이터 변경 통보 뷰 변경 요청 • 모든 Presentational Business Logic을 Presenter에서 처리
  • 54. Presenter View Model 사용자 입력을 통보 데이터 갱신 요청 데이터 변경 통보 뷰 변경 요청 • 모든 Presentational Business Logic을 Presenter에서 처리 • View는 Presenter의 요청에 따라 수동적으로 UI를 처리함
  • 55. Google Architecture Blueprint로 분석해보는 MVP의 핵심 • https://github.com/googlesamples/android-architecture/tree/todo- mvp/
  • 56. Google Architecture Blueprint로 분석해보는 MVP의 핵심 • https://github.com/googlesamples/android-architecture/tree/todo- mvp/ • Contractor Pattern
  • 57. Google Architecture Blueprint로 분석해보는 MVP의 핵심 • https://github.com/googlesamples/android-architecture/tree/todo- mvp/ • Contractor Pattern • View, Presenter는 interface 형태로 서로를 참조
  • 58. Google Architecture Blueprint로 분석해보는 MVP의 핵심 • https://github.com/googlesamples/android-architecture/tree/todo- mvp/ • Contractor Pattern • View, Presenter는 interface 형태로 서로를 참조 • V와 P의 구현이 섞이거나, P가 플랫폼 의존적인 API를 직접 접근할 여지를 원천 봉쇄
  • 59. /** * This specifies the contract between the view and the presenter. */ public interface TasksContract { interface View extends BaseView<Presenter> { // ... void setLoadingIndicator(boolean active); void showTasks(List<Task> tasks); void showAddTask(); void showTaskDetailsUi(String taskId); } interface Presenter extends BasePresenter { // ... void loadTasks(boolean forceUpdate); void addNewTask(); void openTaskDetails(@NonNull Task requestedTask); void completeTask(@NonNull Task completedTask); void activateTask(@NonNull Task activeTask); void clearCompletedTasks(); void setFiltering(TasksFilterType requestType); TasksFilterType getFiltering(); } }
  • 60. /** * This specifies the contract between the view and the presenter. */ public interface TasksContract { interface View extends BaseView<Presenter> { // ... void setLoadingIndicator(boolean active); void showTasks(List<Task> tasks); void showAddTask(); void showTaskDetailsUi(String taskId); } interface Presenter extends BasePresenter { // ... void loadTasks(boolean forceUpdate); void addNewTask(); void openTaskDetails(@NonNull Task requestedTask); void completeTask(@NonNull Task completedTask); void activateTask(@NonNull Task activeTask); void clearCompletedTasks(); void setFiltering(TasksFilterType requestType); TasksFilterType getFiltering(); } } • TODO 앱의 각 작업(task)를 보여주고 추가 하는 화면을 위한 TasksContractor interface 정의
  • 61. /** * This specifies the contract between the view and the presenter. */ public interface TasksContract { interface View extends BaseView<Presenter> { // ... void setLoadingIndicator(boolean active); void showTasks(List<Task> tasks); void showAddTask(); void showTaskDetailsUi(String taskId); } interface Presenter extends BasePresenter { // ... void loadTasks(boolean forceUpdate); void addNewTask(); void openTaskDetails(@NonNull Task requestedTask); void completeTask(@NonNull Task completedTask); void activateTask(@NonNull Task activeTask); void clearCompletedTasks(); void setFiltering(TasksFilterType requestType); TasksFilterType getFiltering(); } } • TODO 앱의 각 작업(task)를 보여주고 추가 하는 화면을 위한 TasksContractor interface 정의 • View-Presenter 간의 직접 연결을 끊음
  • 62. /** * This specifies the contract between the view and the presenter. */ public interface TasksContract { interface View extends BaseView<Presenter> { // ... void setLoadingIndicator(boolean active); void showTasks(List<Task> tasks); void showAddTask(); void showTaskDetailsUi(String taskId); } interface Presenter extends BasePresenter { // ... void loadTasks(boolean forceUpdate); void addNewTask(); void openTaskDetails(@NonNull Task requestedTask); void completeTask(@NonNull Task completedTask); void activateTask(@NonNull Task activeTask); void clearCompletedTasks(); void setFiltering(TasksFilterType requestType); TasksFilterType getFiltering(); } } • TODO 앱의 각 작업(task)를 보여주고 추가 하는 화면을 위한 TasksContractor interface 정의 • View-Presenter 간의 직접 연결을 끊음 • Good?!
  • 63. • 다시 한 번 자세히 봅시다. 🤔/** * This specifies the contract between the view and the presenter. */ public interface TasksContract { interface View extends BaseView<Presenter> { // ... void setLoadingIndicator(boolean active); void showTasks(List<Task> tasks); void showAddTask(); void showTaskDetailsUi(String taskId); } interface Presenter extends BasePresenter { // ... void loadTasks(boolean forceUpdate); void addNewTask(); void openTaskDetails(@NonNull Task requestedTask); void completeTask(@NonNull Task completedTask); void activateTask(@NonNull Task activeTask); void clearCompletedTasks(); void setFiltering(TasksFilterType requestType); TasksFilterType getFiltering(); } }
  • 64. • 다시 한 번 자세히 봅시다. • 어라? Presenter의 메소드들을 보니 데 이터를 넘겨주는 것들이 있네? 🤔/** * This specifies the contract between the view and the presenter. */ public interface TasksContract { interface View extends BaseView<Presenter> { // ... void setLoadingIndicator(boolean active); void showTasks(List<Task> tasks); void showAddTask(); void showTaskDetailsUi(String taskId); } interface Presenter extends BasePresenter { // ... void loadTasks(boolean forceUpdate); void addNewTask(); void openTaskDetails(@NonNull Task requestedTask); void completeTask(@NonNull Task completedTask); void activateTask(@NonNull Task activeTask); void clearCompletedTasks(); void setFiltering(TasksFilterType requestType); TasksFilterType getFiltering(); } }
  • 65. • 다시 한 번 자세히 봅시다. • 어라? Presenter의 메소드들을 보니 데 이터를 넘겨주는 것들이 있네? • 그럼 상태 정보를 View가 갖는다는 얘 기?! 🤔/** * This specifies the contract between the view and the presenter. */ public interface TasksContract { interface View extends BaseView<Presenter> { // ... void setLoadingIndicator(boolean active); void showTasks(List<Task> tasks); void showAddTask(); void showTaskDetailsUi(String taskId); } interface Presenter extends BasePresenter { // ... void loadTasks(boolean forceUpdate); void addNewTask(); void openTaskDetails(@NonNull Task requestedTask); void completeTask(@NonNull Task completedTask); void activateTask(@NonNull Task activeTask); void clearCompletedTasks(); void setFiltering(TasksFilterType requestType); TasksFilterType getFiltering(); } }
  • 66. /** * Display a grid of {@link Task}s. User can choose to view all, active or completed tasks. */ public class TasksFragment extends Fragment implements TasksContract.View { private TasksContract.Presenter mPresenter; //... TaskItemListener mItemListener = new TaskItemListener() { @Override public void onTaskClick(Task clickedTask) { mPresenter.openTaskDetails(clickedTask); } @Override public void onCompleteTaskClick(Task completedTask) { mPresenter.completeTask(completedTask); } @Override public void onActivateTaskClick(Task activatedTask) { mPresenter.activateTask(activatedTask); } }; //... private static class TasksAdapter extends BaseAdapter { private List<Task> mTasks; private TaskItemListener mItemListener; public TasksAdapter(List<Task> tasks, TaskItemListener itemListener) { setList(tasks); mItemListener = itemListener; } } } • Bingo! - 각 상태에 따른 태스크를 view가 판단해서 보내주고 있음
  • 67. /** * Display a grid of {@link Task}s. User can choose to view all, active or completed tasks. */ public class TasksFragment extends Fragment implements TasksContract.View { private TasksContract.Presenter mPresenter; //... TaskItemListener mItemListener = new TaskItemListener() { @Override public void onTaskClick(Task clickedTask) { mPresenter.openTaskDetails(clickedTask); } @Override public void onCompleteTaskClick(Task completedTask) { mPresenter.completeTask(completedTask); } @Override public void onActivateTaskClick(Task activatedTask) { mPresenter.activateTask(activatedTask); } }; //... private static class TasksAdapter extends BaseAdapter { private List<Task> mTasks; private TaskItemListener mItemListener; public TasksAdapter(List<Task> tasks, TaskItemListener itemListener) { setList(tasks); mItemListener = itemListener; } } } • Bingo! - 각 상태에 따른 태스크를 view가 판단해서 보내주고 있음 • 그 item listener를 호출하는 부분을 거 슬러 올라갔더니..
  • 68. /** * Display a grid of {@link Task}s. User can choose to view all, active or completed tasks. */ public class TasksFragment extends Fragment implements TasksContract.View { private TasksContract.Presenter mPresenter; //... TaskItemListener mItemListener = new TaskItemListener() { @Override public void onTaskClick(Task clickedTask) { mPresenter.openTaskDetails(clickedTask); } @Override public void onCompleteTaskClick(Task completedTask) { mPresenter.completeTask(completedTask); } @Override public void onActivateTaskClick(Task activatedTask) { mPresenter.activateTask(activatedTask); } }; //... private static class TasksAdapter extends BaseAdapter { private List<Task> mTasks; private TaskItemListener mItemListener; public TasksAdapter(List<Task> tasks, TaskItemListener itemListener) { setList(tasks); mItemListener = itemListener; } } } • Bingo! - 각 상태에 따른 태스크를 view가 판단해서 보내주고 있음 • 그 item listener를 호출하는 부분을 거 슬러 올라갔더니.. • Task 객체의 상태를 View가 갖고 있고, 어떤 presenter 함수가 호출되어야 할 지 를 View 결정한다?!
  • 69. • 헐?! 이건 MVP가 아니잖아! • View가 passive하지 않다! • 애초에 Activity가 Controller, Fragment 가 View의 역할을 하도록 만든 것 자체가, 일 정 규모 이상의 앱에서는 문제가 될 수 있는 설계 😒
  • 70. • 이런 오해 때문에 Martin Fowler는 Presenter라는 이름을 폐기하고 Supervising Controller라고 부를 것을 제안. (그리고 View는 Passive View 로 부름) • Ref: Retirement note for Model View Presenter Pattern
 https://martinfowler.com/eaaDev/ModelViewPresenter.html .
  • 71. 더 자세한 건… 왜 View는 Passive 해야하는가, 그리고 바람직한 View와 Presenter의 역할은 무엇인가? 속시원하게 알려드립니다… (아마도)
  • 72. • 타 아키텍처에도 적용되는 얘기만 하자면, P V M Home MVP* P V M Banner MVP P V M Original List MVP P V M Preview List MVP ※주의: 어디까지나 추측입니다.
  • 73. • 타 아키텍처에도 적용되는 얘기만 하자면, • Android의 경우, nested 구조로 갈 수밖에 없음. P V M Home MVP* P V M Banner MVP P V M Original List MVP P V M Preview List MVP ※주의: 어디까지나 추측입니다.
  • 74. • 타 아키텍처에도 적용되는 얘기만 하자면, • Android의 경우, nested 구조로 갈 수밖에 없음. • 그럼 구글은 왜 아키텍처 청사진을 이렇게 짰을 까? P V M Home MVP* P V M Banner MVP P V M Original List MVP P V M Preview List MVP ※주의: 어디까지나 추측입니다.
  • 75. • 타 아키텍처에도 적용되는 얘기만 하자면, • Android의 경우, nested 구조로 갈 수밖에 없음. • 그럼 구글은 왜 아키텍처 청사진을 이렇게 짰을 까? • 주의점: 특정 회사의 공식 샘플은 어떤 의도를 가지고 만들어 질 수도 있다는 점을 미리 염두 에 둘 필요가 있음 P V M Home MVP* P V M Banner MVP P V M Original List MVP P V M Preview List MVP ※주의: 어디까지나 추측입니다.
  • 77. MVVM • MVVM에서 View는 누구인가? http://kyubid.com/blog/understanding-mvvm-on-android-tutorial-05-introduction-to-reactive-programming-with-rxjava/
  • 78. MVVM • MVVM에서 View는 누구인가? • XML! DataBinding! http://kyubid.com/blog/understanding-mvvm-on-android-tutorial-05-introduction-to-reactive-programming-with-rxjava/
  • 79. MVVM • MVVM에서 View는 누구인가? • XML! DataBinding! • XML에 view logic을 포함 
 → Declarative한 UI 로직 구현이 가능
 → BindingAdapter 조합, RxJava/ RxBinding의 도움으로 View의 상당수 구현을 Activity/Fragment로부터 빼앗 아 올 수 있음 http://kyubid.com/blog/understanding-mvvm-on-android-tutorial-05-introduction-to-reactive-programming-with-rxjava/
  • 80.
  • 81. • ViewModel • 그 자체로 독립적인 시스템 • View에 접근할 수도 없고, 존재 자체도 모름
  • 82. • ViewModel • 그 자체로 독립적인 시스템 • View에 접근할 수도 없고, 존재 자체도 모름 • AAC의 ViewModel • LifeCycle 지원 기능 이외에 특별한 기능 없음 (차기 버전에서도 SavedState가 추가되는 정 도) • 직접 Life Cycle 처리를 구현하고 AAC-ViewModel을 사용하지 않아도 무방 • Pro tip: MVVM 구조 설명에서 AAC 그림부터 나오는 글이라면 믿고 거르시면 됩니다
  • 84. Redux - 출발점 • Part I.에서 얘기했듯, 모바일 앱에서 가장 큰 난제 중의 하나는 복잡한 상태 들을 어떻게 깔끔하고 유지보수성 높게 구현할 것인가의 문제
  • 85. Redux - 출발점 • Part I.에서 얘기했듯, 모바일 앱에서 가장 큰 난제 중의 하나는 복잡한 상태 들을 어떻게 깔끔하고 유지보수성 높게 구현할 것인가의 문제 • 발상을 바꿔서 앱 전체의 이벤트를 State Machine으로 처리한다면 어떨까?
  • 86. Redux - 출발점 • Part I.에서 얘기했듯, 모바일 앱에서 가장 큰 난제 중의 하나는 복잡한 상태 들을 어떻게 깔끔하고 유지보수성 높게 구현할 것인가의 문제 • 발상을 바꿔서 앱 전체의 이벤트를 State Machine으로 처리한다면 어떨까? • Life Cycle 처리로 골머리 앓을 일이 급격히 줄어듦
  • 87. Redux - 출발점 • Part I.에서 얘기했듯, 모바일 앱에서 가장 큰 난제 중의 하나는 복잡한 상태 들을 어떻게 깔끔하고 유지보수성 높게 구현할 것인가의 문제 • 발상을 바꿔서 앱 전체의 이벤트를 State Machine으로 처리한다면 어떨까? • Life Cycle 처리로 골머리 앓을 일이 급격히 줄어듦 • 상태에 따라 다르게 동작하는 UI를 보다 직관적으로 관리 가능
  • 88. Redux - 출발점 • Part I.에서 얘기했듯, 모바일 앱에서 가장 큰 난제 중의 하나는 복잡한 상태 들을 어떻게 깔끔하고 유지보수성 높게 구현할 것인가의 문제 • 발상을 바꿔서 앱 전체의 이벤트를 State Machine으로 처리한다면 어떨까? • Life Cycle 처리로 골머리 앓을 일이 급격히 줄어듦 • 상태에 따라 다르게 동작하는 UI를 보다 직관적으로 관리 가능 • 특정화면에서 수정 된 내용 (예: “좋아요” 상태 변경)이 다른 곳에서 저절로 적용
  • 90. • 그런데.. • State Machine을 직접 구현하다 보면.. 각 로직의 추상화를 어떻게 할 지 많은 고민 을 하게 됨
  • 91. • 그런데.. • State Machine을 직접 구현하다 보면.. 각 로직의 추상화를 어떻게 할 지 많은 고민 을 하게 됨 • 상태: 먼저 상태를 저장하는 부분은 보통 enum class 아니면, sealed class로 구현
  • 92. • 그런데.. • State Machine을 직접 구현하다 보면.. 각 로직의 추상화를 어떻게 할 지 많은 고민 을 하게 됨 • 상태: 먼저 상태를 저장하는 부분은 보통 enum class 아니면, sealed class로 구현 • 상태 천이(transition/flow): 어떤 조건에서는 B로, 또 다른 조건에서는 C로 변경
  • 93. • 그런데.. • State Machine을 직접 구현하다 보면.. 각 로직의 추상화를 어떻게 할 지 많은 고민 을 하게 됨 • 상태: 먼저 상태를 저장하는 부분은 보통 enum class 아니면, sealed class로 구현 • 상태 천이(transition/flow): 어떤 조건에서는 B로, 또 다른 조건에서는 C로 변경 • 로직 수행: 각 상태가 변경 되었을 때 수행해야할 실제 로직
  • 94. • 그런데.. • State Machine을 직접 구현하다 보면.. 각 로직의 추상화를 어떻게 할 지 많은 고민 을 하게 됨 • 상태: 먼저 상태를 저장하는 부분은 보통 enum class 아니면, sealed class로 구현 • 상태 천이(transition/flow): 어떤 조건에서는 B로, 또 다른 조건에서는 C로 변경 • 로직 수행: 각 상태가 변경 되었을 때 수행해야할 실제 로직 • 위 세 요소의 복잡도에 따라 상황에 맞게 구현해야하지만 가장 범용적인 방법 중 하나 는 uni-directional한 pipeline 형태 -> 바로 Flux 구조!
  • 96. MVI? Flux? Redux? • Flux: Facebook에서, 웹 프론트엔드의 상태 처리를 직관적이고 깔끔하게 하기 위 해 고안한 Architectural Pattern. 단방향의 pipelined loop를 통해 이벤트를 처리 • MVI: Flux에 View 처리 등 모바일 관련 내용을 추가해서 부르는 이름. 안드로이드 개발에선 Flux와 같은 용어라고 생각해도 무방 • Redux: Flux 패턴의 변형 구현체 중 가장 효율적이라고 알려진 구현체. (물론 Java Script로..) - immutable state, single source of truth를 실현한 단순한 구현 • Dan Abramov라는 젊은 개발자가 고안. 100여 줄에 불과한 라이브러리로 모든 Flux 구현체를 평정 -> flux 원 고안자에게 인정 받은 후, 바로 Facebook에서 스 카웃
  • 97. • Action: 상태를 변경하라는 명령만을 가짐 그림 출처: https://speakerdeck.com/yuyakaido/droidkaigi-2019
  • 98. • Action: 상태를 변경하라는 명령만을 가짐 • 보통은 Action Creator를 통해 만들어짐 그림 출처: https://speakerdeck.com/yuyakaido/droidkaigi-2019
  • 99. • Action: 상태를 변경하라는 명령만을 가짐 • 보통은 Action Creator를 통해 만들어짐 • State: 상태의 데이터만을 가짐. no logic 그림 출처: https://speakerdeck.com/yuyakaido/droidkaigi-2019
  • 100. • Action: 상태를 변경하라는 명령만을 가짐 • 보통은 Action Creator를 통해 만들어짐 • State: 상태의 데이터만을 가짐. no logic • immutable (flux는 mutable) 그림 출처: https://speakerdeck.com/yuyakaido/droidkaigi-2019
  • 101. • Action: 상태를 변경하라는 명령만을 가짐 • 보통은 Action Creator를 통해 만들어짐 • State: 상태의 데이터만을 가짐. no logic • immutable (flux는 mutable) • Store 그림 출처: https://speakerdeck.com/yuyakaido/droidkaigi-2019
  • 102. • Action: 상태를 변경하라는 명령만을 가짐 • 보통은 Action Creator를 통해 만들어짐 • State: 상태의 데이터만을 가짐. no logic • immutable (flux는 mutable) • Store • 상태의 저장소 그림 출처: https://speakerdeck.com/yuyakaido/droidkaigi-2019
  • 103. • Action: 상태를 변경하라는 명령만을 가짐 • 보통은 Action Creator를 통해 만들어짐 • State: 상태의 데이터만을 가짐. no logic • immutable (flux는 mutable) • Store • 상태의 저장소 • 상태를 변경시키고, 통지 하는 역할 그림 출처: https://speakerdeck.com/yuyakaido/droidkaigi-2019
  • 104. • Action: 상태를 변경하라는 명령만을 가짐 • 보통은 Action Creator를 통해 만들어짐 • State: 상태의 데이터만을 가짐. no logic • immutable (flux는 mutable) • Store • 상태의 저장소 • 상태를 변경시키고, 통지 하는 역할 • RxJava 혹은 Coroutine으로 손쉽게 구현 가능 그림 출처: https://speakerdeck.com/yuyakaido/droidkaigi-2019
  • 105. • Action: 상태를 변경하라는 명령만을 가짐 • 보통은 Action Creator를 통해 만들어짐 • State: 상태의 데이터만을 가짐. no logic • immutable (flux는 mutable) • Store • 상태의 저장소 • 상태를 변경시키고, 통지 하는 역할 • RxJava 혹은 Coroutine으로 손쉽게 구현 가능 • Reducer 그림 출처: https://speakerdeck.com/yuyakaido/droidkaigi-2019
  • 106. • Action: 상태를 변경하라는 명령만을 가짐 • 보통은 Action Creator를 통해 만들어짐 • State: 상태의 데이터만을 가짐. no logic • immutable (flux는 mutable) • Store • 상태의 저장소 • 상태를 변경시키고, 통지 하는 역할 • RxJava 혹은 Coroutine으로 손쉽게 구현 가능 • Reducer • 순수 함수(pure function) 형태로 상태 변경을 구 현: (State, Action) -> new State그림 출처: https://speakerdeck.com/yuyakaido/droidkaigi-2019
  • 107. 그럼 side effect 처리는 대체 누가? → Middleware! 그림 출처: https://speakerdeck.com/yuyakaido/droidkaigi-2019
  • 109. Redux의 장단점 • 장점 • 상태 처리에서의 라이프 사이클의 영향을 어느 정도 배제할 수 있음
  • 110. Redux의 장단점 • 장점 • 상태 처리에서의 라이프 사이클의 영향을 어느 정도 배제할 수 있음 • 화면에서 back 버튼 누른 후에 뒤늦게 발생한 API 에러.. 같은 애매하고 난해한 상황도 효과적으로 대처 가능
  • 111. Redux의 장단점 • 장점 • 상태 처리에서의 라이프 사이클의 영향을 어느 정도 배제할 수 있음 • 화면에서 back 버튼 누른 후에 뒤늦게 발생한 API 에러.. 같은 애매하고 난해한 상황도 효과적으로 대처 가능 • 상태의 정의 부분, 저장 부분, 처리 부분이 완벽히 나눠져 있기 때문에 수정/확장이 극도로 편함
  • 112. Redux의 장단점 • 장점 • 상태 처리에서의 라이프 사이클의 영향을 어느 정도 배제할 수 있음 • 화면에서 back 버튼 누른 후에 뒤늦게 발생한 API 에러.. 같은 애매하고 난해한 상황도 효과적으로 대처 가능 • 상태의 정의 부분, 저장 부분, 처리 부분이 완벽히 나눠져 있기 때문에 수정/확장이 극도로 편함 • Functional한 구조의 특성상 유닛 테스트를 작성하는 것이 극도로 편리함
  • 113. Redux의 장단점 • 장점 • 상태 처리에서의 라이프 사이클의 영향을 어느 정도 배제할 수 있음 • 화면에서 back 버튼 누른 후에 뒤늦게 발생한 API 에러.. 같은 애매하고 난해한 상황도 효과적으로 대처 가능 • 상태의 정의 부분, 저장 부분, 처리 부분이 완벽히 나눠져 있기 때문에 수정/확장이 극도로 편함 • Functional한 구조의 특성상 유닛 테스트를 작성하는 것이 극도로 편리함 • Debugging의 신세계! 현재의 모든 전역적 상태를 확인할 수 있고, 상태 변수 값을 직접 수정해서 전체 상태를 바꿔볼 수도 있음
  • 114. Redux의 장단점 • 장점 • 상태 처리에서의 라이프 사이클의 영향을 어느 정도 배제할 수 있음 • 화면에서 back 버튼 누른 후에 뒤늦게 발생한 API 에러.. 같은 애매하고 난해한 상황도 효과적으로 대처 가능 • 상태의 정의 부분, 저장 부분, 처리 부분이 완벽히 나눠져 있기 때문에 수정/확장이 극도로 편함 • Functional한 구조의 특성상 유닛 테스트를 작성하는 것이 극도로 편리함 • Debugging의 신세계! 현재의 모든 전역적 상태를 확인할 수 있고, 상태 변수 값을 직접 수정해서 전체 상태를 바꿔볼 수도 있음 • 단점
  • 115. Redux의 장단점 • 장점 • 상태 처리에서의 라이프 사이클의 영향을 어느 정도 배제할 수 있음 • 화면에서 back 버튼 누른 후에 뒤늦게 발생한 API 에러.. 같은 애매하고 난해한 상황도 효과적으로 대처 가능 • 상태의 정의 부분, 저장 부분, 처리 부분이 완벽히 나눠져 있기 때문에 수정/확장이 극도로 편함 • Functional한 구조의 특성상 유닛 테스트를 작성하는 것이 극도로 편리함 • Debugging의 신세계! 현재의 모든 전역적 상태를 확인할 수 있고, 상태 변수 값을 직접 수정해서 전체 상태를 바꿔볼 수도 있음 • 단점 • 상당한 수준의 학습 비용이 소요
  • 116. Redux의 장단점 • 장점 • 상태 처리에서의 라이프 사이클의 영향을 어느 정도 배제할 수 있음 • 화면에서 back 버튼 누른 후에 뒤늦게 발생한 API 에러.. 같은 애매하고 난해한 상황도 효과적으로 대처 가능 • 상태의 정의 부분, 저장 부분, 처리 부분이 완벽히 나눠져 있기 때문에 수정/확장이 극도로 편함 • Functional한 구조의 특성상 유닛 테스트를 작성하는 것이 극도로 편리함 • Debugging의 신세계! 현재의 모든 전역적 상태를 확인할 수 있고, 상태 변수 값을 직접 수정해서 전체 상태를 바꿔볼 수도 있음 • 단점 • 상당한 수준의 학습 비용이 소요 • 코드량 증가, 특히 boiler plate 코드의 반복적 생산은 피하기 어려움
  • 117. Flux / Redux의 현재와 미래 • 현재
  • 118. Flux / Redux의 현재와 미래 • 현재 • ReKotlin, RxRedux이 있으나 현재로선 직접 구현을 추천
  • 119. Flux / Redux의 현재와 미래 • 현재 • ReKotlin, RxRedux이 있으나 현재로선 직접 구현을 추천 • State / Action의 접점을 View로 할 수도 있지만 ViewModel로도 가능
  • 120. Flux / Redux의 현재와 미래 • 현재 • ReKotlin, RxRedux이 있으나 현재로선 직접 구현을 추천 • State / Action의 접점을 View로 할 수도 있지만 ViewModel로도 가능 • 그리고 Flux의 경우는 Store를 ViewModel로 구현!
  • 121. Flux / Redux의 현재와 미래 • 현재 • ReKotlin, RxRedux이 있으나 현재로선 직접 구현을 추천 • State / Action의 접점을 View로 할 수도 있지만 ViewModel로도 가능 • 그리고 Flux의 경우는 Store를 ViewModel로 구현! • RxJava로 Store, 그리고 side effect를 처리하는 middleware를 구현 vs Coroutine + LiveData 조합
  • 122. Flux / Redux의 현재와 미래 • 현재 • ReKotlin, RxRedux이 있으나 현재로선 직접 구현을 추천 • State / Action의 접점을 View로 할 수도 있지만 ViewModel로도 가능 • 그리고 Flux의 경우는 Store를 ViewModel로 구현! • RxJava로 Store, 그리고 side effect를 처리하는 middleware를 구현 vs Coroutine + LiveData 조합 • 미래?
  • 123. Flux / Redux의 현재와 미래 • 현재 • ReKotlin, RxRedux이 있으나 현재로선 직접 구현을 추천 • State / Action의 접점을 View로 할 수도 있지만 ViewModel로도 가능 • 그리고 Flux의 경우는 Store를 ViewModel로 구현! • RxJava로 Store, 그리고 side effect를 처리하는 middleware를 구현 vs Coroutine + LiveData 조합 • 미래? • Rx를 굳이 쓰지 않아도 되는 use case가 대부분이고, coroutine 환경이 성숙/안정화 됨에 따라 급격히 coroutine으로 중심이 넘어갈 듯
  • 124. Flux / Redux의 현재와 미래 • 현재 • ReKotlin, RxRedux이 있으나 현재로선 직접 구현을 추천 • State / Action의 접점을 View로 할 수도 있지만 ViewModel로도 가능 • 그리고 Flux의 경우는 Store를 ViewModel로 구현! • RxJava로 Store, 그리고 side effect를 처리하는 middleware를 구현 vs Coroutine + LiveData 조합 • 미래? • Rx를 굳이 쓰지 않아도 되는 use case가 대부분이고, coroutine 환경이 성숙/안정화 됨에 따라 급격히 coroutine으로 중심이 넘어갈 듯 • 현재 주류인 Redux-Thunk middleware를 Redux-Saga가 대체할 것으로 예상
  • 125. Flux / Redux의 현재와 미래 • 현재 • ReKotlin, RxRedux이 있으나 현재로선 직접 구현을 추천 • State / Action의 접점을 View로 할 수도 있지만 ViewModel로도 가능 • 그리고 Flux의 경우는 Store를 ViewModel로 구현! • RxJava로 Store, 그리고 side effect를 처리하는 middleware를 구현 vs Coroutine + LiveData 조합 • 미래? • Rx를 굳이 쓰지 않아도 되는 use case가 대부분이고, coroutine 환경이 성숙/안정화 됨에 따라 급격히 coroutine으로 중심이 넘어갈 듯 • 현재 주류인 Redux-Thunk middleware를 Redux-Saga가 대체할 것으로 예상 • Coroutine과 완벽하게 매치 되는 async loop 구조
  • 126. Flux / Redux의 현재와 미래 • 현재 • ReKotlin, RxRedux이 있으나 현재로선 직접 구현을 추천 • State / Action의 접점을 View로 할 수도 있지만 ViewModel로도 가능 • 그리고 Flux의 경우는 Store를 ViewModel로 구현! • RxJava로 Store, 그리고 side effect를 처리하는 middleware를 구현 vs Coroutine + LiveData 조합 • 미래? • Rx를 굳이 쓰지 않아도 되는 use case가 대부분이고, coroutine 환경이 성숙/안정화 됨에 따라 급격히 coroutine으로 중심이 넘어갈 듯 • 현재 주류인 Redux-Thunk middleware를 Redux-Saga가 대체할 것으로 예상 • Coroutine과 완벽하게 매치 되는 async loop 구조 • 극도로 아름답고 깔끔한 테스트 코드 작성 가능
  • 127. Part III. 
 New Trends in 2019
  • 130. 1. Multi-module! • 여기서 잠시 질문 • internal class (inner class 아님)가 무엇인지 아시나요?
  • 131. 1. Multi-module! • 여기서 잠시 질문 • internal class (inner class 아님)가 무엇인지 아시나요? • private / protected / internal / public 중 internal과 public의 차이는?
  • 132. 1. Multi-module! • 여기서 잠시 질문 • internal class (inner class 아님)가 무엇인지 아시나요? • private / protected / internal / public 중 internal과 public의 차이는? • internal 식별자 -> 다른 module (package가 아님) 에서 보이지 않게 함
  • 133. 1. Multi-module! • 여기서 잠시 질문 • internal class (inner class 아님)가 무엇인지 아시나요? • private / protected / internal / public 중 internal과 public의 차이는? • internal 식별자 -> 다른 module (package가 아님) 에서 보이지 않게 함 • android gradle plugin 3.0.0부터 compile -> implementation으로 바뀐 이유 가 무엇인지 아시나요?
  • 134. 1. Multi-module! • 여기서 잠시 질문 • internal class (inner class 아님)가 무엇인지 아시나요? • private / protected / internal / public 중 internal과 public의 차이는? • internal 식별자 -> 다른 module (package가 아님) 에서 보이지 않게 함 • android gradle plugin 3.0.0부터 compile -> implementation으로 바뀐 이유 가 무엇인지 아시나요? • 멀티 모듈 지원 기능이 강화 되면서 추가된 개념
  • 135. 1. Multi-module! • 여기서 잠시 질문 • internal class (inner class 아님)가 무엇인지 아시나요? • private / protected / internal / public 중 internal과 public의 차이는? • internal 식별자 -> 다른 module (package가 아님) 에서 보이지 않게 함 • android gradle plugin 3.0.0부터 compile -> implementation으로 바뀐 이유 가 무엇인지 아시나요? • 멀티 모듈 지원 기능이 강화 되면서 추가된 개념 • 정확히는, compile == api 로 바뀜
  • 136. 참조 가능 • Compile (== api) 식별자 그림 출처: https://speakerdeck.com/sansanbuildersbox/multi-module-android-application
  • 137. 참조 가능 • Compile (== api) 식별자 • 특별히 지정하지 않아도 손자 모듈까지 참조 가능 그림 출처: https://speakerdeck.com/sansanbuildersbox/multi-module-android-application
  • 138. 참조 가능 • Compile (== api) 식별자 • 특별히 지정하지 않아도 손자 모듈까지 참조 가능 • 바꿔 얘기하면, module2가 변경이 되 면 app 모듈도 재컴파 일 해야함 그림 출처: https://speakerdeck.com/sansanbuildersbox/multi-module-android-application
  • 139. 참조 불가 • implementation 식별자 그림 출처: https://speakerdeck.com/sansanbuildersbox/multi-module-android-application
  • 140. 참조 불가 • implementation 식별자 • 명시적으로 지정하지 않 은 손자 모듈 참조 불가 그림 출처: https://speakerdeck.com/sansanbuildersbox/multi-module-android-application
  • 141. 참조 불가 • implementation 식별자 • 명시적으로 지정하지 않 은 손자 모듈 참조 불가 • 바꿔 얘기하면, module2가 변경이 되 어도 app 모듈은 컴파 일할 필요가 없음 그림 출처: https://speakerdeck.com/sansanbuildersbox/multi-module-android-application
  • 143. • 멀티 모듈은 왜 쓰는가?
  • 144. • 멀티 모듈은 왜 쓰는가? • 현실적인 이유: 빌드 속도
  • 145. • 멀티 모듈은 왜 쓰는가? • 현실적인 이유: 빌드 속도 • 풀 빌드: 36.4s → 30s, incremental build: 14.2s → 7s
  • 146. • 멀티 모듈은 왜 쓰는가? • 현실적인 이유: 빌드 속도 • 풀 빌드: 36.4s → 30s, incremental build: 14.2s → 7s • Ref: https://speakerdeck.com/sansanbuildersbox/multi-module-android- application
  • 147. • 멀티 모듈은 왜 쓰는가? • 현실적인 이유: 빌드 속도 • 풀 빌드: 36.4s → 30s, incremental build: 14.2s → 7s • Ref: https://speakerdeck.com/sansanbuildersbox/multi-module-android- application • incremental이야 그렇다쳐도 왜 풀빌드도 빠르지? 주된 이유는 annotation processing. kapt의 경우는 아직도 incremental processing을 지원하지 않음.
  • 148. • 멀티 모듈은 왜 쓰는가? • 현실적인 이유: 빌드 속도 • 풀 빌드: 36.4s → 30s, incremental build: 14.2s → 7s • Ref: https://speakerdeck.com/sansanbuildersbox/multi-module-android- application • incremental이야 그렇다쳐도 왜 풀빌드도 빠르지? 주된 이유는 annotation processing. kapt의 경우는 아직도 incremental processing을 지원하지 않음. • 그외 realm과 같이 byte code weaving을 하는 라이브러리를 별도 모듈로 빼는 것 만으로 30% 빌드 성능 향상
  • 149. • 멀티 모듈은 왜 쓰는가? • 현실적인 이유: 빌드 속도 • 풀 빌드: 36.4s → 30s, incremental build: 14.2s → 7s • Ref: https://speakerdeck.com/sansanbuildersbox/multi-module-android- application • incremental이야 그렇다쳐도 왜 풀빌드도 빠르지? 주된 이유는 annotation processing. kapt의 경우는 아직도 incremental processing을 지원하지 않음. • 그외 realm과 같이 byte code weaving을 하는 라이브러리를 별도 모듈로 빼는 것 만으로 30% 빌드 성능 향상 • 효율적인 분업 프로세스 가능: 모듈 별로 구현의 격리 / 테스트가 가능
  • 150. • 멀티 모듈은 왜 쓰는가? • 현실적인 이유: 빌드 속도 • 풀 빌드: 36.4s → 30s, incremental build: 14.2s → 7s • Ref: https://speakerdeck.com/sansanbuildersbox/multi-module-android- application • incremental이야 그렇다쳐도 왜 풀빌드도 빠르지? 주된 이유는 annotation processing. kapt의 경우는 아직도 incremental processing을 지원하지 않음. • 그외 realm과 같이 byte code weaving을 하는 라이브러리를 별도 모듈로 빼는 것 만으로 30% 빌드 성능 향상 • 효율적인 분업 프로세스 가능: 모듈 별로 구현의 격리 / 테스트가 가능 • 독립적인 설계를 촉진
  • 151. • 모듈은 어떻게 나누는가? - (1) Layer 별 수직 분리
  • 152. • 모듈은 어떻게 나누는가? - (1) Layer 별 수직 분리 • Presentation / Domain / Data Layer
  • 153. • 모듈은 어떻게 나누는가? - (1) Layer 별 수직 분리 • Presentation / Domain / Data Layer • 단, Application에서 DB를 생성해야 하기 때문에, Presentation -> Domain -> Data 형태의 배치는 불가능
  • 154. • 모듈은 어떻게 나누는가? - (1) Layer 별 수직 분리 • Presentation / Domain / Data Layer • 단, Application에서 DB를 생성해야 하기 때문에, Presentation -> Domain -> Data 형태의 배치는 불가능 • app은 DI를 정의, ui / data 모듈에 domain 모듈이 주입될 수 있도록 함
  • 155. • 모듈은 어떻게 나누는가? - (1) Layer 별 수직 분리 • Presentation / Domain / Data Layer • 단, Application에서 DB를 생성해야 하기 때문에, Presentation -> Domain -> Data 형태의 배치는 불가능 • app은 DI를 정의, ui / data 모듈에 domain 모듈이 주입될 수 있도록 함 그림 출처: https://speakerdeck.com/sansanbuildersbox/multi-module-android-application
  • 156. • 모듈은 어떻게 나누는가? - (2) 수평 분리
  • 157. • 모듈은 어떻게 나누는가? - (2) 수평 분리 • 화면별 / 기능별로 분리 → feature별 독립성 확보
  • 158. • 모듈은 어떻게 나누는가? - (2) 수평 분리 • 화면별 / 기능별로 분리 → feature별 독립성 확보 • 라이브러리 기준 분리: Realm 등 black magic 계의 기술이 사용된 부분은 극력 별도 모듈로 분리
  • 159. • 모듈은 어떻게 나누는가? - (2) 수평 분리 • 화면별 / 기능별로 분리 → feature별 독립성 확보 • 라이브러리 기준 분리: Realm 등 black magic 계의 기술이 사용된 부분은 극력 별도 모듈로 분리 • → 결과적으로 10~30 개 정도의 모듈로 앱이 구성됨 (주의: 중규모 이상의 팀의 경우)
  • 160. • 모듈은 어떻게 나누는가? - (2) 수평 분리 • 화면별 / 기능별로 분리 → feature별 독립성 확보 • 라이브러리 기준 분리: Realm 등 black magic 계의 기술이 사용된 부분은 극력 별도 모듈로 분리 • → 결과적으로 10~30 개 정도의 모듈로 앱이 구성됨 (주의: 중규모 이상의 팀의 경우) • 주의점: 상호 참조
  • 161. • 모듈은 어떻게 나누는가? - (2) 수평 분리 • 화면별 / 기능별로 분리 → feature별 독립성 확보 • 라이브러리 기준 분리: Realm 등 black magic 계의 기술이 사용된 부분은 극력 별도 모듈로 분리 • → 결과적으로 10~30 개 정도의 모듈로 앱이 구성됨 (주의: 중규모 이상의 팀의 경우) • 주의점: 상호 참조 • 안드로이드 모듈의 참조는 단방향만 허용하므로 양방향의 참조가 불가
  • 162. • 모듈은 어떻게 나누는가? - (2) 수평 분리 • 화면별 / 기능별로 분리 → feature별 독립성 확보 • 라이브러리 기준 분리: Realm 등 black magic 계의 기술이 사용된 부분은 극력 별도 모듈로 분리 • → 결과적으로 10~30 개 정도의 모듈로 앱이 구성됨 (주의: 중규모 이상의 팀의 경우) • 주의점: 상호 참조 • 안드로이드 모듈의 참조는 단방향만 허용하므로 양방향의 참조가 불가 • 두 개의 화면이 각자 서로를 시작할 수 있는 경우는, 각자의 intent를 가져야 하므로 분리가 불가능해짐
  • 163. • 모듈은 어떻게 나누는가? - (2) 수평 분리 • 화면별 / 기능별로 분리 → feature별 독립성 확보 • 라이브러리 기준 분리: Realm 등 black magic 계의 기술이 사용된 부분은 극력 별도 모듈로 분리 • → 결과적으로 10~30 개 정도의 모듈로 앱이 구성됨 (주의: 중규모 이상의 팀의 경우) • 주의점: 상호 참조 • 안드로이드 모듈의 참조는 단방향만 허용하므로 양방향의 참조가 불가 • 두 개의 화면이 각자 서로를 시작할 수 있는 경우는, 각자의 intent를 가져야 하므로 분리가 불가능해짐 • Intent 생성 인터페이스만을 갖고 구현은 최상위 모듈(:app)이 소유 → DI로 얻어오기
  • 164. • 모듈은 어떻게 나누는가? - (2) 수평 분리 • 화면별 / 기능별로 분리 → feature별 독립성 확보 • 라이브러리 기준 분리: Realm 등 black magic 계의 기술이 사용된 부분은 극력 별도 모듈로 분리 • → 결과적으로 10~30 개 정도의 모듈로 앱이 구성됨 (주의: 중규모 이상의 팀의 경우) • 주의점: 상호 참조 • 안드로이드 모듈의 참조는 단방향만 허용하므로 양방향의 참조가 불가 • 두 개의 화면이 각자 서로를 시작할 수 있는 경우는, 각자의 intent를 가져야 하므로 분리가 불가능해짐 • Intent 생성 인터페이스만을 갖고 구현은 최상위 모듈(:app)이 소유 → DI로 얻어오기 • 중앙집중식 navigation 클래스를 만들고 각 모듈은 인터페이스만 갖도록 구현 (DroidKaigi 2018 앱 참조)
  • 165. • 모듈은 어떻게 나누는가? - (2) 수평 분리 • 화면별 / 기능별로 분리 → feature별 독립성 확보 • 라이브러리 기준 분리: Realm 등 black magic 계의 기술이 사용된 부분은 극력 별도 모듈로 분리 • → 결과적으로 10~30 개 정도의 모듈로 앱이 구성됨 (주의: 중규모 이상의 팀의 경우) • 주의점: 상호 참조 • 안드로이드 모듈의 참조는 단방향만 허용하므로 양방향의 참조가 불가 • 두 개의 화면이 각자 서로를 시작할 수 있는 경우는, 각자의 intent를 가져야 하므로 분리가 불가능해짐 • Intent 생성 인터페이스만을 갖고 구현은 최상위 모듈(:app)이 소유 → DI로 얻어오기 • 중앙집중식 navigation 클래스를 만들고 각 모듈은 인터페이스만 갖도록 구현 (DroidKaigi 2018 앱 참조) • Tip: Dagger를 이용한 주입 + 사용자 파라미터가 동시에 필요한 경우라면, AssistedInjection 을 사용
  • 166. • Dependency Inversion Principle: 이제까지 Android에서 중요시 된 적 없던 설계 원칙
  • 167. • Dependency Inversion Principle: 이제까지 Android에서 중요시 된 적 없던 설계 원칙 • 상위 모듈은 하위 모듈에 의존성이 있어서는 안 된다 & 상위 모듈 하위 모듈 모두 인터페이스에만 의존한다
  • 168. • Dependency Inversion Principle: 이제까지 Android에서 중요시 된 적 없던 설계 원칙 • 상위 모듈은 하위 모듈에 의존성이 있어서는 안 된다 & 상위 모듈 하위 모듈 모두 인터페이스에만 의존한다 • 의존성이 생기는 클래스가 volatile 하다면 인터페이스로만 참조가 일어나야 한다
  • 169. • Dependency Inversion Principle: 이제까지 Android에서 중요시 된 적 없던 설계 원칙 • 상위 모듈은 하위 모듈에 의존성이 있어서는 안 된다 & 상위 모듈 하위 모듈 모두 인터페이스에만 의존한다 • 의존성이 생기는 클래스가 volatile 하다면 인터페이스로만 참조가 일어나야 한다 • A 객체가 B 객체의 레퍼런스를 직접 참조하는 대신, interface를 참조하여 구현 의존성을 끊음
  • 170. • Dependency Inversion Principle: 이제까지 Android에서 중요시 된 적 없던 설계 원칙 • 상위 모듈은 하위 모듈에 의존성이 있어서는 안 된다 & 상위 모듈 하위 모듈 모두 인터페이스에만 의존한다 • 의존성이 생기는 클래스가 volatile 하다면 인터페이스로만 참조가 일어나야 한다 • A 객체가 B 객체의 레퍼런스를 직접 참조하는 대신, interface를 참조하여 구현 의존성을 끊음 • B가 변경되어도 A는 컴파일할 필요가 없음
  • 171. • Dependency Inversion Principle: 이제까지 Android에서 중요시 된 적 없던 설계 원칙 • 상위 모듈은 하위 모듈에 의존성이 있어서는 안 된다 & 상위 모듈 하위 모듈 모두 인터페이스에만 의존한다 • 의존성이 생기는 클래스가 volatile 하다면 인터페이스로만 참조가 일어나야 한다 • A 객체가 B 객체의 레퍼런스를 직접 참조하는 대신, interface를 참조하여 구현 의존성을 끊음 • B가 변경되어도 A는 컴파일할 필요가 없음 • 동일한 인터페이스를 갖지만 전혀 다른 로직으로 구현된 제3의 모듈로 쉽게 변경 가능 
 → Dependency Injection의 도움을 받으면 각 모듈 별 설정을 일관된 방식으로 손쉽게 수정 가능
  • 172. DIP + DI 도입전
  • 173. DIP + DI 도입전 그림 출처: https://speakerdeck.com/sansanbuildersbox/multi-module-android-application
  • 174. DIP + DI 도입후
  • 175. DIP + DI 도입후 그림 출처: https://speakerdeck.com/sansanbuildersbox/multi-module-android-application
  • 178. 사실 의존성 주입에 대해 할 말이 많지만.. 떠오르는 꿈나무에 양보하겠습니다.
  • 179. 2. RxJava vs Coroutine vs LiveData • 왜 필요한가?
  • 180. 2. RxJava vs Coroutine vs LiveData • 왜 필요한가? • Reactive: 비동기적인 처리를 imperative하게 처리할 수 있게 해줌
  • 181. 2. RxJava vs Coroutine vs LiveData • 왜 필요한가? • Reactive: 비동기적인 처리를 imperative하게 처리할 수 있게 해줌 • RxJava
  • 182. 2. RxJava vs Coroutine vs LiveData • 왜 필요한가? • Reactive: 비동기적인 처리를 imperative하게 처리할 수 있게 해줌 • RxJava • 여전히, Android에서의 비동기 처리 위한 현존하는 가장 강력하고 편리한 수단
  • 183. 2. RxJava vs Coroutine vs LiveData • 왜 필요한가? • Reactive: 비동기적인 처리를 imperative하게 처리할 수 있게 해줌 • RxJava • 여전히, Android에서의 비동기 처리 위한 현존하는 가장 강력하고 편리한 수단 • Android에서의 복잡한 상태처리를 직관적으로 구현 가능
  • 184. 2. RxJava vs Coroutine vs LiveData • 왜 필요한가? • Reactive: 비동기적인 처리를 imperative하게 처리할 수 있게 해줌 • RxJava • 여전히, Android에서의 비동기 처리 위한 현존하는 가장 강력하고 편리한 수단 • Android에서의 복잡한 상태처리를 직관적으로 구현 가능 • View - ViewModel과의 가교를 위한 black magic 스러운 다양한 구현도 가능
  • 185. 2. RxJava vs Coroutine vs LiveData • 왜 필요한가? • Reactive: 비동기적인 처리를 imperative하게 처리할 수 있게 해줌 • RxJava • 여전히, Android에서의 비동기 처리 위한 현존하는 가장 강력하고 편리한 수단 • Android에서의 복잡한 상태처리를 직관적으로 구현 가능 • View - ViewModel과의 가교를 위한 black magic 스러운 다양한 구현도 가능 • eg. 상황에 따라 순차적으로 실행해야 하는 애니메이션들을 각각 Completable로 정의한 후, Combine해서 실행
  • 186. • 이런 것도 가능! • ViewGroup의 중점이 바뀔 때마다 ViewModel이 통지를 받을 수 있도록 View 측에서 호 출할 수 있는 헬퍼 함수 fun createVerticalCenterPublisher(layout: View): Observable<Int> = Observable.create<Int> { emitter -> emitter.onNext(layout.bottom - layout.top) val callback = View.OnLayoutChangeListener { _, _, top, _, bottom, _, _, _, _ -> emitter.onNext(bottom - top) } layout.addOnLayoutChangeListener(callback) emitter.setCancellable { layout.removeOnLayoutChangeListener(callback) } }.subscribeOn(AndroidSchedulers.mainThread()) .throttleLatest(100, TimeUnit.MILLISECONDS, true) .map { it / 2 }
  • 187. 더 자세한 건… 헐!? 그 명강의를 안 들었다고요?! 😱 YouTube 다시보기를 강추드립니다.
  • 189. Coroutine • 뭐가 좋은가? • 성능 이점: coroutine is light-weight threads
  • 190. Coroutine • 뭐가 좋은가? • 성능 이점: coroutine is light-weight threads • Rx보다 덜 어렵다
  • 191. Coroutine • 뭐가 좋은가? • 성능 이점: coroutine is light-weight threads • Rx보다 덜 어렵다 • 보다 functional한 구현 - Saga 패턴 같은 형태의 구현에 탁월
  • 192. Coroutine • 뭐가 좋은가? • 성능 이점: coroutine is light-weight threads • Rx보다 덜 어렵다 • 보다 functional한 구현 - Saga 패턴 같은 형태의 구현에 탁월 • 이제는 안정기에 접어들었음 - Kotlin 1.3과 함께 정식 버전이 되었고, 최신 사양에 맞춘 다양한 지 원이 예정되어 있음.
  • 193. Coroutine • 뭐가 좋은가? • 성능 이점: coroutine is light-weight threads • Rx보다 덜 어렵다 • 보다 functional한 구현 - Saga 패턴 같은 형태의 구현에 탁월 • 이제는 안정기에 접어들었음 - Kotlin 1.3과 함께 정식 버전이 되었고, 최신 사양에 맞춘 다양한 지 원이 예정되어 있음. • lifecycle-viewModel-ktx 2.1.0 (현재 alpha03)부터 lifecycle-aware한 Coroutine Scope 인 viewmodelScope를 공식 지원
  • 194. Coroutine • 뭐가 좋은가? • 성능 이점: coroutine is light-weight threads • Rx보다 덜 어렵다 • 보다 functional한 구현 - Saga 패턴 같은 형태의 구현에 탁월 • 이제는 안정기에 접어들었음 - Kotlin 1.3과 함께 정식 버전이 되었고, 최신 사양에 맞춘 다양한 지 원이 예정되어 있음. • lifecycle-viewModel-ktx 2.1.0 (현재 alpha03)부터 lifecycle-aware한 Coroutine Scope 인 viewmodelScope를 공식 지원 • retrofit 차기 버전에서 “suspend fun”을 형태로 api interface 정의 (현재 “Deferred”를 리턴 하는 형태)
  • 196. 더 자세한 건… 지금이라도 늦지 않았습니다. 옆 강의실로 고고~ ☺
  • 197. LiveData • LiveData에 대해 논하기 전에..
  • 198. LiveData • LiveData에 대해 논하기 전에.. • View - ViewModel (or Presenter) 간의 이벤트 통지에 있어서 가장 이상적인 이 벤트 통지 전달자는 어떤 특징을 가져야할까?
  • 199. LiveData • LiveData에 대해 논하기 전에.. • View - ViewModel (or Presenter) 간의 이벤트 통지에 있어서 가장 이상적인 이 벤트 통지 전달자는 어떤 특징을 가져야할까? • 이벤트 전달이 UI 스레드에서 이뤄져야 한다
  • 200. LiveData • LiveData에 대해 논하기 전에.. • View - ViewModel (or Presenter) 간의 이벤트 통지에 있어서 가장 이상적인 이 벤트 통지 전달자는 어떤 특징을 가져야할까? • 이벤트 전달이 UI 스레드에서 이뤄져야 한다 • Side Effect의 공유가 가능해야한다. -> 쉬운 말로 하면 하나의 이벤트를 여러 이 벤트 핸들러가 공유할 수 있어야 한다
  • 201. LiveData • LiveData에 대해 논하기 전에.. • View - ViewModel (or Presenter) 간의 이벤트 통지에 있어서 가장 이상적인 이 벤트 통지 전달자는 어떤 특징을 가져야할까? • 이벤트 전달이 UI 스레드에서 이뤄져야 한다 • Side Effect의 공유가 가능해야한다. -> 쉬운 말로 하면 하나의 이벤트를 여러 이 벤트 핸들러가 공유할 수 있어야 한다 • 에러를 skip 할 수 있어야 한다
  • 202. LiveData • LiveData에 대해 논하기 전에.. • View - ViewModel (or Presenter) 간의 이벤트 통지에 있어서 가장 이상적인 이 벤트 통지 전달자는 어떤 특징을 가져야할까? • 이벤트 전달이 UI 스레드에서 이뤄져야 한다 • Side Effect의 공유가 가능해야한다. -> 쉬운 말로 하면 하나의 이벤트를 여러 이 벤트 핸들러가 공유할 수 있어야 한다 • 에러를 skip 할 수 있어야 한다 • → RxSwift의 경우, Signal/Driver가 이에 해당
  • 204. • LiveData의 특징 • 기본적으로 UI thread에서 동작
  • 205. • LiveData의 특징 • 기본적으로 UI thread에서 동작 • Side Effect(값의 변화, 이벤트)의 공유가 가능
  • 206. • LiveData의 특징 • 기본적으로 UI thread에서 동작 • Side Effect(값의 변화, 이벤트)의 공유가 가능 • Configuration 변경 시 마지막 발생한 이벤트를 replay 해줌 (단, 의도치 않은 버그가 생길 여지 있음)
  • 207. • LiveData의 특징 • 기본적으로 UI thread에서 동작 • Side Effect(값의 변화, 이벤트)의 공유가 가능 • Configuration 변경 시 마지막 발생한 이벤트를 replay 해줌 (단, 의도치 않은 버그가 생길 여지 있음) • transformation을 통해 RxJava의 combine과 비슷하게 구현 가능
  • 208. • LiveData의 특징 • 기본적으로 UI thread에서 동작 • Side Effect(값의 변화, 이벤트)의 공유가 가능 • Configuration 변경 시 마지막 발생한 이벤트를 replay 해줌 (단, 의도치 않은 버그가 생길 여지 있음) • transformation을 통해 RxJava의 combine과 비슷하게 구현 가능 • → RxSwift의 Driver와 유사한 개념 + LifeCycle-awareness
  • 209. • LiveData의 특징 • 기본적으로 UI thread에서 동작 • Side Effect(값의 변화, 이벤트)의 공유가 가능 • Configuration 변경 시 마지막 발생한 이벤트를 replay 해줌 (단, 의도치 않은 버그가 생길 여지 있음) • transformation을 통해 RxJava의 combine과 비슷하게 구현 가능 • → RxSwift의 Driver와 유사한 개념 + LifeCycle-awareness • LiveData는 언제 쓰는가?
  • 210. • LiveData의 특징 • 기본적으로 UI thread에서 동작 • Side Effect(값의 변화, 이벤트)의 공유가 가능 • Configuration 변경 시 마지막 발생한 이벤트를 replay 해줌 (단, 의도치 않은 버그가 생길 여지 있음) • transformation을 통해 RxJava의 combine과 비슷하게 구현 가능 • → RxSwift의 Driver와 유사한 개념 + LifeCycle-awareness • LiveData는 언제 쓰는가? • Rx의 대체재가 아닌 보완재
  • 211. • LiveData의 특징 • 기본적으로 UI thread에서 동작 • Side Effect(값의 변화, 이벤트)의 공유가 가능 • Configuration 변경 시 마지막 발생한 이벤트를 replay 해줌 (단, 의도치 않은 버그가 생길 여지 있음) • transformation을 통해 RxJava의 combine과 비슷하게 구현 가능 • → RxSwift의 Driver와 유사한 개념 + LifeCycle-awareness • LiveData는 언제 쓰는가? • Rx의 대체재가 아닌 보완재 • DataBinding 용도로 ObservableField보다 적합할 수도 있으나.. 있으나.. ;;;
  • 212. 더 자세한 건… 개인적으로는 large-scale app이라면 LiveData를 일부 소 극적으로 쓰고, RxBinding을 적극적으로 사용합니다.
  • 213. Part IV. 
 Best Examples
  • 214. 선정 조건 • 앱 규모: Toy project가 아니고 실제 Play Store에 올라온 앱인가 • 설계: Clean Architecture 등이 잘 적용되어 있는가 • 테스트: Unit Test가 요소요소 잘 구현되어 있는가 • 코드 품질: 내 프로젝트에도 갖다 쓸만한 표현이 많은가
  • 215. Google IO 2018 • https://github.com/google/iosched • Clean Architecture - Domain layer의 UseCase 구현 및 테스트 • LiveData 사용의 진수: RxJava 아니면 안 될 것 같은 기능들까지도 몽땅 MediatorLiveData로 구현! • 주의할 점: LiveData를 실제로 저렇게 쓰는 것은 극력 비추천 • 기타 아키텍처 외적으로 세부 코드 구현에 참고할 점이 매우 많음
  • 216. DroidKaigi 2018 • https://github.com/DroidKaigi/conference-app-2018 • 가장 모범적인 MVVM 구조 • 가장 훌륭하고 깔끔한 Dagger 정의 • Domain - Data 레이어를 특별히 나누지 않고 Repository 패턴으로 구현 • NavigationController - 매우 훌륭한 coordination 대안 • gradle kts
  • 217. DroidKaigi 2019 • https://github.com/DroidKaigi/conference-app-2019 • 멀티 모듈 구현 • + iOS도 지원 • Flux 구조: Store를 ViewModel로 구현 • Dagger 확장: AssistInjection! • 최신 UI 구현! - Custom LayoutManager의 좋은 예를 볼 수 있다!
  • 218. I’ll be back! • DroidKnights 2020 안드로이드 아키텍처 세번째 시리즈로 돌아옵니다. 
 내용은 아마도.. • Coroutine + Arrow로 구현한 functional한 Redux 구조 심층 분석 • 대규모 Multi-module 프로젝트 구축 • 기타 등등 • (개점휴업 중이던) 블로그 재개합니다! - 4/20부터 • 실제 프로젝트에서 의미있는 Test-Driven Development • Dagger 2 Dependency Injection 구현 전략 총정리 강사룡 Email: justfaceit@gmail.com Blog: https://medium.com/@justfaceit Slide: https://slideshare.net/saryongkang