State - How do we deal with it?

Me 🕶️

Mobile Enthusiastic 📱🍭

💖 Kotlin & Swift + Open source software

Works at Mercari (Merpay division) in Tokyo 🗼


State - what is it?

State = Abstraction

Programming is all about abstraction

Programming uses language to solve problems


  var x: Int? = 10 //variable is state

  x = 15 //update state

  x++ //mutate state

  x = null //"clean up" state

More example

  //somewhere in your project

  data class JobCategory(
    val id: String,
    val title: String,
    val subs: List<JobSubcategory>

  data class JobSubcategory(
    val id: String,
    val title: String,
    val coverUrl: String

State is EASY 🍌

Using state, just assign/update value

One knows how to use it

But .... easy  simple

State is COMPLEX 🙄 

Unpredictable ...

Race conditions ...

Hard to write tests ...

Familiar or approachable



Fewer concepts / not complex to understand



More example

More on this!

  // in your class, you have this variable
  var isHeaderAdded: Boolean = false

  // in your class, you have this sort of function
  fun updateItemCount(count: Int) {
  // inside updateItemCount
  fun updateItemCount(count: Int) {
    if (isHeaderAdded) {
      val header = getHeaderView()

      if (itemCount == 0) {
        isHeaderAdded = false
      } else {
    } else if (itemCount > 0) {
      val header by lazy { HeaderView() }

      isHeaderAdded = true

This kinda work™

Brittle, it looks !@#$%^&* but hard to maintain 🙀

Hidden context! - header is added or not 🔬

Hard to test, no resistant to change 👴 

So, solution💡

Type = proof = prevent errors

Programmer tends to make errors

We need something to restrict what you can do


Type gives you the hidden context

Type Proves
ByteArray Nothing much
String String - list of Chars, not just random bytes
URL String reprsents URL, not just random list of Chars


interface List<out E> {
  abstract val size: Int

  abstract operator fun contains(element: E):

  abstract fun containsAll(elements: Collection<E>): 

  abstract operator fun get(index: Int): E

  abstract fun indexOf(element: E): Int

  abstract fun isEmpty(): Boolean
  abstract operator fun iterator(): Iterator<E>

  abstract fun lastIndexOf(element: E): Int

  abstract fun listIterator(): ListIterator<E>

  abstract fun listIterator(index: Int): 

  abstract fun subList(fromIndex: Int, toIndex: Int): 
interface MutableList<E> : List<E> {
  fun add(element: E): Boolean

  fun add(index: Int, element: E): Unit

  fun addAll(index: Int, elements: Collection<E>):

  fun addAll(elements: Collection<E>): Boolean

  fun clear(): Unit

  fun listIterator(): MutableListIterator<E>

  fun listIterator(index: Int): MutableListIterator<E>

  fun remove(element: E): Boolean

  fun removeAll(elements: Collection<E>): Boolean

  fun removeAt(index: Int): E

  fun retainAll(elements: Collection<E>): 

  operator fun set(index: Int, element: E): E

  fun subList(fromIndex: Int, toIndex: Int): MutableList<E>

List<E> is more restricted than Mutable<E>

List<E> is prevents you to expose to more errors comparing to Mutable<E>


  // in your class, you have this variable
  var isHeaderAdded: Boolean = false

  // in your class, you have this sort of function
  fun updateItemCount(count: Int) {
  sealed class Content<ViewType, T> {
    data Empty(val empty: ViewType) : Content()
    data Value(list: List<T>, val header: ViewType) : Content()

  // usage
  when (content) {
    is Content.Empty -> {
      addHeaderView(content.empty) // smart cast :hooray:
    is Content.Value -> {
      // update your view with value

Validated<T, E>

 sealed class Validated<T, E> {

   class Valid(value: T)
     : Validated()
   class Invalid(errors: List<Exception>)
     : Validated()

   companion object {
     fun error(e: Exception) = 

   var isValid 
     get() = when(this) {
       is Valid -> true
       is Invalid -> false
 sealed class InputError : Throwable() {
    data class WrongFormat(reason: String) : EmailError()
    object Length : EmailError()

 fun validateEmail(email: String): 
   Validated<Email, EmailError> =
   if (email.contains("@")) 
   else error(InputError.WrongFormat("🙅‍♂️"))

 fun validateName(name: String): 
   Validated<Name, Exception> = 
   if (name.isEmpty().not()) 
   else error(InputError.Length)

RemoteData<T, E>

Represents a state of data that will be coming in the future

Eventually be either success or failure 

Captures Loading state as well

RemoteData<T, E>

Not Asked


Success(value: T)

Failure(error: E)


"Type" is your best friend, use them A LOT

Kotlin sealed class is one of them most underrated feature

Don't overuse them, understand and use where it makes sense

Q & A 🙋