Как стать автором
Обновить

Комментарии 100

На текущий момент, используя тесты около 8 лет, с разной интенсивностью, могу сказать следующее: Имеет смысл покрывать тестами только переиспользуемый код. Какие-то функции ядра вашего приложения. То, что вызывается из множества мест вашего приложения. Или тестом стоит фиксировать сложно уловимый баг.
Конечный код, который формирует http ответ, или рисует гуй или ещё что-то тестировать смысла нет. И вот теперь почему:
1. Тесты это действительно код, и код которые требует затрат на содержание.
2. Количество тестов растёт. И затраты на них тоже. Часто можно обнаружить что тесты растут быстрее самого приложения. Мы очень редко удаляем код, в тесты удаляются ещё реже. Когда есть тысяча работающих тестов, никто не пойдёт удалить 500 из них. Да, начинается деление на сьюты постоянных и страховочных, но затраты на содержание никуда не уходят.

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

Поддерживаю по всем тезисам. И это всё — собственно, собирательная причина того, что TDD сложно назвать каким-то другим словом, кроме как "культ". Действительно, хорошие и полезные тесты — хороши и полезны, но на их создание уходят значительные усилия, и покрытие такими тестами будет скорее всего сильно меньше 100% (но покрытие — вообще не тот параметр, за которым следует гнаться). Все остальные тесты — как минимум немножечко вредят, а не помогают. Как максимум — вредят очень сильно. Например, толстая пачка посредственных тестов, порожденных адептом TDD при написании кода — вредит немножечко, но стоит только эту пачку поддерживать вдолгую — и она уже начинает вредить сильно, отжирая время на поддержку, обновление, перестановку всех граничных случаев, и т.д.

Согласен. Примерно в каждой интересной статье на эту тему пытался задавать адептам вопрос — а считали ли вы деньги на разработку и поддержку тестов, а спрашивали ли вы заказчика, который вам оные деньги дает, на что лучше их потратить, на тесты, или на развитие функциональности?

И очень редко когда люди применяют TDD, и при этом задают себе подобные вопросы, считают деньги и меряют усилия. А тесты — это инструмент, причем инструмент не единственный (ну, собственно частично об этом и данный пост). Его применение нужно оценивать.
а считали ли вы деньги на разработку и поддержку тестов, а спрашивали ли вы заказчика, который вам оные деньги дает, на что лучше их потратить, на тесты, или на развитие функциональности?


а если продолжить…
— а считали ли вы, сколько времени затрачивается на систему контроля версий, бранчи, слияния, пул-реквесты и т.д. и готов ли заказчик за это платить?
— а считали ли вы, сколько времени затрачивается на условный jenkins, его интеграцию с cvs, настройку и т.д. и готов ли заказчик за это платить?
— а считали ли вы, сколько времени затрачивается на условный elk, его настройку, сопровождение и т.д. и готов ли заказчик за это платить?
— …

И дальше продолжаем по аналогии:

И очень редко когда люди применяют <подставить по вкусу>, и при этом задают себе подобные вопросы, считают деньги и меряют усилия. А <подставить по вкусу> — это инструмент, причем инструмент не единственный (ну, собственно частично об этом и данный пост). Его применение нужно оценивать.
Ну да, можно продолжить. Вообще, имеет ли место культ вокруг TDD — вопрос тонкий. Как мы видим прямо тут — есть люди, которые про это думают, и наверное культ этот не всеобщий.

Минус не мой, если чо, хотя я с такой постановкой и не согласен. Смысла в таком обобщении не очень много, на мой взгляд.
имеет ли место культ вокруг TDD
Работал я как-то в одной крупной международной компании, разрабатывавшей 10+ лет систему управления резервным копированием, и там в то время заказали внешней консультационной фирме оптимизацию процесса SCRUM-разработки. Внешняя фирма тщательно разработала SCRUM-процедуры и структуру SCRUM-команд, только её разработки никак не учитывали специфику работы компании-заказчика в виде обработки реквестов «повышенной срочности» от заказчиков на исправление ошибок, оптимизацию, доработку и новую функциональность (это были в основном крупные корпоративные заказчики, если что) в части выделения на это человеко-часов. Но несколько миллионов долларов за работу были уплачены.

