Доклад, о котором я думал в последнее время, — это доклад Гэри Бернхардта под названием Идеология. Я настоятельно рекомендую вам пойти посмотреть его сейчас, если хотите, я подожду здесь. В противном случае, вот tl;dr: энтузиасты динамической типизации любят говорить, что им не нужен компилятор, так как у них есть тесты; энтузиасты статической типизации любят говорить, что им не нужны тесты, поскольку у них есть компилятор.

По моему опыту, первое утверждение встречается гораздо чаще, чем второе, редко можно услышать, как люди, которым нравятся статические типы, говорят, что им не нужны модульные тесты. Может быть, в прошлом все было иначе; в какой-то момент истории инженеры Google заявили, что модульные тесты нужны только плохим кодерам, но с тех пор они оказались неправы, и теперь Google жестко принуждает к тестированию всего своего кода.
То, что я иногда слышу от энтузиастов таких языков, как Node.js, Python или Ruby, заключается в том, что им на самом деле не нужна безопасность и структура, обеспечиваемые компилятором, поскольку у них есть наборы модульных тестов, которые отлавливают ошибки.

Это вредная философия. В некоторых случаях это не страшно, когда ошибки на самом деле не имеют значения: на ранних стадиях стартапы ошибки имеют ограниченное влияние, потому что у вас либо вообще нет клиентов, либо клиенты терпимы к проблемам. Вы можете позволить себе пропускать ошибки, так как преимущество возможности быстро двигаться и вносить изменения перевешивает стоимость доставки ошибок.
К сожалению, это меняется по мере роста стартапа, а ошибочный код и регрессивные ошибки приводят непосредственно к оттоку клиентов. . Это усугубляется тем, что по мере усложнения программного обеспечения и увеличения размеров команд вероятность создания ошибок возрастает очень быстро. Если вы ничего с этим не сделаете, команды в конечном итоге окажутся в ситуации, когда они будут просто тушить пожары, а не создавать продукт.

«Но если бы у вас был хороший набор тестов, этого бы не произошло!» утверждают многие разработчики. Разве тестирование недостаточно качественное и не выявит ли мои ошибки, если они есть? Есть много способов, которыми ошибки могут проскользнуть мимо тестов, вот несколько примеров. Каждый из них я видел в профессиональной среде, в том числе в Google, где очень строгие стандарты кодирования:

  • Тесты, которые ничего не проверяют. Тест может выполнить код и получить 100% покрытие кода, но если он не проверяет правильные условия, то это плохой тест.
  • Их изначально никто не писал. Иногда, когда нужно что-то исправить, люди пропускают написание тестов. Во многих компаниях существует культура, ориентированная на максимально быструю доставку, что не способствует написанию надежного программного обеспечения.
  • Не проверять важные дела. Я видел тесты, которые просто проверяют счастливый путь, не проверяя ни одного из сценариев ошибок — что, если вы не можете подключиться к базе данных или соединение обрывается? Что делать, если файл, который вы пытаетесь прочитать, отсутствует?
  • Интеграционные/функциональные тесты. По своей природе интеграционные тесты сложнее писать и поддерживать, а количество входных данных растет экспоненциально, поэтому очень редко можно иметь надежный набор интеграционных тестов за пределами абсолютно важных проектов.
  • Никто не запускал тесты и не смотрел на результаты перед отправкой. Это происходит в настройках, где нет никаких процессов (я смотрю на вас, стартап-хакеры), где неудачные тесты блокируют коммиты/слияния/пуши.

Есть несколько решений для них. Некоторые из них довольно просты и широко распространены: проверка кода, непрерывная интеграция, перехватчики перед фиксацией и строгие разрешения на основные ветки — это лишь некоторые из них.

Более глубокое решение, уменьшающее головную боль, — это использование подсказок типов. Причина, по которой я рекомендую это, заключается в том, что если вы используете его последовательно, это устраняет много человеческих ошибок из уравнения — компилятор всегда не забывает проверять все, в то время как даже самые лучшие люди иногда споткнуться и что-то забыть. Компилятор также намного быстрее находит ошибки, в то время как выполнение наборов интеграционных тестов может занять очень много времени — исходя из эмпирического правила, я не блокирую коммиты в интеграционных тестах, иначе внесение изменений может занять несколько часов. Это также автоматически: вам не нужно писать тесты. Меньше работы — это плюс в моих книгах.

Но должен ли я использовать для этого один из этих раздражающих языков, таких как C++ или Java, где я трачу все свое время, пытаясь удовлетворить компилятор, а не выполняя реальную работу? Неа! Вы можете использовать это в Node.js с компилятором TypeScript или Google Closure, в Python вы можете использовать объявления типов Python 3, а в Ruby вы можете использовать что-то вроде RDL (отказ от ответственности, я никогда не использовал его). Существуют также современные языки со статической типизацией, такие как Go, Rust, Swift и Kotlin, которые гораздо приятнее в использовании, чем предыдущие поколения.

Для связи между различными системами вы можете использовать JSON со схемой JSON или буферами протокола (которые при необходимости могут быть сериализованы как JSON). Страшная история из прошлого: моя команда строила распределенную систему с Node.js и Python, и разные узлы в системе передавали сообщения через JSON. Кто-то внес изменение в одну систему, изменившее тип поля в одном из сообщений, но прошло несколько прыжков, прежде чем что-то действительно попыталось получить доступ к этому полю. Система, которая пыталась получить к нему доступ, очевидно, дала сбой, и отслеживание того, где это поле было изменено, потребовало немало детективной работы (в дополнение к простою производства).
К счастью для нас, сбой произошел в Python. системы, поэтому у нас была KeyError и трассировка стека, чтобы хотя бы иметь представление о том, что происходит, если бы это произошло в одной из систем Node.js, она бы только что произвела undefined и продолжила свой путь.
Если бы мы использовали своего рода проверку типов сообщений, это упражнение по отладке было бы намного проще.

Я настоятельно рекомендую, если вы занимаетесь какой-либо внутренней или инфраструктурной разработкой и еще не используете некоторые из этих методов, вы должны начать. Позже это избавит вас от головной боли.

Первоначально опубликовано на www.codementor.io.