One single authoritative knowledge representation

Duplicated knowledge is harmful because it makes changes expensive. Worse than that, it conceals the code intent. Let's take a look at the following code.

class Person(private val name: String) {

  fun name(): String {
    return name
  }
}

class Job(private val name:String) {

  fun name(): String {
    return name
  }
}

class App {

  fun main() {
    val person = Person("Andrea")
    val job = Job("developer")

    val result = person.name() + " is a " + job.name() //Andrea is a developer
  }
}

Now let's assume we want to have an ellipsis when Person or Job names are longer than 5 characters. One solution could be to modify the name method of both Person and Job like follows.

class Person(private val name: String) {

  fun name(): String {
    if (name.length > 5) {
      return name.substring(0, 5) + "..."
    }
    return name
  }
}

class Job(private val name:String) {

  fun name(): String {
    if (name.length > 5) {
      return name.substring(0, 5) + "..."
    }
    return name
  }
}

class App {

  fun main() {
    val person = Person("Andrea")
    val job = Job("developer")

    val result = person.name() + " is a " + job.name() //Andre... is a devel...
  }
}

In the above code, changing the ellipsis threshold from 5 to 10 characters will affect the name method of both Personand Job classes. Moreover, there is a risk to introduce bugs as changes might not be replicated across both classes by mistake. The problem is that the concept of name is spread across Person and Job instead if being a standalone class like follows.

class Name(private val name: String) {

  fun format(): String {
    if (name.length > 5) {
      return name.substring(0, 5) + "..."
    }
    return name
  }
}

class Person(private val name: Name) {

  fun format(): String {
    return name.format()
  }
}

class Job(private val name:Name) {

  fun format(): String {
    return name.format()
  }
}

class App {

  fun main() {
    val person = Person(Name("Andrea"))
    val job = Job(Name("developer"))

    val result = person.format() + " is a " + job.format() //Andre... is a devel...
  }
}

Now the intent is clearer, making it easier to reason about the code. Furthermore, whenever we need to change something related to the concept of name, only the Name class will be affected.

As a final note, be mindful that knowledge duplication might be there even if the code looks different. The typical example is object-relational mapping libraries and SQL initialisation scripts: who of the two is responsible for the knowledge of database tables creation?


Recommended reads

Teach me back

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