Осмыслив это, я понял, что культы модных методик и технологий — это, кроме прочего, прибыльная сфера по части преподавания и консультаций, так что такие культы всегда будут надуваться и поддерживаться.
Я практически не сомневаюсь, что и такое тоже есть.
Вы знаете, задаются такие вопросы. И конкретно в моём случае в текущий момент система контроля версий есть, бранчи и слияния есть, а пул реквесты — нет.
Jenkins используется, а elk нет. Это в этом проекте. А кое где и дженкинса нет. Потому что не каждая возможность должна быть реализована. А вы устанавливаете следилку за монитором сотрудника или нет? А СБ проверяет до 10 колена всех? А ТРИЗ внедряете? А канбан одновременно со скрамом используете?
И очень редко когда люди применяют <подставить по вкусу>, и при этом задают себе подобные вопросы, считают деньги и меряют усилия.

Возможно что-то не так в вашем окружении, потому что в бизнесе, перед тем как что-то использовать считают деньги и меряют усилия постоянно.
а пул реквесты — нет.


А как тогда вы проводите рецензирование кода? Вообще ситуации бывают совершенно разные — в одной фин. конторе рецензирование проводят постфактум (после слияния). И ничего, живут так давно.
Хотите ужасную информацию? Я написал про проект который сделали три сеньёра и мы не ревьювили код друг друга вообще. Мы его просто написали. И да, это большой проект на 4 года, на несколько сотен тыс строк кода. Правильно ли это? Проект сдан в срок и в бюджет. Был ли шанс провала — был. Как и везде вопрос цены и затрат.
Ничего ужасного. Я просто думал, что вы как-то по-другому делаете. Рецензирование нужно только если оно помогает найти ошибки. Если оно их не находит, то это просто трата времени.

Я последние пару лет очень много занимаюсь этим и вижу, что да, раз в 5-10 PR'ов что-то нахожу, что следует исправить — народ соглашается. Если бы не находил, то перестал бы проверять тем или иным образом.

Я не считаю нужным исправлять кож который работает но не идеален, и даже может немного нептимален. Это вцелом. А тут конкретно мы иногда "ревьювили" друг друга на словах обсуждая архитектуру, а потом садились и делали.

Я писал пару проектов один. И никто это не смотрел - некому было. Однако результат как у вас, сдано и работает. Мораль простая - главное без фанатизма.

Да, и тестов не было, кстати. Три года

Но система контроля версий всё же была?
Да, я же не робот. Mercurial, например.
Я не про то, робот или нет, я про систему относительно централизованного хранения кода.
Ну, я говорил про то, что мне же иногда откат нужно сделать. Да и ветку завести. Или дифф скажем посмотреть. Поэтому даже в проекте, который делает один человек, версионирование более чем осмысленно. Ну и если это в проекте на компанию — то обычно централизованное.
В старых проекта, начинавшихся на каких-то ДВК, никаких систем контроля версий не было. Очень жаль, конечно.
Пост-рецензирование — вещь хорошая, однако что там делалось, если это пост-рецензирование выявляло ошибки?
Исправлять ошибки, разве нет? Точно также как и когда баг всплывает на предрелизном тестировании мастера или в продакшне.
Ну, как бы считается, что баг, найденный после коммита, обходится дороже, чем баг, найденный до коммита, хотя и всё равно меньше, чем баг, найденный тестером.

Да, но сравнивать их надо не между собой а со стоимостью комплекса мероприятий по их предотвращению помноженной на реальную эфективность таких мероприятий.

Тут шутка в том, кто платит за это «обходится дороже», а кто платит за рецензирование.

Это разные люди, поэтому если они ведут себя как «экономически рациональные субъекты» (это хорошее приближение для описания людей), то рецензировать не выгодно => все пытаются оттянуть это как можно дальше => затягивают сроки вывода изменения в PROD.

Вообще теория игр как нельзя лучше подходит для описания работы больших контор. «Прикладная политика».
Ну да, исправляли ошибки — я сразу же задал ровно этот же вопрос. Да, постфактум — когда код уже на Альфе/в Testing. Они решили, что лучше так, чем задерживать изменения на день/другой.

