Тестирование — это еще не все, но это важно

Доклад, о котором я думал в последнее время, — это доклад Гэри Бернхардта, который называется Идеология. Я настоятельно рекомендую вам пойти посмотреть его сейчас, если хотите, я подожду здесь. В противном случае, вот 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 и продолжил свой путь.
Если бы мы использовали какие-то проверки типов сообщений, это упражнение по отладке было бы намного проще.

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

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *