Kotlin Code Smell 14 - Anonymous Functions Abusers

Kotlin Code Smell 14 - Anonymous Functions Abusers

Closures in Check: Enhancing Code Maintainability

TL;DR: Avoid excessive use of closures and functions. Encapsulate them within objects.

Problems

  • Maintainability

  • Testability

  • Code Reuse

  • Implementation Hiding

  • Debugging

Solutions

  • Wrap functions/closures

  • Reify algorithms using a method object / Strategy pattern

Sample Code

Wrong

fun sortFunction(
    list: MutableList<Int>,
    fn: (Int, Int) -> Boolean
) {
    for (i in list.indices) {
        for (j in 0 until list.size - i - 1) {
            if (fn(list[j], list[j + 1])) {
                val temp = list[j]
                list[j] = list[j + 1]
                list[j + 1] = temp
            }
        }
    }
}

fun main() {
    val scores = mutableListOf(9, 5, 2, 7, 23, 1, 3)
    sortFunction(scores) { a, b -> a > b }
}

Right

class ElementComparator {
    fun greaterThen(firstElement: Int, secondElement: Int) =
        firstElement > secondElement

    // This is just an example. With more complex objects,
    // this comparison might not be so trivial...
}

class BubbleSortStrategy(
    private val elements: MutableList<Int>,
    private val comparator: ElementComparator
) {
    // We have a strategy; we can unit test it, change it to a
    // polymorphic implementation, or benchmark different algorithms, etc.
    fun sort() {
        for (i in elements.indices) {
            for (j in 0 until elements.size - i - 1) {
                if (comparator.greaterThen(elements[j], elements[j + 1])) {
                    swap(j)
                }
            }
        }
    }

    private fun swap(index: Int) {
        val temp = elements[index]
        elements[index] = elements[index + 1]
        elements[index + 1] = temp
    }
}

fun main() {
    val scores = mutableListOf(9, 5, 2, 7, 23, 1, 3)
    BubbleSortStrategy(scores, ElementComparator()).sort()
}

Conclusion

Humans read code, and while software can handle anonymous functions, maintainability suffers when multiple closures are used. By extracting functionality into objects, we can improve code reuse and maintainability.

Credits

Did you find this article valuable?

Support Yonatan Karp-Rudin by becoming a sponsor. Any amount is appreciated!