Учтите, что рецензирование в таких конторах «не оплачивается» — вы просто тратите своё время на помощь коллегам. Для руководства же вы просто продолбали время.
Они решили, что лучше так, чем задерживать изменения на день/другой.
Тоже довод. Заодно большая «гранулярность».
И конкретно в моём случае в текущий момент система контроля версий есть, бранчи и слияния есть

Ок, значит вы уже посчитали, сколько вам проносит пользы использование cvs.
Поделитесь, сколько денег сэкономили заказчику?

Также про jenkins. Заказчик знает сколько денег экономит, используя jenkins?
Правилами хорошего тона не рекомендуется озвучивать какие-бы то ни было суммы качающиеся заказчиков. Естественно до цента это никто не считал. Но усреднённую стоимость ошибки в продакшне за год считали, в баксах, и примерно с ней сравнивается стоимость операций по попытке её недопущения.
Заказчик знает сколько денег экономит, используя jenkins?
<сарказм>
Заказчик знает сколько денег экономит конкурентам, используя jenkins?
</сарказм>
Аналогия выходит за границы применимости.

Система контроля версий и условный Jenkins — это фактически внешняя коллективная часть IDE, и они требуют времени только во время установки и настройки, а дальше его сильно экономят. Выбор «на что потратить деньги — на развитие функциональности или на систему контроля версий» вообще никогда не стоит: затраты времени несопоставимы, это как «купить автомобиль или пачку сигарет».
Спасибо.

А почему ядро приложения более важно, чем не-ядро? Если повалится что-то в не-ядре, Вы пользователю тоже вот так объясните? :)

Потому что когда отвалилось ядро отвалилось множество функций (одноразовому коду в ядре делать нечего) и часто приложение неработоспасобно или существенно деградировало, а когда отпала одна функция приложения ничего критичного с бизнесовой точки зрения как правило, не происходит, как отпало так и починим. В полном соответствии с принципом graceful degradation. Мы всё равно не умеем делать приложения без ошибок, даже НАСА и банки не умеют. Но если посмотреть на стандарты написани кода на плюсах в НАСА, которые безусловно сильно снижают шанс на ошибку, то застрелиться так писать, это очень дорого. И проект где я работаю не смог бы окупить разработку по стандартам наса, а если бы это и сделал то не заработал бы больше. А всё потому что разработка это про деньги.

Если разработка это про деньги, то это как раз повод чтобы делать хорошо, нет? Я не знаю о стандартах NASA, я знаю только о процессах Amazon/Google. И Google предпочитает делать хорошо — и если на тесты нужно время, значит нужно его запланировать.


ИМХО ссылаться на graceful degradation, как на оправдание забиванию на тесты, несколько все же странно.


А почему Ваш проект не позволяет вложить чуть больше времени в достижение более-менее сносного покрытия юнит тестами (ну хотя бы >80%, хотя это очень мало)?

Зачем? Это не позволит ему больше зарабатывать. Есть очень много очень глючных продуктов которые зарабатывают. Мой не самый глючный. Но в вопросе тестов мир не бинарен, есть или нет. Вопрос сколько. Это тоже самое сколько безопасности должно быть в машине. И ответ "вся" не подходит. Потому что пятиточечные ремни точно безопаснее чем трёхточечные, но их никто не будет использовать. И вообще безопаснее не выезжать из гаража. И поэтому каждый ищет некое своё среднее. Общие стандарты растут, но низкобюджетные можели как были существенно менее безопасны чем лендровер, вольво и мерседес так и остаются. И всё это на рынке. И роллсройс например концы с концами не сводит, хотя очень безопасен. Возможно, трать они на это чуть меньше сил, как продукт они были бы незначительно хуже, а как бизнес значительно лучше.

Вопрос, почему продукт не сводит концы с концами, может быть вообще не связан с технической частью. Может быть фейл маркетинга и т.д.
И про "бинарность" я не говорил.
Про гараж вообще сравнение, простите, не в тему. Конечно, безопаснее вообще не писать код и не разрабатывать продукт, тогда и багов не будет, но я-то ратовал, наоборот, за обратное.
А что, если не секрет, у Вас за проект?:)

