Clarify what is superfluous

Sometimes the you aren't going to need it principle is abused, leading to code that does not pass all tests. This usually happens in the form of assuming specifications. Let's consider the following example where we are required to build a piece of code that:

  • stores fruits by their names
  • does not store a fruit name more than once
  • given a fruit name, returns true if it has been previously stored
class FruitInventory {
  private val fruits = ArrayList<String>()

  fun storeFruit(name: String) {
    if (contains(name))
      return
    
    fruits.add(name)
  }

  fun contains(name: String): Boolean {
    for(fruit in fruits) {
      if (name == fruit)
        return true
    }
    return false
  }
}

The above code works just fine given the specifications. However, we might argue that fruits implemented as a list is not very performant and that we could make both contains and storeFruit faster by simply using a set. It is a mistake to dismiss such thought appealing to the you aren't going to need it principle. In fact, we would be assuming a specification about performance that is currently unknown. We should instead clarify the expected performance of FruitInventory: if it is irrelevant then the code is as good as it is, otherwise we need to change it as follows.

class FruitInventory {
  private val fruits = HashSet<String>()

  fun storeFruit(name: String) {
    fruits.add(name)
  }
  
  fun contains(name: String): Boolean {
    return fruits.contains(name)
  }
}

Performance specifications aside, the above code using HashSet is superior as it better expresses intent. We could even argue that HashSet approach satisfies the specifications just fine and we aren't going to need all the for-loop complexity introduced by the ArrayList approach.


Recommended reads

Teach me back

I really appreciate any feedback about the book and my current understanding of software design.