내부에서 다양한 멤버 or 전역변수들을 사용하고 있다. - 한 화면이 담당하고 있는 기능, 위젯이 많다. - 하나의 함수에 너무 많은 역할이 존재한다. - 멤버 or 전역변수를 사용할 수록 Side Effect 가 발생할 확률이 높다. - 존재하는 기능, 위젯만큼 복잡도가 높아진다. 👇
멤버 or 전역변수들을 사용하고 있다. - 한 화면이 담당하고 있는 기능, 위젯이 많다. - 하나의 함수에 너무 많은 역할이 존재한다. - 멤버 or 전역변수를 사용할 수록 Side Effect 가 발생할 확률이 높다. - 존재하는 기능, 위젯만큼 복잡도가 높아진다. Pain point 👇 High Complexity
멤버 or 전역변수들을 사용하고 있다. - 한 화면이 담당하고 있는 기능, 위젯이 많다. - 하나의 함수에 너무 많은 역할이 존재한다. - 멤버 or 전역변수를 사용할 수록 Side Effect 가 발생할 확률이 높다. - 존재하는 기능, 위젯만큼 복잡도가 높아진다. Pain point 👇 High Complexity Row Maintainability =
멤버 or 전역변수들을 사용하고 있다. - 한 화면이 담당하고 있는 기능, 위젯이 많다. - 하나의 함수에 너무 많은 역할이 존재한다. - 멤버 or 전역변수를 사용할 수록 Side Effect 가 발생할 확률이 높다. - 존재하는 기능, 위젯만큼 복잡도가 높아진다. Pain point 👇 Complexity = State
멤버 or 전역변수들을 사용하고 있다. - 한 화면이 담당하고 있는 기능, 위젯이 많다. - 하나의 함수에 너무 많은 역할이 존재한다. - 멤버 or 전역변수를 사용할 수록 Side Effect 가 발생할 확률이 높다. - 존재하는 기능, 위젯만큼 복잡도가 높아진다. Pain point 👇 Complexity Management = State Management Maintainability ↕
if (taskId != null && isDataLoading) { populateTask() } } private val taskId: String? override var isDataLoading: Boolean taskId는 immutable하기 때문에 Side Effect를 발생시키지 않는다. 하지만 가독성을 해칠 수 있다.
if (taskId != null && isDataLoading) { populateTask() } } private val taskId: String? override var isDataLoading: Boolean taskId는 immutable하기 때문에 Side Effect를 발생시키지 않는다. 하지만 가독성을 해칠 수 있다. isDataLoading은 함수 스코프 밖에서 변경될 수 있음으로 Side Effect를 만든다.
if (taskId != null && isDataLoading) { populateTask() } } private val taskId: String? override var isDataLoading: Boolean taskId는 immutable하기 때문에 Side Effect를 발생시키지 않는다. 하지만 가독성을 해칠 수 있다. isDataLoading은 함수 스코프 밖에서 변경될 수 있음으로 Side Effect를 만든다. 그럼으로 start()는 참조투명하지 않다.
(taskId == null) { throw RuntimeException("populateTask() was called but task is new.") } isDataLoading = true tasksRepository.getTask(taskId, this) } RuntimeException을 throw 한다
(taskId == null) { throw RuntimeException("populateTask() was called but task is new.") } isDataLoading = true tasksRepository.getTask(taskId, this) } RuntimeException을 throw 한다 isDataLoading 을 true 로 변경한다.
(taskId == null) { throw RuntimeException("populateTask() was called but task is new.") } isDataLoading = true tasksRepository.getTask(taskId, this) } RuntimeException을 throw 한다 Repository를 통해 Task를 가져온다. isDataLoading 을 true 로 변경한다.
if (addTaskView.isActive) { addTaskView.setTitle(task.title) addTaskView.setDescription(task.description) } isDataLoading = false } addTaskView.isActive 일 때 View를 업데이트 한다.
if (addTaskView.isActive) { addTaskView.setTitle(task.title) addTaskView.setDescription(task.description) } isDataLoading = false } addTaskView.isActive 일 때 View를 업데이트 한다. isDataLoading 을 false 로 변경한다.
null && isDataLoading) { populateTask() } } val taskIdIsExist = taskId.filter { it.isNotEmpty() } val isEditTask = Observables.combineLatest( dataLoading, taskIdIsExist ).filter { (isDataLoading, _) -> isDataLoading.not() } .distinctUntilChanged() .map { (_, taskId) -> taskId } .share() taskId 값이 빈값이 아닐 때 흐르는 스트림을 생성. 위의 스트림과 dataLoading 을 조합하고 filter Operator를 통해 if (taskId != null && isDataLoading) 와 같게 동작하는 스트림을 생성
null && isDataLoading) { populateTask() } } val taskIdIsExist = taskId.filter { it.isNotEmpty() } val isEditTask = Observables.combineLatest( dataLoading, taskIdIsExist ).filter { (isDataLoading, _) -> isDataLoading.not() } .distinctUntilChanged() .map { (_, taskId) -> taskId } .share() taskId 값이 빈값이 아닐 때 흐르는 스트림을 생성. 위의 스트림과 dataLoading 을 조합하고 filter Operator를 통해 if (taskId != null && isDataLoading) 와 같게 동작하는 스트림을 생성 모든 스트림은 서로 합성 될 수 있으며 또한 분해 될 수 있다.
null) { throw RuntimeException(“populateTask()….”) } isDataLoading = true tasksRepository.getTask(taskId, this) } isEditTask는 이미 앞에서 taskId == null 에 대한 검사를 완료한 스트림이다. isEditTask
{ addTaskView.setTitle(task.title) addTaskView.setDescription(task.description) } isDataLoading = false } val task = getTask.ofType(Success::class.java) .map { result -> result.data as Task } addTaskView.isActive 대신 Success 조건이 추가 됨
분해와 합성에 용이하다. - 중복코드를 최소화 할 수 있다. - 다른 코드에 영향을 덜 주면서 개선, 새로운 기능을 추가 할 수 있다. - Side Effect를 최소화하여 개발이 가능하다. - 모든 상태를 Stream으로 관리 할 수 있다. - operator function은 참조 투명하다. - Rx의 강력한 Operator 들로 인해 가독성이 좋다.
분해와 합성에 용이하다. - 중복코드를 최소화 할 수 있다. - 다른 코드에 영향을 덜 주면서 개선, 새로운 기능을 추가 할 수 있다. - Side Effect를 최소화하여 개발이 가능하다. - 모든 상태를 Stream으로 관리 할 수 있다. - operator function은 참조 투명하다. - Rx의 강력한 Operator 들로 인해 가독성이 좋다. 유지보수성이 높은 코드를 작성할 수 있다.
비용이 존재한다. - 충분히 익숙해지기 전 작성하는 코드는 오히려 가독성이 훨씬 떨어진다. - Stream은 참조 투명하지 않다. - 생명주기(Disposable), 쓰레드 관리 등. - 언어의 특성상 Immutable을 잘 관리해야 한다. - 복잡한 상황에서 발생하는 여러 예외 케이스에 대하여 컨벤션이 잘 만들어져있어야 한다.
비용이 존재한다. - 충분히 익숙해지기 전 작성하는 코드는 오히려 가독성이 훨씬 떨어진다. - Stream은 참조 투명하지 않다. - 생명주기(Disposable), 쓰레드 관리 등. - 언어의 특성상 Immutable을 잘 관리해야 한다. - 복잡한 상황에서 발생하는 여러 예외 케이스에 대하여 컨벤션이 잘 만들어져있어야 한다. 높은 수준을 요구하지만 그 만큼의 가치가 있다.