Онлайн и мобильные игры.

Кстати, а мутационное тестирование пробовали? Вот это, имхо, близко к абсолютному качеству тестов. Хотел бы я на такой проект посмотреть и может поработать, узнать как там со скоростью разработки и гибкостью.

Оно, кмк, слишком тяжеловесно. Возможно тогда проще Agda начать применять. И Coq. По крайней мере, по ним есть специалисты, которых можно всегда допросить.

О, вот мы и нащупали вашу точку баланса, сколько тестов надо :) у меня она просто в сторону меньшего количества тестов сдвинута.

У меня, как и у вас нет единой точки баланса, всё зависит от проекта. Но они в любом случае не попадают в mutation testing. По крайней мере сейчас. :-)

Но извините, я встрял в вашу беседу с vyakhir29.

Нет не приходилось. :) Как-то все в компаниях, где я работаю, принято unit & integration тесты и все (ну и load тесты, конечно). И плюс сложная система деплоя в связке с метриками и алармами — все вместе это дает довольно надежный Continuous Delivery с минимумом откатов.

И я утверждаю что покрыть тестами 80% кода займёт больше времени чем его написать. А это очень много.

Конечно больше, разве я спорю. Просто имхо это неплохо, но это, очевидно, вопрос вкуса, времени и традиций разработки в каждой компании.

Вот с этим согласен. Это во многом вопрос традиции конкретной команды. Просто на заре своего пользования тестами я думал что тестов или нет, или надо покрывать всё на 100%. И по моему опыту оказалось что это сильно не так, и, собственно описал опыт.

А почему Ваш проект не позволяет вложить чуть больше времени в достижение более-менее сносного покрытия юнит тестами (ну хотя бы >80%, хотя это очень мало)?


Даже 100% покрытие не покрывает все пути выполнения. См. пример в статье. Полное покрытие путей может быть только если мы используем property testing, то есть, гоняем Монте-Карло, и количество задаваемых параметров обозримо. Тогда да,
мы получаем сообщение от G∀ST:

