Do not abstract by visual pattern matching

Two pieces of code that are identical but represent two distinct concepts should stay separated: they are not duplication. Let's consider the example where we are asked to calculate the perimeter of rectangles and rhombuses.

class Rhombus(private val width: Int, private val height: Int) {

  fun perimeter(): Int {
    return 2 * (width + height)
  }
}

class Rectangle(private val width: Int, private val height: Int) {

  fun perimeter(): Int {
    return 2 * (width + height)
  }
}

When seeing a piece of code like the above, one might be tempted to remove the duplication of the perimeter method like follows.

class Shape(private val width: Int, private val height: Int) {

  fun perimeter(): Int {
    return 2 * (width + height)
  }
}

However, what happens if after some time we are asked to calculate the perimeter of a circle? Now the concept represented by Shape does not relate to circle, which is definitely a shape though. There are many ways to refactor this situation, for instance making shape an interface, but in a large codebase these refactorings are more expensive than leaving duplicated code until we understand it is duplicated knowledge. It is hard to build the right knowledge model, especially if specifications are not entirely known or the domain is complex. In doubt, the rule of thumb is to remove duplication only after it occurs more than two times.


Recommended reads

Teach me back

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