Простая и наглядная демонстрация пользы от типов

22 сентября 2014

Однажды я потратил два дня на поиск и исправление одного идиотского бага. В системе было множество сущностей, которые временами сохранялись в базу и имели id. Были разные функции для работы с этими сущностями. Функции также ходили в базу и зачастую принимали в качестве аргументов id сущностей. Баг заключался в том, что в результате некогда проведенного рефакторинга изменился порядок аргументов и id стали передаваться в неправильном порядке.

Грубо говоря:

#!/usr/bin/env scala

def joinChat(userId: Long, chatId: Long) {
  println(s"userId = $userId, chatId = $chatId")
}

val userId = 123L
val chatId = 456L

joinChat(userId, chatId)
joinChat(chatId, userId)

Код успешно выполняется и выводит:

userId = 123, chatId = 456
userId = 456, chatId = 123

Понятно, что все id-шники представляют собой Long, поэтому компилятор не может обнаружить ошибку. А теперь немного перепишем код:

#!/usr/bin/env scala

class User()
class Chat()
case class Id[A](value: Long)

def joinChat(userId: Id[User], chatId: Id[Chat]) {
  println(s"userId = ${userId.value}, chatId = ${chatId.value}")
}

val userId = Id[User](123L)
val chatId = Id[Chat](456L)

joinChat(userId, chatId)
// joinChat(chatId, userId)

Код стал не намного сложнее (уверен, многие согласятся со мной, что он стал еще и понятнее), но упомянутый баг в нем стало просто невозможно допустить:

./script2.scala:15: error: type mismatch;
 found   : this.Id[this.Chat]
 required: this.Id[this.User]
joinChat(chatId, userId)
         ^
./script2.scala:15: error: type mismatch;
 found   : this.Id[this.User]
 required: this.Id[this.Chat]
joinChat(chatId, userId)
                 ^
two errors found

Две минуты работы могли сэкономить два дня времени, потраченных на поиск и исправления бага. Также благодаря типам вы никогда не сложите возраст с долларами, не сошлетесь на несуществующий URL и не напишите невалидный SQL запрос. Я многие годы работал с динамически типизированными языками программирования и пришел к выводу, что писать на них что-то серьезнее скрипта на 100 строк кода — это боль и унижение. Не повторяйте моих ошибок, пишите на нормальных языках.

Перекрестная ссылка: Так ли плоха статическая типизация?

Дополнение: См также value classes.

Метки: , .

Понравился пост? Узнайте, как можно поддержать развитие этого блога.

Также подпишитесь на RSS, Facebook, ВКонтакте, Twitter или Telegram.