[["«propertyEQ» Proof: success for all arguments after 127 tests


Но обычно поле параметров слишком велико, поэтому доказательство невозможно даже за сутки прогона теста.

Это означает, что, как правило, мы должны принять волевое решение по прекращению работы над тестами. А для принятия этого решения необходимо взвешивать все плюсы тестирования и минусы, а потом прикидывать, где оптимум.
И оптимум сильно зависит от поля, в котором работает команда.

А нет цели покрыть все пути. Есть цель — снизить вероятность ошибки в продакшне. И еще, как я сказал выше, юнит тесты — отличный способ проверить, не совсем ли плохо написан тестируемый код.

Есть цель — снизить вероятность ошибки в продакшне.


Тогда возвращаясь к Вашему комментарию внизу:

1. Я сторонник того, что у нас есть много разных инструментов отфильтровывания ошибок. Они, в общем, образуют конвейер фильтрации.

2. Очень важно поставить эти инструменты в правильном порядке. Например дешёвые и грубые фильтры должны стоять вначале. А тонкие, но дорогие — в конце.

3. Для этого очень важно знать цену каждого инструмента. Вот на это и направлена статья.

Все верно, и я со всем согласен. Но юнит тесты обнаружат ошибку раньше чем все остальные инструменты. Я не понял аналогию с тонкими и грубыми фильтрами: разные инструменты отличаются вовсе не грубостью, а подходом. Интеграционные тесты не более и не менее грубые чем юнит — они другие. Но обнаружить ошибку юнит тестом выйдет дешевле чем интеграционным.
Лоад тесты тоже не более грубый и не более тонкий — они тестируют другое.

Но юнит тесты обнаружат ошибку раньше чем все остальные инструменты.


Компиляция раньше. Например, в коде

-- Наша мегафункция
eitherString :: Either String -> String
eitherString e = case e of
     Left s -> s

-- Конец нашей мегафункции


компилятор скажет, что пропущен второй вариант.

Несомненно. Но компилятор ловит синтаксические ошибки, а тут-то разговор идет больше о логических.

Система типов функциональных языков ловит и массу логических. Собственно в коде выше ошибка именно логическая.

Но и помимо компиляции в наших руках масса лёгких инструментов: простая пошаговая отладка, self-code-review, линтеры, анализаторы уровня Coverity, отладочная печать, блок-схемы на бумажке, обсуждение с товарищем. И наверняка я что-то забыл.
Но юнит тесты обнаружат ошибку раньше чем все остальные инструменты.

Это так
А нет цели покрыть все пути. Есть цель — снизить вероятность ошибки в продакшне.

это тоже так
Но обнаружить ошибку юнит тестом выйдет дешевле чем интеграционным.

если говорить про «обнаружить» то дешевле.
А потом мы можем попробовать сравнить две ситуации:
1. У нас есть только acceptance и integration тесты, но нет юнит тестов, и мы все баги будем ловить чуть позже.
2. У нас есть unit, acceptance, integration тесты и мы ловим ошибку раньше.
Так вот стоит сравнить стоимость содержания и написания unit тестов со стоимостью исправления бага после выявления его на acceptance или integration стадии. И внезапно может отказаться что более дорогое исправление багов в год в сумме может быть дешевле чем содержание юнит тестов. А может и не быть. И решать это команде и любой из этих подходов приемлем.
P.s. Почему-то среди программистов гораздо больше любят даже огромные предсказуемые затраты чем непредсказуемые. Это далеко не лучшая стратегия на рынке. Очень часто ограниченные и оценённые заранее непредсказуемые потери может быть дешевле просто оплачивать, чем содержать системы по их предотвращению. Это ровно то, почему супермаркеты в итоге выгоднее, хотя очевидно, сделай как в старых магазинах, где всё за прилавком и всё тебе подаёт продавец и краж от посетителей будет меньше. Но это не выгодно. Ещё очень много про принятие потерь и работу с ними можно почерпнуть из военной истории.
Это так


Это не так — вы сперва компилируете, а потом пишете тесты, или нет?

Когда как. Red green refactor иногда бывает но не постоянно. И да компилятор ккк я понимаю был все этих инструментов. Если сюда упоминать копилятор то я всенепременно за достаточно жеский компилятор, но не абсолютно. Я не фанат раста или других жестких языков.

Я, всё-таки, хотел бы зафиксировать то, что у нас есть разные инструменты для поиска ошибок, которые стоят в конвейере и до, и после тестов (это справедливо и для юнит-тестов, и для интеграционных). Например, компиляция с её предупреждениями и ошибками (даже компиляторы такого сложного языка, как С++ дают сейчас очень хорошую диагностику).

Какие-то фильтры ошибок, конечно, можно переставлять в конвейере цикла разработки — если тесты уже написаны, разумно их запустить перед self-review или прогоном линтера.

Поэтому ультимативное утверждение, что юнит-тесты — это первичный фильтр ошибок, в корне неверно. В некоторых ситуациях может быть, но как правило, они где-то посередине цепочки.
Это то да. Я о том что из набора инструментов по поиску ошибок, далеко не всегда нужно применять все сразу и на все 100%. У всего есть цена, и иногда цена выше профита. Очень часто в статьях про тесты и TDD говорится что тесты это невероятно крутой инструмент который без затрат принесёт вам только благо. Так вот это не так, у них есть цена, про которую адепты успешно забывают. И цена то только в момент когда вы пишете тест. И цель этой статьи и моих рассуждений не сказать «тесты говно», а сказать что у тестов есть цена и нужно взвешивать и подбирать инструмент под задачу, а не слепо применять весь инструмент что доступен.
Почему-то среди программистов гораздо больше любят даже огромные предсказуемые затраты чем непредсказуемые.
Это типично менеджерский подход.
У нашего проекта порядка сотни пользователей. И у каждого из них есть свои особенности. Если сломано что-то не в ядре, то часть пользователей этого просто не заметит, потому что они часть фич не применяют (если совсем просто — мы поддерживаем Oracle и MS SQL, если представить, что поддержка MS SQL вдруг совсем сломана — это будет означать лишь, что процентов 10 пользователей не сможет эту версию использовать). Но для остальных 90% она будет полностью работоспособна. Это синтетический пример, но близкий к реальности.

А ведь время итерации write-check-correct loop — это важнейшая характеристика, напрямую влияющая на производительность программиста.

Так а что вы предлагаете использовать вместо тестов если я хочу получить этот check?

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

Соответственно, после компиляции программы на том же Haskell/Ocaml уже очень мало чего надо проверять тестами => их становится мало => их неприятные побочные эффекты уже не страшны. К сожалению, это не очень хорошо работает с вычислительными задачами, где почти всё типа Double. :-(
То есть, они должны находиться в конвейере после системы типов, а не вместо неё

При написании кода возможны, условно говоря, 100 единиц проблем.
Система типов выделяет из них, условно говоря, 5 единиц.
При этом стоит, условно говоря 80 руб за единицу.


Система тестов выделяет, условно говоря, 80 единиц проблем (и выделяемые типами входят в эти 80)
При этом стоит 20 руб за единицу


Это мои эмпирические наблюдения

НЛО прилетело и опубликовало эту надпись здесь
А как на Агде работать с численными алгоритмами? Скажем, вычисление квадратного корня
sqrt :: Double Double Double -> Double
sqrt eps x r
   | abs (r * r - x) < eps = r
   | otherwise = sqrt eps x ((r + x/r)/2)


Там же всё имеет один тип.
НЛО прилетело и опубликовало эту надпись здесь
Вообще вещественная арифметика ­— одна из самых неприятных для работы вещей что в пруфассистантах, что во всяких SMT.


Да, насколько я знаю. Поэтому пока мне кажется разумным именно гонять разные Монте-Карло ­— в моём случае G∀ST. Конечно, очень неудобны Double ­— все эти граничные случаи и т.д. Я в какой-то момент для полиномов стал использовать поля Галуа ­— они хороши тем, что это совершенно нормальные числа, без каких-либо потерь точности (надо написать по этому поводу маленькую заметку). Но зато у них нет упорядочения. :-( То есть, < не работает.

Вообще идея полиморфных вычислительных алгоритмов мне кажется богатой. В принципе, понятно, как использовать в разных алгоритмах рациональные/алгебраические числа для их тестирования. А ещё полиморфизм открывает дорогу автоматическому дифференцированию, конструктивным числам и всяким UNUM (как хорошие интервальные).

Какая альтернатива интеграционным тестам на агде?

НЛО прилетело и опубликовало эту надпись здесь

Греческие и спецсимволы лигатурами созданы или через буфер копируете в utf8?

НЛО прилетело и опубликовало эту надпись здесь
2500 — максимальное количество доказанно работающих строк по Кнуту (как отправная точка A Why3 proof of GMP algorithms, страница 43), в refinedt 5000 строк… У Кормена или других есть о лимитах количества строк алгоритмов, работу которых можем доказать?
НЛО прилетело и опубликовало эту надпись здесь

Раз мы о языках, пока не мейнстримных для веба... В агде есть работа с hylomorphisms, как в хаскеле?

НЛО прилетело и опубликовало эту надпись здесь
Ньюфаг агды радуется.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
и наверняка часть из претензий надумана
Чуть более чем все претензии надуманы. При всех недостатках альтернативы ещё хуже. Лучше 10 минут потерять пока тест гоняется, чем потом от пользователя прилетит. А пользователи они ведь разные бывают.

Не выявят всех ошибок, да, но выявят множество ошибок, которые были бы пропущены без тестов.

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

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

Совершенно согласен. Увы, не могу плюсануть...

Тут на самом деле 2 подхода к разработке, живой пример в моей команде перед глазами, работаем над одним проектом, но человек искренне уверен, что код может быть тщательно продуман, написан, протестирован вручную и… всё. Дальше можно его не трогать, а что ему будет, всё же нужное написано и протестировано. Другой подход это постоянный рефакторинг, потому что, во-первых, идеально написать большой проект или его подсистему сразу не получится, во вторых, функциональность дополняется, требования меняются, код требует изменения.
Первому тесты никакие не нужны, это потеря времени, второй без тестов закопается в самоподдерживающейся как лесной пожар системе из возникающих по мере изменения кода ошибок, провоцирующих другие ошибки.
А я просто поставлю плюсик за упоминание Geant4 :) Ностальгия, знаете ли.
В какой области считали на нем?

ЗЫ. Тесты не пишу, но у нас хранимки в БД — как для них вообще тесты писать?
Медицинская физика и ядерная — прикидывали дозу и обсчитывали защиту.
ЗЫ. Тесты не пишу, но у нас хранимки в БД — как для них вообще тесты писать?


Может быть какие-нибудь стенды есть? Если честно, вот для такого бы я точно писал тесты. Чисто для душевного спокойствия.
На заре «трёхуровневой системы», насколько я знаю, в хранимках была вся бизнес-логика, а на middle tier Java — только рендеринг результатов в HTML. Прочитав ваш комментарий, подумал, что скорее всего именно малая пригодность хранимок для отладки и юнит-тестирования стала одной из причин отказа от такой практики.

Я так и не понял в чем недостатки. Ну да, тесты нужно писать — так ведь и руки чтобы помыть, нужно потратить немного энергии.
Для меня самый большой плюс юнит тестов даже не собственно в тестировании а в "валидации качества" моего кода. Обычно, если у меня не получается написать маленькие компактные юнит тесты, это является мощным сигналом подумать, а не плох ли мой код. Поэтому для меня, юнит тесты — это хорошо.


Во многих подразделениях компании Amazon у вас нет шанса пройти код ревью, если вы не пишете тесты на ваши изменения.
В гугле (в некоторых отделах) внутренняя код ревью тулза просто не позволит вам выложить код ревью, если нет юнит тестов.
Конечно, написание юнит тестов иногда напрягает, т.к. времени уходит больше чем на "полезный" код. Но, если отнестись к этому серьезно, то это помогает в будущем ловить ошибки, когда кто-то другой (вы ведь, как правило, не одни разрабатываете; с чего вы взяли что ваши коллеги так же аккуратны или. так же разбираются в этом коде как вы?) впопыхах делает изменение и не думает о каких-то специфических сценариях.
Как и везде — чтобы получить профит завтра нужно немного вложиться сегодня.

Я так и не понял в чем недостатки.


Очень жаль. В следующий раз буду писать лучше.

Не надо. :) Вы выразили свое мнение, я — свое. Это никоим образом не значит что Ваша статья плохая.

По этой теме уже не буду — ув. Aquahawk добавил то, что мне было нужно. :-) И, видимо, на этом дополнения заканчиваются.
>Обычно, если у меня не получается написать маленькие компактные юнит тесты, это является мощным сигналом подумать, а не плох ли мой код.
Вы знаете, я в статьях про тестирование наверное уже раз пять писал, что поступаю примерно так же. Примерно — потому что считаю, что лучший способ повышения качества кода — это как следует над ним подумать. В том числе — и тем способом, о котором вы говорите, т.е. написания тестов (если вам так удобно думать надо кодом, в терминах теста). А еще — более точное описание структур данных, которые применяются, если не для компилятора, то хотя бы для себя (ну типа, если у языка система типов недостаточно хороша). И я много раз замечал, что в процессе вот такого обдумывания качество кода повышается уже до написания какого-либо теста.

Конечно, думать над структурами данных и интерфейсами, как минимум, не менее важно, абсолютно согласен.
Но это не исключает того, что тесты тоже могут тут помочь. :)

