morristech
4/12/2017 - 6:00 AM

Companion code to https://medium.com/p/2c1687173c7c

class TemporalCoupling {

    fun incorrectUsageOfBadApi() {
        val badApi: BadApi = BadApi()

        badApi.username = "Zak"
        badApi.password = "temporalCouplingIsBad_123"
        badApi.login() //throws an NullPointerException
    }

    fun correctUsageOfBadApi() {
        val badApi: BadApi = BadApi()

        badApi.username = "Zak"
        badApi.password = "temporalCouplingIsBad_123"
        badApi.url = "http://my-endpoint.com"
        badApi.login() //works
    }

    fun correctUsageOfGoodApi() {
        val goodApi: GoodApi = GoodApi(url = "http://my-endpoint.com")
        //hard to call this function incorrectly
        goodApi.login(
                username = "Zak",
                password = "temporalCouplingIsBad_123"
        )
    }

    class GoodApi(private val url: String) {

        fun login(username: String, password: String) {
            NetworkCall(url, username, password).execute()
        }
    }

    class BadApi {
        var url: String? = null
        var username: String? = null
        var password: String? = null

        fun login() {
            NetworkCall(url!!, username!!, password!!).execute()
        }
    }

    data class NetworkCall(val url: String, val username: String, val password: String) {
        fun execute() {
            //does nothing..
        }
    }
    
    data class Password(val password: String) {
        init {
            if (password.length < 10) {
                throw IllegalStateException("Password must be at least 10 characters")
            }
        }
    }
}