SlideShare a Scribd company logo
1 of 75
Download to read offline
KOTLINIFY YOUR PROJECT!
OR NOYMAN, CITI
AGENDA
KOTLIN ENABLES FUNCTION ORIENTED PROGRAMMING STYLE
▸ High order functions
▸ Functions as first-class citizens
▸ Type inference
▸ Extension functions
▸ Operator overloading
▸ Collection API (map, flatMap, reduce)
▸ Algebric data types (sealed classes)
AGENDA
WHY FUNCTIONAL?
▸ Referential transparency
▸ Purity
▸ Deferred computation (lazy evaluation)
▸ Higher-Level abstractions
RECURSIONS
THE ITERATIVE WAY
fun Context?.findActivity(): Activity? {
var context = this
while (context is ContextWrapper) {
if (context is Activity) {
return context
}
context = context.baseContext
}
return null
}
RECURSIONS
THE RECURSIVE WAY
fun Context?.findActivity(): Activity? =
when (this) {
is Activity -> this
is ContextWrapper -> this.baseContext.findActivity()
else -> null
}
RECURSIONS
THE (TAIL)RECURSIVE WAY
tailrec fun Context?.findActivity(): Activity? =
when (this) {
is Activity -> this
is ContextWrapper -> this.baseContext.findActivity()
else -> null
}
RECURSIONS
THE (TAIL)RECURSIVE WAY
@Nullable
public static final Activity findActivity(@Nullable Context $receiver) {
while(true) {
Activity var10000;
if($receiver instanceof Activity) {
var10000 = (Activity)$receiver;
} else {
if($receiver instanceof ContextWrapper) {
$receiver = ((ContextWrapper)$receiver).getBaseContext();
continue;
}
var10000 = null;
}
return var10000;
}
}
RECURSIONS
FALL-THROUGH-STRUCTURE
PHASE1
PHASE2
PHASE3
PHASE4
VERIFY1
VERIFY2
VERIFY3
VERIFY4
RECURSIONS
FALL-THROUGH-SWITCH
enum Verification {
NO_VERIFICATION,
VERIFY_PHASE_1,
VERIFY_PHASE_2,
VERIFY_PHASE_3,
VERIFY_PHASE_4
}
PHASE1
PHASE2
PHASE3
PHASE4
VERIFY1
VERIFY2
VERIFY3
VERIFY4
RECURSIONS
FALL-THROUGH-SWITCH
void verify(TestDriver driver) {
switch (verification) {
case VERIFY_PHASE_4:
verifyPhase4(driver);
case VERIFY_PHASE_3:
verifyPhase3(driver);
case VERIFY_PHASE_2:
verifyPhase2(driver);
case VERIFY_PHASE_1:
verifyPhase1(driver);
case NO_VERIFICATION:
}
}
PHASE1
PHASE2
PHASE3
PHASE4
VERIFY1
VERIFY2
VERIFY3
VERIFY4
RECURSIONS
FALL-THROUGH-WHEN?
fun verify(driver: TestDriver) =
when (verification) {
NO_VERIFICATION -> Unit
VERIFY_PHASE_1 -> verifyPhase1(driver)
VERIFY_PHASE_2 -> {
verifyPhase1(driver)
verifyPhase2(driver)
}
VERIFY_PHASE_3 -> {
verifyPhase1(driver)
verifyPhase2(driver)
verifyPhase3(driver)
}
VERIFY_PHASE_4 -> {
verifyPhase1(driver)
verifyPhase2(driver)
verifyPhase3(driver)
verifyPhase4(driver)
}
}
PHASE1
PHASE2
PHASE3
PHASE4
VERIFY1
VERIFY2
VERIFY3
VERIFY4
RECURSIONS
FALL-THROUGH-LIKE-WHEN
inline fun <reified T : Enum<T>> T.prev(): T {
val values = enumValues<T>()
val prevOrdinal = (ordinal - 1) % values.size
return values[prevOrdinal]
}
enum class Verification { NO_VERIFICATION,
VERIFY_PHASE_1,
VERIFY_PHASE_2,
VERIFY_PHASE_3,
VERIFY_PHASE_4 }
PHASE1
PHASE2
PHASE3
PHASE4
VERIFY1
VERIFY2
VERIFY3
VERIFY4
RECURSIONS
FALL-THROUGH-LIKE-WHEN
inline fun <reified T : Enum<T>> T.prev(): T {
val values = enumValues<T>()
val prevOrdinal = (ordinal - 1) % values.size
return values[prevOrdinal]
}
enum class Verification { NO_VERIFICATION,
VERIFY_PHASE_1,
VERIFY_PHASE_2,
VERIFY_PHASE_3,
VERIFY_PHASE_4 }
PHASE1
PHASE2
PHASE3
PHASE4
VERIFY1
VERIFY2
VERIFY3
VERIFY4
RECURSIONS
FALL-THROUGH-LIKE-WHEN
inline fun <reified T : Enum<T>> T.prev(): T {
val values = enumValues<T>()
val prevOrdinal = (ordinal - 1) % values.size
return values[prevOrdinal]
}
enum class Verification { NO_VERIFICATION,
VERIFY_PHASE_1,
VERIFY_PHASE_2,
VERIFY_PHASE_3,
VERIFY_PHASE_4 }
PHASE1
PHASE2
PHASE3
PHASE4
VERIFY1
VERIFY2
VERIFY3
VERIFY4
RECURSIONS
FALL-THROUGH-WHEN?
fun verify(driver: TestDriver) =
when (verification) {
NO_VERIFICATION -> Unit
VERIFY_PHASE_1 -> verifyPhase1(driver)
VERIFY_PHASE_2 -> {
verifyPhase1(driver)
verifyPhase2(driver)
}
VERIFY_PHASE_3 -> {
verifyPhase1(driver)
verifyPhase2(driver)
verifyPhase3(driver)
}
VERIFY_PHASE_4 -> {
verifyPhase1(driver)
verifyPhase2(driver)
verifyPhase3(driver)
verifyPhase4(driver)
}
}
PHASE1
PHASE2
PHASE3
PHASE4
VERIFY1
VERIFY2
VERIFY3
VERIFY4
RECURSIONS
FALL-THROUGH-LIKE-WHEN
fun verify(driver: TestDriver) {
tailrec fun verify(verification: Verification) {
when (verification) {
NO_VERIFICATION -> return
VERIFY_PHASE_1 -> verifyPhase1(driver)
VERIFY_PHASE_2 -> verifyPhase2(driver)
VERIFY_PHASE_3 -> verifyPhase3(driver)
VERIFY_PHASE_4 -> verifyPhase4(driver)
}
verify(verification.prev())
}
verify(verification)
}
PHASE1
PHASE2
PHASE3
PHASE4
VERIFY1
VERIFY2
VERIFY3
VERIFY4
RECURSIONS
FALL-THROUGH-LIKE-WHEN
fun verify(driver: TestDriver) {
tailrec fun verify(verification: Verification) {
when (verification) {
NO_VERIFICATION -> return
VERIFY_PHASE_1 -> verifyPhase1(driver)
VERIFY_PHASE_2 -> verifyPhase2(driver)
VERIFY_PHASE_3 -> verifyPhase3(driver)
VERIFY_PHASE_4 -> verifyPhase4(driver)
}
verify(verification.prev())
}
verify(verification)
}
PHASE1
PHASE2
PHASE3
PHASE4
VERIFY1
VERIFY2
VERIFY3
VERIFY4
RECURSIONS
FALL-THROUGH-LIKE-WHEN
fun verify(driver: TestDriver) {
tailrec fun verify(verification: Verification) {
when (verification) {
NO_VERIFICATION -> return
VERIFY_PHASE_1 -> verifyPhase1(driver)
VERIFY_PHASE_2 -> verifyPhase2(driver)
VERIFY_PHASE_3 -> verifyPhase3(driver)
VERIFY_PHASE_4 -> verifyPhase4(driver)
}
verify(verification.prev())
}
verify(verification)
}
PHASE1
PHASE2
PHASE3
PHASE4
VERIFY1
VERIFY2
VERIFY3
VERIFY4
RECURSIONS
FALL-THROUGH-LIKE-WHEN
fun verify(driver: TestDriver) {
tailrec fun verify(verification: Verification) {
when (verification) {
NO_VERIFICATION -> return
VERIFY_PHASE_1 -> verifyPhase1(driver)
VERIFY_PHASE_2 -> verifyPhase2(driver)
VERIFY_PHASE_3 -> verifyPhase3(driver)
VERIFY_PHASE_4 -> verifyPhase4(driver)
}
verify(verification.prev())
}
verify(verification)
}
PHASE1
PHASE2
PHASE3
PHASE4
VERIFY1
VERIFY2
VERIFY3
VERIFY4
RECURSIONS
FALL-THROUGH-LIKE-WHEN
fun verify(driver: TestDriver) {
tailrec fun verify(verification: Verification) {
when (verification) {
NO_VERIFICATION -> return
VERIFY_PHASE_1 -> verifyPhase1(driver)
VERIFY_PHASE_2 -> verifyPhase2(driver)
VERIFY_PHASE_3 -> verifyPhase3(driver)
VERIFY_PHASE_4 -> verifyPhase4(driver)
}
verify(verification.prev())
}
verify(verification)
}
PHASE1
PHASE2
PHASE3
PHASE4
VERIFY1
VERIFY2
VERIFY3
VERIFY4
RECURSIONS
DEFERRED RECURSION (RECURSIVE FLATMAP)
▸ see: https://goo.gl/tuDwFn
MAKE RX CLEARER
COMPLEX ASYNC FLOW
▸ Parallelise as much as possible
▸ Respect dependencies
ASYNC1
ASYNC2
ASYNC3 ASYNC4
ASYNC5
ASYNC6
ASYNC7
MAKE RX CLEARER
COMPLEX ASYNC FLOW
fun async1(): Completable { ... }
fun async2(): Completable { ... }
fun async3(): Completable { ... }
fun async4(): Completable { ... }
fun async5(): Completable { ... }
fun async6(): Completable { ... }
fun async7(): Completable { ... }
ASYNC1
ASYNC2
ASYNC3 ASYNC4
ASYNC5
ASYNC6
ASYNC7
MAKE RX CLEARER
COMPLEX ASYNC FLOW
private fun prefetchData(): Completable =
Completable.mergeArray(
async1().concatWith(async2()).concatWith(async3().mergeWith(async4())),
async1().concatWith(async5()),
async6().concatWith(async7()))
ASYNC1
ASYNC2
ASYNC3 ASYNC4
ASYNC5
ASYNC6
ASYNC7
MAKE RX CLEARER
COMPLEX ASYNC FLOW
private fun prefetchData(): Completable =
Completable.mergeArray(
async1().concatWith(async2()).concatWith(async3().mergeWith(async4())),
async1().concatWith(async5()),
async6().concatWith(async7()))
ASYNC1 ASYNC6
MAKE RX CLEARER
COMPLEX ASYNC FLOW
private fun prefetchData(): Completable =
Completable.mergeArray(
async1().concatWith(async2()).concatWith(async3().mergeWith(async4())),
async1().concatWith(async5()),
async6().concatWith(async7()))
ASYNC1
ASYNC2
ASYNC6
MAKE RX CLEARER
COMPLEX ASYNC FLOW
private fun prefetchData(): Completable =
Completable.mergeArray(
async1().concatWith(async2()).concatWith(async3().mergeWith(async4())),
async1().concatWith(async5()),
async6().concatWith(async7()))
ASYNC1
ASYNC2
ASYNC6
ASYNC3 ASYNC4
MAKE RX CLEARER
COMPLEX ASYNC FLOW
private fun prefetchData(): Completable =
Completable.mergeArray(
async1().concatWith(async2()).concatWith(async3().mergeWith(async4())),
async1().concatWith(async5()),
async6().concatWith(async7()))
ASYNC1
ASYNC2
ASYNC3 ASYNC4
ASYNC6
MAKE RX CLEARER
COMPLEX ASYNC FLOW
private fun prefetchData(): Completable =
Completable.mergeArray(
async1().concatWith(async2()).concatWith(async3().mergeWith(async4())),
async1().concatWith(async5()),
async6().concatWith(async7()))
ASYNC1
ASYNC2
ASYNC3 ASYNC4
ASYNC5
ASYNC6
MAKE RX CLEARER
COMPLEX ASYNC FLOW
private fun prefetchData(): Completable =
Completable.mergeArray(
async1().concatWith(async2()).concatWith(async3().mergeWith(async4())),
async1().concatWith(async5()),
async6().concatWith(async7()))
ASYNC1
ASYNC2
ASYNC3 ASYNC4
ASYNC5
ASYNC6
ASYNC7
MAKE RX CLEARER
COMPLEX ASYNC FLOW
private fun prefetchData(): Completable =
Completable.mergeArray(
async1().concatWith(async2()).concatWith(async3().mergeWith(async4())),
async1().concatWith(async5()),
async6().concatWith(async7()))
ASYNC1
ASYNC2
ASYNC3 ASYNC4
ASYNC5
ASYNC6
ASYNC7
MAKE RX CLEARER
COMPLEX ASYNC FLOW - CLEANER?
fun inParallel(vararg sources: CompletableSource): Completable =
Completable.mergeArray(*sources)
infix fun Completable.andThen(next: CompletableSource): Completable =
this.concatWith(next)
infix fun Completable.alongside(other: CompletableSource): Completable
= this.mergeWith(other)
ASYNC1
ASYNC2
ASYNC3 ASYNC4
ASYNC5
ASYNC6
ASYNC7
MAKE RX CLEARER
COMPLEX ASYNC FLOW
private fun prefetchData(): Completable =
Completable.mergeArray(
async1().concatWith(async2()).concatWith(async3().mergeWith(async4())),
async1().concatWith(async5()),
async6().concatWith(async7()))
ASYNC1
ASYNC2
ASYNC3 ASYNC4
ASYNC5
ASYNC6
ASYNC7
MAKE RX CLEARER
COMPLEX ASYNC FLOW - CLEANER!
private fun prefetchData(): Completable =
inParallel(
async1() andThen async2() andThen (async3() alongside async4()),
async1() andThen async5(),
async6() andThen async7())
ASYNC1
ASYNC2
ASYNC3 ASYNC4
ASYNC5
ASYNC6
ASYNC7
YOU MIGHT NOT THINK THAT PROGRAMMERS ARE
ARTISTS, BUT PROGRAMMING IS AN EXTREMELY
CREATIVE PROFESSION. IT'S LOGIC-BASED
CREATIVITY.
John Romero
MAKE RX CLEARER
ENABLE FUNCTIONAL ARCHITECTURE
IMMUTABLE VALUE TYPES
▸ have no identity
▸ defined by the set of values they hold
▸ overrides equals, hashCode and toString
▸ builder pattern (?)
ENABLE FUNCTIONAL ARCHITECTURE
IMMUTABLE VALUE TYPES
▸ Java has no built-in support :(
▸ Possible through AutoValue :)
▸ AutoValue is no fun :(
ENABLE FUNCTIONAL ARCHITECTURE
IMMUTABLE VALUE TYPES - AUTO VALUE
@AutoValue
abstract class RepositoryResponse {
@NonNull abstract long id();
@NonNull abstract String name();
@NonNull abstract String fullName();
@NonNull abstract UserResponse owner();
@NonNull abstract String htmlUri();
@NonNull abstract String description();
@NonNull abstract String uri();
public static Builder builder() {
return new AutoValue_RepositoryResponse.Builder();
}
@AutoValue.Builder abstract static class Builder {
abstract Builder id(long id);
abstract Builder name(String name);
abstract Builder fullName(String fullName);
abstract Builder owner(UserResponse owner);
abstract Builder description(String description);
abstract Builder uri(String uri);
abstract RepositoryResponse build();
}
}
ENABLE FUNCTIONAL ARCHITECTURE
IMMUTABLE VALUE TYPES - DATA CLASS
data class RepositoryResponse(val id: Long, val name: String,
val fullName: String, val owner: UserResponse,
val htmlUri: String, val description: String,
val uri: String)
ENABLE FUNCTIONAL ARCHITECTURE
IMMUTABLE VALUE TYPES - DATA CLASS
data class RepositoryResponse(val id: Long, val name: String,
val fullName: String, val owner: UserResponse,
val htmlUri: String, val description: String,
val uri: String)
val owner: UserResponse = TODO("stub")
val response = RepositoryResponse(id = 33768, name = "restor1",
fullName = "Or Noyman", owner = owner, htmlUri = "...",
description = "...", uri = "...")
ENABLE FUNCTIONAL ARCHITECTURE
SEALED CLASS HIERARCHIES
▸ model all possible outcomes as data types
▸ represent through restricted class hierarchies
▸ leverage ‘when’ expressions
ENABLE FUNCTIONAL ARCHITECTURE
SEALED CLASS HIERARCHIES
fun fetchRepositories(username: String): Observable<?>
ENABLE FUNCTIONAL ARCHITECTURE
SEALED CLASS HIERARCHIES
fun fetchRepositories(username: String): Observable<FetchRepositoriesResult>
sealed class FetchRepositoriesResult
ENABLE FUNCTIONAL ARCHITECTURE
SEALED CLASS HIERARCHIES
fun fetchRepositories(username: String): Observable<FetchRepositoriesResult>
sealed class FetchRepositoriesResult
object FetchRepositoriesLoading : FetchRepositoriesResult()
object FetchRepositoriesError : FetchRepositoriesResult()
data class FetchRepositoriesOk(val repo: List<RepositoryResponse>)
: FetchRepositoriesResult()
ENABLE FUNCTIONAL ARCHITECTURE
SEALED CLASS HIERARCHIES
fun fetchRepositories(username: String): Observable<FetchRepositoriesResult> =
githubApiService.getUsersRepositories(username)
.map<FetchRepositoriesResult>(::FetchRepositoriesOk)
.onErrorReturnItem(FetchRepositoriesError)
.startWith(FetchRepositoriesLoading)
sealed class FetchRepositoriesResult
object FetchRepositoriesLoading : FetchRepositoriesResult()
object FetchRepositoriesError : FetchRepositoriesResult()
data class FetchRepositoriesOk(val repo: List<RepositoryResponse>)
: FetchRepositoriesResult()
ENABLE FUNCTIONAL ARCHITECTURE
SEALED CLASS HIERARCHIES
fun fetchRepositories(username: String): Observable<FetchRepositoriesResult> =
githubApiService.getUsersRepositories(username)
.map<FetchRepositoriesResult>(::FetchRepositoriesOk)
.onErrorReturnItem(FetchRepositoriesError)
.startWith(FetchRepositoriesLoading)
sealed class FetchRepositoriesResult
object FetchRepositoriesLoading : FetchRepositoriesResult()
object FetchRepositoriesError : FetchRepositoriesResult()
data class FetchRepositoriesOk(val repo: List<RepositoryResponse>)
: FetchRepositoriesResult()
ENABLE FUNCTIONAL ARCHITECTURE
SEALED CLASS HIERARCHIES
fun fetchRepositories(username: String): Observable<FetchRepositoriesResult> =
githubApiService.getUsersRepositories(username)
.map<FetchRepositoriesResult>(::FetchRepositoriesOk)
.onErrorReturnItem(FetchRepositoriesError)
.startWith(FetchRepositoriesLoading)
sealed class FetchRepositoriesResult
object FetchRepositoriesLoading : FetchRepositoriesResult()
object FetchRepositoriesError : FetchRepositoriesResult()
data class FetchRepositoriesOk(val repo: List<RepositoryResponse>)
: FetchRepositoriesResult()
ENABLE FUNCTIONAL ARCHITECTURE
SEALED CLASS HIERARCHIES
fun fetchRepositories(username: String): Observable<FetchRepositoriesResult> =
githubApiService.getUsersRepositories(username)
.map<FetchRepositoriesResult>(::FetchRepositoriesOk)
.onErrorReturnItem(FetchRepositoriesError)
.startWith(FetchRepositoriesLoading)
sealed class FetchRepositoriesResult
object FetchRepositoriesLoading : FetchRepositoriesResult()
object FetchRepositoriesError : FetchRepositoriesResult()
data class FetchRepositoriesOk(val repo: List<RepositoryResponse>)
: FetchRepositoriesResult()
ENABLE FUNCTIONAL ARCHITECTURE
SEALED CLASS HIERARCHIES
fun fetchRepositories(username: String): Observable<FetchRepositoriesResult> =
githubApiService.getUsersRepositories(username)
.map<FetchRepositoriesResult>(::FetchRepositoriesOk)
.onErrorReturnItem(FetchRepositoriesError)
.startWith(FetchRepositoriesLoading)
sealed class FetchRepositoriesResult
object FetchRepositoriesLoading : FetchRepositoriesResult()
object FetchRepositoriesError : FetchRepositoriesResult()
data class FetchRepositoriesOk(val repo: List<RepositoryResponse>)
: FetchRepositoriesResult()
ENABLE FUNCTIONAL ARCHITECTURE
SEALED CLASS HIERARCHIES
fun fetchRepositories(username: String): Observable<FetchRepositoriesResult> =
githubApiService.getUsersRepositories(username)
.map<FetchRepositoriesResult>(::FetchRepositoriesOk)
.onErrorReturnItem(FetchRepositoriesError)
.startWith(FetchRepositoriesLoading)
sealed class FetchRepositoriesResult
object FetchRepositoriesLoading : FetchRepositoriesResult()
object FetchRepositoriesError : FetchRepositoriesResult()
data class FetchRepositoriesOk(val repo: List<RepositoryResponse>)
: FetchRepositoriesResult()
ENABLE FUNCTIONAL ARCHITECTURE
WHEN
fun renderFetchRepositories() {
fetchRepositories("JakeWharton")
.observeOn(AndroidSchedulers.mainThread())
.subscribe { response ->
when (response) {
is FetchRepositoriesLoading -> showShimmer()
is FetchRepositoriesError -> showError()
is FetchRepositoriesOk -> renderRepositories(response.repo)
}
}
}
ENABLE FUNCTIONAL ARCHITECTURE
WHEN
fun renderFetchRepositories() {
fetchRepositories("JakeWharton")
.observeOn(AndroidSchedulers.mainThread())
.subscribe { response ->
when (response) {
is FetchRepositoriesLoading -> showShimmer()
is FetchRepositoriesError -> showError()
is FetchRepositoriesOk -> renderRepositories(response.repo)
}
}
}
ENABLE FUNCTIONAL ARCHITECTURE
WHEN
fun renderFetchRepositories() {
fetchRepositories("JakeWharton")
.observeOn(AndroidSchedulers.mainThread())
.subscribe { response ->
when (response) {
is FetchRepositoriesLoading -> showShimmer()
is FetchRepositoriesError -> showError()
is FetchRepositoriesOk -> renderRepositories(response.repo)
}
}
}
ENABLE FUNCTIONAL ARCHITECTURE
WHEN
fun renderFetchRepositories() {
fetchRepositories("JakeWharton")
.observeOn(AndroidSchedulers.mainThread())
.subscribe { response ->
when (response) {
is FetchRepositoriesLoading -> showShimmer()
is FetchRepositoriesError -> showError()
is FetchRepositoriesOk -> renderRepositories(response.repo)
}
}
}
ENABLE FUNCTIONAL ARCHITECTURE
VIEW STATE
▸ immutable value type
▸ represents entire screen state
ENABLE FUNCTIONAL ARCHITECTURE
VIEW STATE REDUCER
CURRENT VIEW STATE EVENT
NEW VIEW STATE
REDUCER
ENABLE FUNCTIONAL ARCHITECTURE
VIEW STATE REDUCER
sealed class FetchRepositoriesResult
object FetchRepositoriesLoading : FetchRepositoriesResult()
object FetchRepositoriesError : FetchRepositoriesResult()
data class FetchRepositoriesOk(val repo: List<RepositoryResponse>)
: FetchRepositoriesResult()
ENABLE FUNCTIONAL ARCHITECTURE
VIEW STATE REDUCER
sealed class Event
sealed class FetchRepositoriesResult: Event()
object FetchRepositoriesLoading : FetchRepositoriesResult()
object FetchRepositoriesError : FetchRepositoriesResult()
data class FetchRepositoriesOk(val repo: List<RepositoryResponse>)
: FetchRepositoriesResult()
sealed class FetchUserResult: Event()
object FetchUserLoading : FetchUserResult()
object FetchUserError : FetchUserResult()
data class FetchUserOk(val user: UserResponse)
: FetchUserResult()
ENABLE FUNCTIONAL ARCHITECTURE
VIEW STATE REDUCER
sealed class Event
sealed class FetchRepositoriesResult: Event()
object FetchRepositoriesLoading : FetchRepositoriesResult()
object FetchRepositoriesError : FetchRepositoriesResult()
data class FetchRepositoriesOk(val repo: List<RepositoryResponse>)
: FetchRepositoriesResult()
sealed class FetchUserResult: Event()
object FetchUserLoading : FetchUserResult()
object FetchUserError : FetchUserResult()
data class FetchUserOk(val user: UserResponse)
: FetchUserResult()
ENABLE FUNCTIONAL ARCHITECTURE
VIEW STATE REDUCER
data class ViewState(val isLoadingUser: Boolean,
val isErrorUser: Boolean,
val user: UserResponse?,
val isLoadingRepos: Boolean,
val isErrorRepos: Boolean,
val repos: List<RepositoryResponse>?)
ENABLE FUNCTIONAL ARCHITECTURE
VIEW STATE REDUCER
fun ViewState.reduce(event: Event): ViewState =
when (event) {
FetchRepositoriesLoading -> this.copy(isLoadingRepos = true,
isErrorRepos = false)
FetchRepositoriesError -> this.copy(isLoadingRepos = false,
isErrorRepos = true)
is FetchRepositoriesOk -> this.copy(repos = event.repo,
isLoadingRepos = false)
FetchUserLoading -> this.copy(isLoadingUser = true,
isErrorUser = false)
FetchUserError -> this.copy(isLoadingUser = false,
isErrorUser = true)
is FetchUserOk -> this.copy(user = event.user,
isLoadingUser = false)
}
ENABLE FUNCTIONAL ARCHITECTURE
VIEW STATE REDUCER
fun ViewState.reduce(event: Event): ViewState =
when (event) {
FetchRepositoriesLoading -> this.copy(isLoadingRepos = true,
isErrorRepos = false)
FetchRepositoriesError -> this.copy(isLoadingRepos = false,
isErrorRepos = true)
is FetchRepositoriesOk -> this.copy(repos = event.repo,
isLoadingRepos = false)
FetchUserLoading -> this.copy(isLoadingUser = true,
isErrorUser = false)
FetchUserError -> this.copy(isLoadingUser = false,
isErrorUser = true)
is FetchUserOk -> this.copy(user = event.user,
isLoadingUser = false)
}
ENABLE FUNCTIONAL ARCHITECTURE
VIEW STATE REDUCER
fun ViewState.reduce(event: Event): ViewState =
when (event) {
FetchRepositoriesLoading -> this.copy(isLoadingRepos = true,
isErrorRepos = false)
FetchRepositoriesError -> this.copy(isLoadingRepos = false,
isErrorRepos = true)
is FetchRepositoriesOk -> this.copy(repos = event.repo,
isLoadingRepos = false)
FetchUserLoading -> this.copy(isLoadingUser = true,
isErrorUser = false)
FetchUserError -> this.copy(isLoadingUser = false,
isErrorUser = true)
is FetchUserOk -> this.copy(user = event.user,
isLoadingUser = false)
}
ENABLE FUNCTIONAL ARCHITECTURE
VIEW STATE REDUCER
fun ViewState.reduce(event: Event): ViewState =
when (event) {
FetchRepositoriesLoading -> this.copy(isLoadingRepos = true,
isErrorRepos = false)
FetchRepositoriesError -> this.copy(isLoadingRepos = false,
isErrorRepos = true)
is FetchRepositoriesOk -> this.copy(repos = event.repo,
isLoadingRepos = false)
FetchUserLoading -> this.copy(isLoadingUser = true,
isErrorUser = false)
FetchUserError -> this.copy(isLoadingUser = false,
isErrorUser = true)
is FetchUserOk -> this.copy(user = event.user,
isLoadingUser = false)
}
ENABLE FUNCTIONAL ARCHITECTURE
VIEW STATE REDUCER
fun ViewState.reduce(event: Event): ViewState =
when (event) {
FetchRepositoriesLoading -> this.copy(isLoadingRepos = true,
isErrorRepos = false)
FetchRepositoriesError -> this.copy(isLoadingRepos = false,
isErrorRepos = true)
is FetchRepositoriesOk -> this.copy(repos = event.repo,
isLoadingRepos = false)
FetchUserLoading -> this.copy(isLoadingUser = true,
isErrorUser = false)
FetchUserError -> this.copy(isLoadingUser = false,
isErrorUser = true)
is FetchUserOk -> this.copy(user = event.user,
isLoadingUser = false)
}
ENABLE FUNCTIONAL ARCHITECTURE
VIEW STATE REDUCER
fun ViewState.reduce(event: Event): ViewState =
when (event) {
FetchRepositoriesLoading -> this.copy(isLoadingRepos = true,
isErrorRepos = false)
FetchRepositoriesError -> this.copy(isLoadingRepos = false,
isErrorRepos = true)
is FetchRepositoriesOk -> this.copy(repos = event.repo,
isLoadingRepos = false)
FetchUserLoading -> this.copy(isLoadingUser = true,
isErrorUser = false)
FetchUserError -> this.copy(isLoadingUser = false,
isErrorUser = true)
is FetchUserOk -> this.copy(user = event.user,
isLoadingUser = false)
}
MORE ABOUT THE DEMISE OF OOP
▸ https://medium.com/@cscalfani/goodbye-object-oriented-
programming-a59cda4c0e53
MORE MODEL-VIEW-INTENT-PATTERN
▸ Jake Wharton - Managing State with RX
▸ http://hannesdorfmann.com/android/mosby3-mvi-1
MORE ABOUT FUNCTIONAL KOTLIN
▸ http://kategory.io
▸ http://kategory.io/docs/quickstart/blogs/

More Related Content

What's hot

Merge sort
Merge sortMerge sort
Merge sortKumar
 
Conctructing Polytopes via a Vertex Oracle
Conctructing Polytopes via a Vertex OracleConctructing Polytopes via a Vertex Oracle
Conctructing Polytopes via a Vertex OracleVissarion Fisikopoulos
 
T sql denali code Day of .Net
T sql denali code Day of .NetT sql denali code Day of .Net
T sql denali code Day of .NetKathiK58
 
String matching with finite state automata
String matching with finite state automataString matching with finite state automata
String matching with finite state automataAnmol Hamid
 
RedisConf18 - CRDTs and Redis - From sequential to concurrent executions
RedisConf18 - CRDTs and Redis - From sequential to concurrent executionsRedisConf18 - CRDTs and Redis - From sequential to concurrent executions
RedisConf18 - CRDTs and Redis - From sequential to concurrent executionsRedis Labs
 
視覚化とSwiftのタイプについて
視覚化とSwiftのタイプについて視覚化とSwiftのタイプについて
視覚化とSwiftのタイプについてRay Fix
 

What's hot (9)

Merge sort
Merge sortMerge sort
Merge sort
 
Stacks queues
Stacks queuesStacks queues
Stacks queues
 
Conctructing Polytopes via a Vertex Oracle
Conctructing Polytopes via a Vertex OracleConctructing Polytopes via a Vertex Oracle
Conctructing Polytopes via a Vertex Oracle
 
T sql denali code Day of .Net
T sql denali code Day of .NetT sql denali code Day of .Net
T sql denali code Day of .Net
 
String matching with finite state automata
String matching with finite state automataString matching with finite state automata
String matching with finite state automata
 
RedisConf18 - CRDTs and Redis - From sequential to concurrent executions
RedisConf18 - CRDTs and Redis - From sequential to concurrent executionsRedisConf18 - CRDTs and Redis - From sequential to concurrent executions
RedisConf18 - CRDTs and Redis - From sequential to concurrent executions
 
Block Diagram Algebra
Block Diagram AlgebraBlock Diagram Algebra
Block Diagram Algebra
 
視覚化とSwiftのタイプについて
視覚化とSwiftのタイプについて視覚化とSwiftのタイプについて
視覚化とSwiftのタイプについて
 
Stacks fundamentals
Stacks fundamentalsStacks fundamentals
Stacks fundamentals
 

Similar to Kotlinify Your Project!

Monadologie
MonadologieMonadologie
Monadologieleague
 
Functional Programming for OO Programmers (part 2)
Functional Programming for OO Programmers (part 2)Functional Programming for OO Programmers (part 2)
Functional Programming for OO Programmers (part 2)Calvin Cheng
 
TI1220 Lecture 6: First-class Functions
TI1220 Lecture 6: First-class FunctionsTI1220 Lecture 6: First-class Functions
TI1220 Lecture 6: First-class FunctionsEelco Visser
 
Functional programming in Swift
Functional programming in SwiftFunctional programming in Swift
Functional programming in SwiftJohn Pham
 
Introduction to R programming
Introduction to R programmingIntroduction to R programming
Introduction to R programmingAlberto Labarga
 
yield and return (poor English ver)
yield and return (poor English ver)yield and return (poor English ver)
yield and return (poor English ver)bleis tift
 
Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3Kirill Rozov
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with GroovyArturo Herrero
 
Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303Alex Semin
 
Kotlin for Android Developers - 2
Kotlin for Android Developers - 2Kotlin for Android Developers - 2
Kotlin for Android Developers - 2Mohamed Nabil, MSc.
 
Hitchhiker's Guide to Functional Programming
Hitchhiker's Guide to Functional ProgrammingHitchhiker's Guide to Functional Programming
Hitchhiker's Guide to Functional ProgrammingSergey Shishkin
 
Functions in advanced programming
Functions in advanced programmingFunctions in advanced programming
Functions in advanced programmingVisnuDharsini
 
Go: It's Not Just For Google
Go: It's Not Just For GoogleGo: It's Not Just For Google
Go: It's Not Just For GoogleEleanor McHugh
 
Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015Leonardo Borges
 
Swift 함수 커링 사용하기
Swift 함수 커링 사용하기Swift 함수 커링 사용하기
Swift 함수 커링 사용하기진성 오
 
Data structure 8.pptx
Data structure 8.pptxData structure 8.pptx
Data structure 8.pptxSajalFayyaz
 
Un dsl pour ma base de données
Un dsl pour ma base de donnéesUn dsl pour ma base de données
Un dsl pour ma base de donnéesRomain Lecomte
 
RxJS Evolved
RxJS EvolvedRxJS Evolved
RxJS Evolvedtrxcllnt
 

Similar to Kotlinify Your Project! (20)

Monadologie
MonadologieMonadologie
Monadologie
 
Functional Programming for OO Programmers (part 2)
Functional Programming for OO Programmers (part 2)Functional Programming for OO Programmers (part 2)
Functional Programming for OO Programmers (part 2)
 
TI1220 Lecture 6: First-class Functions
TI1220 Lecture 6: First-class FunctionsTI1220 Lecture 6: First-class Functions
TI1220 Lecture 6: First-class Functions
 
Functional programming in Swift
Functional programming in SwiftFunctional programming in Swift
Functional programming in Swift
 
Introduction to R programming
Introduction to R programmingIntroduction to R programming
Introduction to R programming
 
yield and return (poor English ver)
yield and return (poor English ver)yield and return (poor English ver)
yield and return (poor English ver)
 
Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3
 
Functional Programming with Groovy
Functional Programming with GroovyFunctional Programming with Groovy
Functional Programming with Groovy
 
Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303Dip into Coroutines - KTUG Munich 202303
Dip into Coroutines - KTUG Munich 202303
 
Kotlin for Android Developers - 2
Kotlin for Android Developers - 2Kotlin for Android Developers - 2
Kotlin for Android Developers - 2
 
Hitchhiker's Guide to Functional Programming
Hitchhiker's Guide to Functional ProgrammingHitchhiker's Guide to Functional Programming
Hitchhiker's Guide to Functional Programming
 
Functions in advanced programming
Functions in advanced programmingFunctions in advanced programming
Functions in advanced programming
 
Go: It's Not Just For Google
Go: It's Not Just For GoogleGo: It's Not Just For Google
Go: It's Not Just For Google
 
Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015Parametricity - #cljsyd - May, 2015
Parametricity - #cljsyd - May, 2015
 
Swift 함수 커링 사용하기
Swift 함수 커링 사용하기Swift 함수 커링 사용하기
Swift 함수 커링 사용하기
 
Data structure 8.pptx
Data structure 8.pptxData structure 8.pptx
Data structure 8.pptx
 
Disjoint sets
Disjoint setsDisjoint sets
Disjoint sets
 
Un dsl pour ma base de données
Un dsl pour ma base de donnéesUn dsl pour ma base de données
Un dsl pour ma base de données
 
DataStructures notes
DataStructures notesDataStructures notes
DataStructures notes
 
RxJS Evolved
RxJS EvolvedRxJS Evolved
RxJS Evolved
 

Recently uploaded

Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionSolGuruz
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️anilsa9823
 
Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendArshad QA
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
Clustering techniques data mining book ....
Clustering techniques data mining book ....Clustering techniques data mining book ....
Clustering techniques data mining book ....ShaimaaMohamedGalal
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about usDynamic Netsoft
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerThousandEyes
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
Active Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdfActive Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdfCionsystems
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 

Recently uploaded (20)

Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
 
Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and Backend
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
Clustering techniques data mining book ....
Clustering techniques data mining book ....Clustering techniques data mining book ....
Clustering techniques data mining book ....
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about us
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
Active Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdfActive Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdf
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 

Kotlinify Your Project!

  • 2.
  • 3.
  • 4.
  • 5. AGENDA KOTLIN ENABLES FUNCTION ORIENTED PROGRAMMING STYLE ▸ High order functions ▸ Functions as first-class citizens ▸ Type inference ▸ Extension functions ▸ Operator overloading ▸ Collection API (map, flatMap, reduce) ▸ Algebric data types (sealed classes)
  • 6. AGENDA WHY FUNCTIONAL? ▸ Referential transparency ▸ Purity ▸ Deferred computation (lazy evaluation) ▸ Higher-Level abstractions
  • 7. RECURSIONS THE ITERATIVE WAY fun Context?.findActivity(): Activity? { var context = this while (context is ContextWrapper) { if (context is Activity) { return context } context = context.baseContext } return null }
  • 8. RECURSIONS THE RECURSIVE WAY fun Context?.findActivity(): Activity? = when (this) { is Activity -> this is ContextWrapper -> this.baseContext.findActivity() else -> null }
  • 9. RECURSIONS THE (TAIL)RECURSIVE WAY tailrec fun Context?.findActivity(): Activity? = when (this) { is Activity -> this is ContextWrapper -> this.baseContext.findActivity() else -> null }
  • 10. RECURSIONS THE (TAIL)RECURSIVE WAY @Nullable public static final Activity findActivity(@Nullable Context $receiver) { while(true) { Activity var10000; if($receiver instanceof Activity) { var10000 = (Activity)$receiver; } else { if($receiver instanceof ContextWrapper) { $receiver = ((ContextWrapper)$receiver).getBaseContext(); continue; } var10000 = null; } return var10000; } }
  • 13. RECURSIONS FALL-THROUGH-SWITCH void verify(TestDriver driver) { switch (verification) { case VERIFY_PHASE_4: verifyPhase4(driver); case VERIFY_PHASE_3: verifyPhase3(driver); case VERIFY_PHASE_2: verifyPhase2(driver); case VERIFY_PHASE_1: verifyPhase1(driver); case NO_VERIFICATION: } } PHASE1 PHASE2 PHASE3 PHASE4 VERIFY1 VERIFY2 VERIFY3 VERIFY4
  • 14. RECURSIONS FALL-THROUGH-WHEN? fun verify(driver: TestDriver) = when (verification) { NO_VERIFICATION -> Unit VERIFY_PHASE_1 -> verifyPhase1(driver) VERIFY_PHASE_2 -> { verifyPhase1(driver) verifyPhase2(driver) } VERIFY_PHASE_3 -> { verifyPhase1(driver) verifyPhase2(driver) verifyPhase3(driver) } VERIFY_PHASE_4 -> { verifyPhase1(driver) verifyPhase2(driver) verifyPhase3(driver) verifyPhase4(driver) } } PHASE1 PHASE2 PHASE3 PHASE4 VERIFY1 VERIFY2 VERIFY3 VERIFY4
  • 15. RECURSIONS FALL-THROUGH-LIKE-WHEN inline fun <reified T : Enum<T>> T.prev(): T { val values = enumValues<T>() val prevOrdinal = (ordinal - 1) % values.size return values[prevOrdinal] } enum class Verification { NO_VERIFICATION, VERIFY_PHASE_1, VERIFY_PHASE_2, VERIFY_PHASE_3, VERIFY_PHASE_4 } PHASE1 PHASE2 PHASE3 PHASE4 VERIFY1 VERIFY2 VERIFY3 VERIFY4
  • 16. RECURSIONS FALL-THROUGH-LIKE-WHEN inline fun <reified T : Enum<T>> T.prev(): T { val values = enumValues<T>() val prevOrdinal = (ordinal - 1) % values.size return values[prevOrdinal] } enum class Verification { NO_VERIFICATION, VERIFY_PHASE_1, VERIFY_PHASE_2, VERIFY_PHASE_3, VERIFY_PHASE_4 } PHASE1 PHASE2 PHASE3 PHASE4 VERIFY1 VERIFY2 VERIFY3 VERIFY4
  • 17. RECURSIONS FALL-THROUGH-LIKE-WHEN inline fun <reified T : Enum<T>> T.prev(): T { val values = enumValues<T>() val prevOrdinal = (ordinal - 1) % values.size return values[prevOrdinal] } enum class Verification { NO_VERIFICATION, VERIFY_PHASE_1, VERIFY_PHASE_2, VERIFY_PHASE_3, VERIFY_PHASE_4 } PHASE1 PHASE2 PHASE3 PHASE4 VERIFY1 VERIFY2 VERIFY3 VERIFY4
  • 18. RECURSIONS FALL-THROUGH-WHEN? fun verify(driver: TestDriver) = when (verification) { NO_VERIFICATION -> Unit VERIFY_PHASE_1 -> verifyPhase1(driver) VERIFY_PHASE_2 -> { verifyPhase1(driver) verifyPhase2(driver) } VERIFY_PHASE_3 -> { verifyPhase1(driver) verifyPhase2(driver) verifyPhase3(driver) } VERIFY_PHASE_4 -> { verifyPhase1(driver) verifyPhase2(driver) verifyPhase3(driver) verifyPhase4(driver) } } PHASE1 PHASE2 PHASE3 PHASE4 VERIFY1 VERIFY2 VERIFY3 VERIFY4
  • 19. RECURSIONS FALL-THROUGH-LIKE-WHEN fun verify(driver: TestDriver) { tailrec fun verify(verification: Verification) { when (verification) { NO_VERIFICATION -> return VERIFY_PHASE_1 -> verifyPhase1(driver) VERIFY_PHASE_2 -> verifyPhase2(driver) VERIFY_PHASE_3 -> verifyPhase3(driver) VERIFY_PHASE_4 -> verifyPhase4(driver) } verify(verification.prev()) } verify(verification) } PHASE1 PHASE2 PHASE3 PHASE4 VERIFY1 VERIFY2 VERIFY3 VERIFY4
  • 20. RECURSIONS FALL-THROUGH-LIKE-WHEN fun verify(driver: TestDriver) { tailrec fun verify(verification: Verification) { when (verification) { NO_VERIFICATION -> return VERIFY_PHASE_1 -> verifyPhase1(driver) VERIFY_PHASE_2 -> verifyPhase2(driver) VERIFY_PHASE_3 -> verifyPhase3(driver) VERIFY_PHASE_4 -> verifyPhase4(driver) } verify(verification.prev()) } verify(verification) } PHASE1 PHASE2 PHASE3 PHASE4 VERIFY1 VERIFY2 VERIFY3 VERIFY4
  • 21. RECURSIONS FALL-THROUGH-LIKE-WHEN fun verify(driver: TestDriver) { tailrec fun verify(verification: Verification) { when (verification) { NO_VERIFICATION -> return VERIFY_PHASE_1 -> verifyPhase1(driver) VERIFY_PHASE_2 -> verifyPhase2(driver) VERIFY_PHASE_3 -> verifyPhase3(driver) VERIFY_PHASE_4 -> verifyPhase4(driver) } verify(verification.prev()) } verify(verification) } PHASE1 PHASE2 PHASE3 PHASE4 VERIFY1 VERIFY2 VERIFY3 VERIFY4
  • 22. RECURSIONS FALL-THROUGH-LIKE-WHEN fun verify(driver: TestDriver) { tailrec fun verify(verification: Verification) { when (verification) { NO_VERIFICATION -> return VERIFY_PHASE_1 -> verifyPhase1(driver) VERIFY_PHASE_2 -> verifyPhase2(driver) VERIFY_PHASE_3 -> verifyPhase3(driver) VERIFY_PHASE_4 -> verifyPhase4(driver) } verify(verification.prev()) } verify(verification) } PHASE1 PHASE2 PHASE3 PHASE4 VERIFY1 VERIFY2 VERIFY3 VERIFY4
  • 23. RECURSIONS FALL-THROUGH-LIKE-WHEN fun verify(driver: TestDriver) { tailrec fun verify(verification: Verification) { when (verification) { NO_VERIFICATION -> return VERIFY_PHASE_1 -> verifyPhase1(driver) VERIFY_PHASE_2 -> verifyPhase2(driver) VERIFY_PHASE_3 -> verifyPhase3(driver) VERIFY_PHASE_4 -> verifyPhase4(driver) } verify(verification.prev()) } verify(verification) } PHASE1 PHASE2 PHASE3 PHASE4 VERIFY1 VERIFY2 VERIFY3 VERIFY4
  • 24. RECURSIONS DEFERRED RECURSION (RECURSIVE FLATMAP) ▸ see: https://goo.gl/tuDwFn
  • 25.
  • 26.
  • 27. MAKE RX CLEARER COMPLEX ASYNC FLOW ▸ Parallelise as much as possible ▸ Respect dependencies ASYNC1 ASYNC2 ASYNC3 ASYNC4 ASYNC5 ASYNC6 ASYNC7
  • 28. MAKE RX CLEARER COMPLEX ASYNC FLOW fun async1(): Completable { ... } fun async2(): Completable { ... } fun async3(): Completable { ... } fun async4(): Completable { ... } fun async5(): Completable { ... } fun async6(): Completable { ... } fun async7(): Completable { ... } ASYNC1 ASYNC2 ASYNC3 ASYNC4 ASYNC5 ASYNC6 ASYNC7
  • 29. MAKE RX CLEARER COMPLEX ASYNC FLOW private fun prefetchData(): Completable = Completable.mergeArray( async1().concatWith(async2()).concatWith(async3().mergeWith(async4())), async1().concatWith(async5()), async6().concatWith(async7())) ASYNC1 ASYNC2 ASYNC3 ASYNC4 ASYNC5 ASYNC6 ASYNC7
  • 30. MAKE RX CLEARER COMPLEX ASYNC FLOW private fun prefetchData(): Completable = Completable.mergeArray( async1().concatWith(async2()).concatWith(async3().mergeWith(async4())), async1().concatWith(async5()), async6().concatWith(async7())) ASYNC1 ASYNC6
  • 31. MAKE RX CLEARER COMPLEX ASYNC FLOW private fun prefetchData(): Completable = Completable.mergeArray( async1().concatWith(async2()).concatWith(async3().mergeWith(async4())), async1().concatWith(async5()), async6().concatWith(async7())) ASYNC1 ASYNC2 ASYNC6
  • 32. MAKE RX CLEARER COMPLEX ASYNC FLOW private fun prefetchData(): Completable = Completable.mergeArray( async1().concatWith(async2()).concatWith(async3().mergeWith(async4())), async1().concatWith(async5()), async6().concatWith(async7())) ASYNC1 ASYNC2 ASYNC6 ASYNC3 ASYNC4
  • 33. MAKE RX CLEARER COMPLEX ASYNC FLOW private fun prefetchData(): Completable = Completable.mergeArray( async1().concatWith(async2()).concatWith(async3().mergeWith(async4())), async1().concatWith(async5()), async6().concatWith(async7())) ASYNC1 ASYNC2 ASYNC3 ASYNC4 ASYNC6
  • 34. MAKE RX CLEARER COMPLEX ASYNC FLOW private fun prefetchData(): Completable = Completable.mergeArray( async1().concatWith(async2()).concatWith(async3().mergeWith(async4())), async1().concatWith(async5()), async6().concatWith(async7())) ASYNC1 ASYNC2 ASYNC3 ASYNC4 ASYNC5 ASYNC6
  • 35. MAKE RX CLEARER COMPLEX ASYNC FLOW private fun prefetchData(): Completable = Completable.mergeArray( async1().concatWith(async2()).concatWith(async3().mergeWith(async4())), async1().concatWith(async5()), async6().concatWith(async7())) ASYNC1 ASYNC2 ASYNC3 ASYNC4 ASYNC5 ASYNC6 ASYNC7
  • 36. MAKE RX CLEARER COMPLEX ASYNC FLOW private fun prefetchData(): Completable = Completable.mergeArray( async1().concatWith(async2()).concatWith(async3().mergeWith(async4())), async1().concatWith(async5()), async6().concatWith(async7())) ASYNC1 ASYNC2 ASYNC3 ASYNC4 ASYNC5 ASYNC6 ASYNC7
  • 37. MAKE RX CLEARER COMPLEX ASYNC FLOW - CLEANER? fun inParallel(vararg sources: CompletableSource): Completable = Completable.mergeArray(*sources) infix fun Completable.andThen(next: CompletableSource): Completable = this.concatWith(next) infix fun Completable.alongside(other: CompletableSource): Completable = this.mergeWith(other) ASYNC1 ASYNC2 ASYNC3 ASYNC4 ASYNC5 ASYNC6 ASYNC7
  • 38. MAKE RX CLEARER COMPLEX ASYNC FLOW private fun prefetchData(): Completable = Completable.mergeArray( async1().concatWith(async2()).concatWith(async3().mergeWith(async4())), async1().concatWith(async5()), async6().concatWith(async7())) ASYNC1 ASYNC2 ASYNC3 ASYNC4 ASYNC5 ASYNC6 ASYNC7
  • 39. MAKE RX CLEARER COMPLEX ASYNC FLOW - CLEANER! private fun prefetchData(): Completable = inParallel( async1() andThen async2() andThen (async3() alongside async4()), async1() andThen async5(), async6() andThen async7()) ASYNC1 ASYNC2 ASYNC3 ASYNC4 ASYNC5 ASYNC6 ASYNC7
  • 40. YOU MIGHT NOT THINK THAT PROGRAMMERS ARE ARTISTS, BUT PROGRAMMING IS AN EXTREMELY CREATIVE PROFESSION. IT'S LOGIC-BASED CREATIVITY. John Romero MAKE RX CLEARER
  • 41. ENABLE FUNCTIONAL ARCHITECTURE IMMUTABLE VALUE TYPES ▸ have no identity ▸ defined by the set of values they hold ▸ overrides equals, hashCode and toString ▸ builder pattern (?)
  • 42. ENABLE FUNCTIONAL ARCHITECTURE IMMUTABLE VALUE TYPES ▸ Java has no built-in support :( ▸ Possible through AutoValue :) ▸ AutoValue is no fun :(
  • 43. ENABLE FUNCTIONAL ARCHITECTURE IMMUTABLE VALUE TYPES - AUTO VALUE @AutoValue abstract class RepositoryResponse { @NonNull abstract long id(); @NonNull abstract String name(); @NonNull abstract String fullName(); @NonNull abstract UserResponse owner(); @NonNull abstract String htmlUri(); @NonNull abstract String description(); @NonNull abstract String uri(); public static Builder builder() { return new AutoValue_RepositoryResponse.Builder(); } @AutoValue.Builder abstract static class Builder { abstract Builder id(long id); abstract Builder name(String name); abstract Builder fullName(String fullName); abstract Builder owner(UserResponse owner); abstract Builder description(String description); abstract Builder uri(String uri); abstract RepositoryResponse build(); } }
  • 44. ENABLE FUNCTIONAL ARCHITECTURE IMMUTABLE VALUE TYPES - DATA CLASS data class RepositoryResponse(val id: Long, val name: String, val fullName: String, val owner: UserResponse, val htmlUri: String, val description: String, val uri: String)
  • 45. ENABLE FUNCTIONAL ARCHITECTURE IMMUTABLE VALUE TYPES - DATA CLASS data class RepositoryResponse(val id: Long, val name: String, val fullName: String, val owner: UserResponse, val htmlUri: String, val description: String, val uri: String) val owner: UserResponse = TODO("stub") val response = RepositoryResponse(id = 33768, name = "restor1", fullName = "Or Noyman", owner = owner, htmlUri = "...", description = "...", uri = "...")
  • 46. ENABLE FUNCTIONAL ARCHITECTURE SEALED CLASS HIERARCHIES ▸ model all possible outcomes as data types ▸ represent through restricted class hierarchies ▸ leverage ‘when’ expressions
  • 47. ENABLE FUNCTIONAL ARCHITECTURE SEALED CLASS HIERARCHIES fun fetchRepositories(username: String): Observable<?>
  • 48. ENABLE FUNCTIONAL ARCHITECTURE SEALED CLASS HIERARCHIES fun fetchRepositories(username: String): Observable<FetchRepositoriesResult> sealed class FetchRepositoriesResult
  • 49. ENABLE FUNCTIONAL ARCHITECTURE SEALED CLASS HIERARCHIES fun fetchRepositories(username: String): Observable<FetchRepositoriesResult> sealed class FetchRepositoriesResult object FetchRepositoriesLoading : FetchRepositoriesResult() object FetchRepositoriesError : FetchRepositoriesResult() data class FetchRepositoriesOk(val repo: List<RepositoryResponse>) : FetchRepositoriesResult()
  • 50. ENABLE FUNCTIONAL ARCHITECTURE SEALED CLASS HIERARCHIES fun fetchRepositories(username: String): Observable<FetchRepositoriesResult> = githubApiService.getUsersRepositories(username) .map<FetchRepositoriesResult>(::FetchRepositoriesOk) .onErrorReturnItem(FetchRepositoriesError) .startWith(FetchRepositoriesLoading) sealed class FetchRepositoriesResult object FetchRepositoriesLoading : FetchRepositoriesResult() object FetchRepositoriesError : FetchRepositoriesResult() data class FetchRepositoriesOk(val repo: List<RepositoryResponse>) : FetchRepositoriesResult()
  • 51. ENABLE FUNCTIONAL ARCHITECTURE SEALED CLASS HIERARCHIES fun fetchRepositories(username: String): Observable<FetchRepositoriesResult> = githubApiService.getUsersRepositories(username) .map<FetchRepositoriesResult>(::FetchRepositoriesOk) .onErrorReturnItem(FetchRepositoriesError) .startWith(FetchRepositoriesLoading) sealed class FetchRepositoriesResult object FetchRepositoriesLoading : FetchRepositoriesResult() object FetchRepositoriesError : FetchRepositoriesResult() data class FetchRepositoriesOk(val repo: List<RepositoryResponse>) : FetchRepositoriesResult()
  • 52. ENABLE FUNCTIONAL ARCHITECTURE SEALED CLASS HIERARCHIES fun fetchRepositories(username: String): Observable<FetchRepositoriesResult> = githubApiService.getUsersRepositories(username) .map<FetchRepositoriesResult>(::FetchRepositoriesOk) .onErrorReturnItem(FetchRepositoriesError) .startWith(FetchRepositoriesLoading) sealed class FetchRepositoriesResult object FetchRepositoriesLoading : FetchRepositoriesResult() object FetchRepositoriesError : FetchRepositoriesResult() data class FetchRepositoriesOk(val repo: List<RepositoryResponse>) : FetchRepositoriesResult()
  • 53. ENABLE FUNCTIONAL ARCHITECTURE SEALED CLASS HIERARCHIES fun fetchRepositories(username: String): Observable<FetchRepositoriesResult> = githubApiService.getUsersRepositories(username) .map<FetchRepositoriesResult>(::FetchRepositoriesOk) .onErrorReturnItem(FetchRepositoriesError) .startWith(FetchRepositoriesLoading) sealed class FetchRepositoriesResult object FetchRepositoriesLoading : FetchRepositoriesResult() object FetchRepositoriesError : FetchRepositoriesResult() data class FetchRepositoriesOk(val repo: List<RepositoryResponse>) : FetchRepositoriesResult()
  • 54. ENABLE FUNCTIONAL ARCHITECTURE SEALED CLASS HIERARCHIES fun fetchRepositories(username: String): Observable<FetchRepositoriesResult> = githubApiService.getUsersRepositories(username) .map<FetchRepositoriesResult>(::FetchRepositoriesOk) .onErrorReturnItem(FetchRepositoriesError) .startWith(FetchRepositoriesLoading) sealed class FetchRepositoriesResult object FetchRepositoriesLoading : FetchRepositoriesResult() object FetchRepositoriesError : FetchRepositoriesResult() data class FetchRepositoriesOk(val repo: List<RepositoryResponse>) : FetchRepositoriesResult()
  • 55. ENABLE FUNCTIONAL ARCHITECTURE SEALED CLASS HIERARCHIES fun fetchRepositories(username: String): Observable<FetchRepositoriesResult> = githubApiService.getUsersRepositories(username) .map<FetchRepositoriesResult>(::FetchRepositoriesOk) .onErrorReturnItem(FetchRepositoriesError) .startWith(FetchRepositoriesLoading) sealed class FetchRepositoriesResult object FetchRepositoriesLoading : FetchRepositoriesResult() object FetchRepositoriesError : FetchRepositoriesResult() data class FetchRepositoriesOk(val repo: List<RepositoryResponse>) : FetchRepositoriesResult()
  • 56. ENABLE FUNCTIONAL ARCHITECTURE WHEN fun renderFetchRepositories() { fetchRepositories("JakeWharton") .observeOn(AndroidSchedulers.mainThread()) .subscribe { response -> when (response) { is FetchRepositoriesLoading -> showShimmer() is FetchRepositoriesError -> showError() is FetchRepositoriesOk -> renderRepositories(response.repo) } } }
  • 57. ENABLE FUNCTIONAL ARCHITECTURE WHEN fun renderFetchRepositories() { fetchRepositories("JakeWharton") .observeOn(AndroidSchedulers.mainThread()) .subscribe { response -> when (response) { is FetchRepositoriesLoading -> showShimmer() is FetchRepositoriesError -> showError() is FetchRepositoriesOk -> renderRepositories(response.repo) } } }
  • 58. ENABLE FUNCTIONAL ARCHITECTURE WHEN fun renderFetchRepositories() { fetchRepositories("JakeWharton") .observeOn(AndroidSchedulers.mainThread()) .subscribe { response -> when (response) { is FetchRepositoriesLoading -> showShimmer() is FetchRepositoriesError -> showError() is FetchRepositoriesOk -> renderRepositories(response.repo) } } }
  • 59. ENABLE FUNCTIONAL ARCHITECTURE WHEN fun renderFetchRepositories() { fetchRepositories("JakeWharton") .observeOn(AndroidSchedulers.mainThread()) .subscribe { response -> when (response) { is FetchRepositoriesLoading -> showShimmer() is FetchRepositoriesError -> showError() is FetchRepositoriesOk -> renderRepositories(response.repo) } } }
  • 60.
  • 61. ENABLE FUNCTIONAL ARCHITECTURE VIEW STATE ▸ immutable value type ▸ represents entire screen state
  • 62. ENABLE FUNCTIONAL ARCHITECTURE VIEW STATE REDUCER CURRENT VIEW STATE EVENT NEW VIEW STATE REDUCER
  • 63. ENABLE FUNCTIONAL ARCHITECTURE VIEW STATE REDUCER sealed class FetchRepositoriesResult object FetchRepositoriesLoading : FetchRepositoriesResult() object FetchRepositoriesError : FetchRepositoriesResult() data class FetchRepositoriesOk(val repo: List<RepositoryResponse>) : FetchRepositoriesResult()
  • 64. ENABLE FUNCTIONAL ARCHITECTURE VIEW STATE REDUCER sealed class Event sealed class FetchRepositoriesResult: Event() object FetchRepositoriesLoading : FetchRepositoriesResult() object FetchRepositoriesError : FetchRepositoriesResult() data class FetchRepositoriesOk(val repo: List<RepositoryResponse>) : FetchRepositoriesResult() sealed class FetchUserResult: Event() object FetchUserLoading : FetchUserResult() object FetchUserError : FetchUserResult() data class FetchUserOk(val user: UserResponse) : FetchUserResult()
  • 65. ENABLE FUNCTIONAL ARCHITECTURE VIEW STATE REDUCER sealed class Event sealed class FetchRepositoriesResult: Event() object FetchRepositoriesLoading : FetchRepositoriesResult() object FetchRepositoriesError : FetchRepositoriesResult() data class FetchRepositoriesOk(val repo: List<RepositoryResponse>) : FetchRepositoriesResult() sealed class FetchUserResult: Event() object FetchUserLoading : FetchUserResult() object FetchUserError : FetchUserResult() data class FetchUserOk(val user: UserResponse) : FetchUserResult()
  • 66. ENABLE FUNCTIONAL ARCHITECTURE VIEW STATE REDUCER data class ViewState(val isLoadingUser: Boolean, val isErrorUser: Boolean, val user: UserResponse?, val isLoadingRepos: Boolean, val isErrorRepos: Boolean, val repos: List<RepositoryResponse>?)
  • 67. ENABLE FUNCTIONAL ARCHITECTURE VIEW STATE REDUCER fun ViewState.reduce(event: Event): ViewState = when (event) { FetchRepositoriesLoading -> this.copy(isLoadingRepos = true, isErrorRepos = false) FetchRepositoriesError -> this.copy(isLoadingRepos = false, isErrorRepos = true) is FetchRepositoriesOk -> this.copy(repos = event.repo, isLoadingRepos = false) FetchUserLoading -> this.copy(isLoadingUser = true, isErrorUser = false) FetchUserError -> this.copy(isLoadingUser = false, isErrorUser = true) is FetchUserOk -> this.copy(user = event.user, isLoadingUser = false) }
  • 68. ENABLE FUNCTIONAL ARCHITECTURE VIEW STATE REDUCER fun ViewState.reduce(event: Event): ViewState = when (event) { FetchRepositoriesLoading -> this.copy(isLoadingRepos = true, isErrorRepos = false) FetchRepositoriesError -> this.copy(isLoadingRepos = false, isErrorRepos = true) is FetchRepositoriesOk -> this.copy(repos = event.repo, isLoadingRepos = false) FetchUserLoading -> this.copy(isLoadingUser = true, isErrorUser = false) FetchUserError -> this.copy(isLoadingUser = false, isErrorUser = true) is FetchUserOk -> this.copy(user = event.user, isLoadingUser = false) }
  • 69. ENABLE FUNCTIONAL ARCHITECTURE VIEW STATE REDUCER fun ViewState.reduce(event: Event): ViewState = when (event) { FetchRepositoriesLoading -> this.copy(isLoadingRepos = true, isErrorRepos = false) FetchRepositoriesError -> this.copy(isLoadingRepos = false, isErrorRepos = true) is FetchRepositoriesOk -> this.copy(repos = event.repo, isLoadingRepos = false) FetchUserLoading -> this.copy(isLoadingUser = true, isErrorUser = false) FetchUserError -> this.copy(isLoadingUser = false, isErrorUser = true) is FetchUserOk -> this.copy(user = event.user, isLoadingUser = false) }
  • 70. ENABLE FUNCTIONAL ARCHITECTURE VIEW STATE REDUCER fun ViewState.reduce(event: Event): ViewState = when (event) { FetchRepositoriesLoading -> this.copy(isLoadingRepos = true, isErrorRepos = false) FetchRepositoriesError -> this.copy(isLoadingRepos = false, isErrorRepos = true) is FetchRepositoriesOk -> this.copy(repos = event.repo, isLoadingRepos = false) FetchUserLoading -> this.copy(isLoadingUser = true, isErrorUser = false) FetchUserError -> this.copy(isLoadingUser = false, isErrorUser = true) is FetchUserOk -> this.copy(user = event.user, isLoadingUser = false) }
  • 71. ENABLE FUNCTIONAL ARCHITECTURE VIEW STATE REDUCER fun ViewState.reduce(event: Event): ViewState = when (event) { FetchRepositoriesLoading -> this.copy(isLoadingRepos = true, isErrorRepos = false) FetchRepositoriesError -> this.copy(isLoadingRepos = false, isErrorRepos = true) is FetchRepositoriesOk -> this.copy(repos = event.repo, isLoadingRepos = false) FetchUserLoading -> this.copy(isLoadingUser = true, isErrorUser = false) FetchUserError -> this.copy(isLoadingUser = false, isErrorUser = true) is FetchUserOk -> this.copy(user = event.user, isLoadingUser = false) }
  • 72. ENABLE FUNCTIONAL ARCHITECTURE VIEW STATE REDUCER fun ViewState.reduce(event: Event): ViewState = when (event) { FetchRepositoriesLoading -> this.copy(isLoadingRepos = true, isErrorRepos = false) FetchRepositoriesError -> this.copy(isLoadingRepos = false, isErrorRepos = true) is FetchRepositoriesOk -> this.copy(repos = event.repo, isLoadingRepos = false) FetchUserLoading -> this.copy(isLoadingUser = true, isErrorUser = false) FetchUserError -> this.copy(isLoadingUser = false, isErrorUser = true) is FetchUserOk -> this.copy(user = event.user, isLoadingUser = false) }
  • 73. MORE ABOUT THE DEMISE OF OOP ▸ https://medium.com/@cscalfani/goodbye-object-oriented- programming-a59cda4c0e53
  • 74. MORE MODEL-VIEW-INTENT-PATTERN ▸ Jake Wharton - Managing State with RX ▸ http://hannesdorfmann.com/android/mosby3-mvi-1
  • 75. MORE ABOUT FUNCTIONAL KOTLIN ▸ http://kategory.io ▸ http://kategory.io/docs/quickstart/blogs/