Ну я вроде так и написал — если вам для обдумывания удобно написать тест — то почему нет? Я лишь чуть о другом — когда я знаю, что у меня в коде компонента есть проблема, я, пытаясь ее локализовать, думаю в терминах тестов, скажем, рефакторю так, чтобы получить чистые функции, и наоборот, выделить побочные эффекты, и т.п. — чтобы написать тест, это полезно, но это полезно и само по себе.

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

О ну с этим я совершенно согласен, не поспоришь.

Мне кажется проблему лучше было сформулировать в терминах возможностей и ограничений, чем достоинств и недостатков. Статический анализ кода с использованием разного рода формализаций это крутая штука, но как любая формальная система она имеет свои ограничения в смысле применения на практике. Рано или поздно мы упираемся в ограничения тайп чекера конкретного языка программирования, теорему о неполноте или какие-то другие специфичные научные проблемы, решать которые не хватит ни какого бюджета. Так или иначе реализацию нужно тестировать. Юнит тесты это лишь частный вид тестирования среди многих других, которые принято рисовать в виде тестовой пирамиды. Но он один из самых дешевых. В проектах, которые вынуждены и могут позволить себе осознанно заниматься контролем качества, наличие и степень покрытия кода юнит- (и разными другими) тестами определяется тестовой стратегией. В других случаях все решается по какому-то своему наитию.

Из сферических наблюдений за кровавым энтерпрайзом, откуда все эти «бэст практисес» обычно растут (десятки независимых команд в различных таймзонах, разные конфигурации, мудреные интеграции с такими же монстрами и т.п.). Отловить дефект локально и исправить обычно занимает минуты или часы одного разработчика. Исправление дефекта, отловленного в pull request средствами CI может занимать часы или дни, в добавок отжирая время ревьюверов (которые часто находятся в других таймзонах). Регрессии на нижних энвайронментах могут отрабатываться днями и неделями, стоить времени уже десятка человек (здесь подключается low env саппорт, devops, разношерстный QA, дев команды и всякие неравнодушные менеджеры), приводить к простоям других недешевых ребят. Баги на продакшене отрабатывают толпы народа (к предыдущим добавляются три линии саппорта, релиз менеджмент, аккаунты и т.д. и т.п.), чреваты бритчами SLA, что может выливаться в еще большие потери в деньгах и репутации. Поэтому рациональное предложение молодого девелопера — а давайте тут закоммитим кусок кода без теста, я сто раз проверил этот флоу локально, сэкономим полчаса моего времени — это чисто напоржать. В других условиях все может быть по другому.
НЛО прилетело и опубликовало эту надпись здесь
Я ещё не встречался ни с одной задачей, где у меня не получилось бы убедить тайпчекер, что всё корректно.


Ну для вычмата, всё-таки, юнит-тесты будут дешевле. По крайней мере, для меня. Бизнес-логика — это да, тут typechecker.
НЛО прилетело и опубликовало эту надпись здесь
Я не имел ввиду конкретно агду. На практике мы имеем дело с разными языками, у которых возможности тайпчекера могут быть довольно ограничены. В целом согласен — чем больше удается переложить проверок на верификацию, тем меньше приходится писать тестов.

Интересно какие есть возможности, чтобы заменить тесты на верификацию, скажем клиента и сервера, общающихся между собой через REST API?
НЛО прилетело и опубликовало эту надпись здесь
> Она лишь говорит, что вы изнутри тайпчекера не можете доказать, что этот самый тайпчекер корректен. Неприятно, требует верить, но требует верить сильно мелкой кодовой базе (и которая, к тому же, шарится между всеми проектами на этом языке).

0xd34df00d Формальная спецификация (в виде системы типов или что мы там используем для верификации) это тоже формальная система, которая или неполна, или противоречива. Следовательно какие-то элементы мы вынуждены вводить как аксиомы или игнорировать на этом уровне (нюансы окружения в котором будет собираться или выполняться программа, различные нефункциональные требования и т.п.). Но даже со всеми этими допущениями мы упираемся в проблему останова — как формально доказать для произвольной программы, что она когда-нибудь завершится? Поэтому сколько не верифицируй, а тестировать все равно придется. Разве не так?
НЛО прилетело и опубликовало эту надпись здесь

А теперь нужно вспомнить, сколько раз вы жалели о ненаписанных тестах, а сколько — о написанных зря.


Для определения "правильного" покрытия юнит-тестами у меня есть универсально-бесполезное правило: тестировать нужно код, который сломается. Если вы написали тест, который всегда будет "зеленым" — время на его написание и запуски было потрачено зря.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации