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

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

Для любителей посмотреть и послушать: некоторые из этих сопротивлений были озвучены на IT-Weekend Kharkiv: Software Testing: youtu.be/AoPmghGFFD4
А еще можете привести примеры нетестопригодных систем?
Существуют вариации переработки таких систем в тестопригодные?
Можно рассмотреть мобильное приложение «Сканнер штриховых кодов для мероприятий». В ней есть несколько основных сценариев:

1. Пропустить пользователя с валидным билетом.
2. Показать предупреждение, если билет поддельный (не найден код в базе данных).
3. Показать предупреждение, если билет уже использован (например, дал другу, он распечатал такой же куар-код).

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

Но автоматически это сделать сложно.

Решение:
1. Изоляция компонента, который сканирует куар-код и подстановка тестового двойника.
2. Моканье (mock) метода SDK, который возвращает считанный код.

Автоматический тест для каждого из трех сценариев будет подставлять заранее известный код, как будто бы он пришел с реальной камеры, и сравнивать на него реакцию на визуальном интерфейсе с ожидаемой.
Еще я для себя вывел такое правило: если в текущем проекте написание тестов идет не как по маслу, то значит плохо с тестопригодностью. ;) Вы можете проверить это правило и на себе.
Из более формальных критериев — завязаны ли конструирование и внедрение объектов на DI, как часто используются моки статичных методов, эмуляцию системных классов (в java передача параметров через System.getProperty(...) и других вызовов методов с побочными эффектами.

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


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

«нетестопригодные системы почему-то тестами не покрыты»

В проблеме сразу и отгадка: не покрыты, потому что нетестопригодны. :)

Из нашего опыта для нетестопригодных систем:
1. Расставляем функции по приоритету в соответствии с ценностью для клиента/пользователя.
2. Пишем высокоуровневые (UI или API) тесты.

Тем самым снижаем вероятность внесения случайных регрессий.

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

Надо было кавычки поставить вокруг "почему-то" :)


  1. На практике лучше себя показывает анализ флоу разработки. Какие файлы чаще меняются, в каких больше ошибок выявляется на всех стадиях и т. п. — те и покрываются тестами в первую очередь.
2. Пишем высокоуровневые (UI или API) тесты.

там может быть намного сложнее с наблюдаемостью…
А еще можете привести примеры нетестопригодных систем?

Тестопригодность это же не бинарное свойство. Совершенно непригодных для тестирования систем вряд ли много. Но вот плохо приспособленных — полно. В компании где я работаю сейчас, например, частая проблема в слишком сильной связности компонентов. В результате для тестирования такого компонента приходится либо описывать простыню моков втрое длиннее чем собственно сам тестируемый класс, либо уходить на более высокий уровень функционального/интеграционного или даже системного тестирования, что на порядок дольше даже для сопоставимого количества тестов. А количество не сопоставимо из-за комбинаторного взрыва.
P.S. Я не уверен насколько мой комментарий понятен, поэтому не стесняйтесь спросить если что.

Совершенно верно, не бинарное. В идеале, нужно разработать формулу, которая оценит систему, компонент или функцию в интервале от 0 до 1, где 1 — идеальная тестопригодность, 0 — полная нетестопригодность.

Например, идеальная тестопригодность у функции:

def sum(a, b):
     return a + b


Потому что совершенно не нужно прикладывать никаких усилий, чтобы ее протестировать. :)

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

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

Очень сложно внедрить автоматические тесты, если программист не обучен методам тестопригодного проектирования или если менеджмент не поддерживает культуру надежного программирования в организации.
С точки зрения кого нужно их внедрять? Вы здесь в какой роли, консультант, рядовой программист, менеджер смежного подразделения?
То что тесты нужны, мне например очевидно, статью с интересом прочитал, всё доходчиво, всё по делу. Условный Василий, мой коллега за соседним столом, тоже статью прочитает, если я ему скину ссылку, но сделает для себя прямо противоположные выводы, он-то пишет быстро и четко, рефакторинг не практикует, тесты/отладка вручную 1 раз при написании, затем код лежит и не меняется практически, зачем тратить в 2-3 раза больше времени, у него свой путь. Нет, через год-два-пять, по мере разрастания проекта или работы с горами чужого легаси он конечно поймет, что тесты нужны, рефакторинг важен, и т.п. Но он поймет это сам, отбив себе всё самолюбие собственноручно расставленными в прошлом граблями. Наверное только так, через боль и унижения, это всё усваивается, а не по указке сверху.
Из моей практики «драйвером» изменения культуры программирования выступали разные роли.

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

В одной организации, которую я консультировал, таким драйвером изменений выступил собственник и СЕО, который потерял на разработке ненадежного ПО 70000 (семьдесят тысяч) долларов своих личных средств.

Мне такие «Василии» знакомы. Для таких Василиев шанс для изменения, увы, только один — это глубокий кризис. Такие кризисы рано или поздно переживают все программисты: это и бессонные ночи на работе, и увольнения, и штрафы, и судебные иски. Те моменты, когда человек уверенно говорит: «Никогда в жизни больше я не буду писать без автоматических тестов!»

Мы с единомышленниками видим такую стратегию изменения культуры программирования:

1. Сформировать новый источник этических профессиональных норм. Иными словами, сформулировать, что хорошо, что плохо. «Тесты, рефакторинг — хорошо», «Редактировать исходники прям на сервере — плохо».

2. Подготовить материалы (статьи, курсы, видео) в поддержку п. 1. Чтобы нельзя было сказать, что мы голословны и кидаемся громкими лозунгами.

3. Пропаганда этой новой культуры надежного программирования.

Программист «Василий» должен сам добровольно выбрать, на какой он стороне: с тестами, рефакторингами и счастьем? Или без тестов, с авралами и без работы? :)
Самое странное с чем встречался лично: компанией формально признаётся необходимость писать тесты, это вроде как даже обязанность всех разработчиков, технологии в проект внедрены, но в целом покрытие порядка 30% (это без учёта легаси) и уменьшается, тесты и тестовые окружения не поддерживаются, при ревью или мерже не тесты запускаются, когда запускаешь полный прогон самостоятельно раз в неделю-две — десятки сломанных тестов выплывают, часть разработчиков тесты пишут из под палки или для галочки, часть пишет много тестов, но бОльшая часть из них это тестирование геттеров/сеттеров на ошибки, которые можно выявлять статанализом, а непосредственное руководство считает, судя по всему, наличие тестов опциональной документацией к уже выполненной задаче, типа если срочных задач нет (что редко бывает), то можешь и тесты пописать.
Знакомо! Однозначно проблема с культурой. Проблему культуры невозможно решить на уровне менеджмента, методов или технологий. Здесь только изменить (воспитать) правильную картину мира в голове.

«если срочных задач нет» — 99% срочных задач можно было бы избежать, если бы заранее было сделано надежно: проработаны требования, архитектура, сделан код ревью, написаны тесты. ;)

Ох, я как раз в процессе донесения мысли до разработчиков и менеджеров что отсутствие тестов — это технический долг и незаконченная задача, а не место куда можно слить свободное время когда оно есть (а его естественно нет). Я такой здесь не один, и дело движется впрочем, так что все не так уж и плохо.

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

Не согласен. По пунктам:


  • профессионал не должен доказывать ничего руководству или заказчику на этапе сдачи работы, если это не предусмотрено законом, договором или заданием. Есть конкретные претензии? Назовите, обсудим это невыполненные требования или новые. Нет? Оплатите. Писать тесты в оплачиваемое время без ведома заказчика и руководства — в лучшем случае неэтично.
  • это возможно и без автоматических тестов, ручным тестированием по тем же кейсам как минимум. Даже юнит тесты можно вручную делать, особенно если язык интерпретируемый или имеет "псевдоинтерпретатор" в наборе инструментов.
«Есть конкретные претензии? Назовите, обсудим это невыполненные требования или новые.»

Вот тут-то и самое интересное! Профессионал прислал работу, сказал: «Я все сделал», руководитель полез перепроверить, а там на 2 из 10 юз-кейсов приложение просто крешится. Говорить «я все сделал», когда на самом деле «я что-то там написал, но не проверял» — это непрофессионально и ненадежно.

«это возможно и без автоматических тестов, ручным тестированием»

Повторюсь, 500 тест-кейсов для мобильного приложения «Онлайн-кинотеатр» тестировщик проверяет за 40 рабочих часов для одной версии iOS, а поддерживаем мы их три. Автоматический тест смог бы проверить правильность за несколько часов.

И как вы себе представляете тестировать, например, копилятор языка в ручную без автоматических тестов?
А если полез проверять и все 10 кейсов проходят? При том нет следов того, что профессионал как-то проверял.

Ну, то есть всё же не невозможно, а вполне конкретных и реальных 40 часов занимает. Если релизы раз в месяц, то одного тестировщика хватит с запасом. Можно обсуждать что выгоднее в тех или иных аспектах. Покрыть такое приложение автотестами на всех уровнях скорее всего займёт довольно много времени минимум трёх человек: разработчика, тестировщика и девопса. При том необходимость в тестировщике не исчезнет вообще после покрытия. И время всех троих надо будет тратить и на поддержку, и на развитие. Может оказаться выгодно, может нет.

Ну я тестировал, написанный мной транслятор языка вручную. Это с одной стороны. С другой, писать тесты или нет, насколько полно их и писать и т. п. — это вопрос экономической целесообразности обычно. При этом нельзя забывать, что тесты — это не гарантия отсутствия ошибок, это лишь повышение вероятности обнаружения некоторых ошибок автоматически.
Предположим, что релиз раз в месяц. Программист три недели писал код, затем тестировщик неделю тестировал, и в пятницу в 15:00, сообщил о 3 критических ошибках, 10 major и 20 minor. Общий эстимейт на исправление — 40 часов. А релиз версии был обещан в понедельник.

Ваши действия? :)
Откат фич/фиксов, вызвавших мажорные ошибки, смок тест и релиз без них, если смок-тест не прошёл, то откладывание релиза до прохождения :)

А если серьёзно, то абстрактные ситуации обсуждать можно бесконечно, нужно считать конкретные, пускай и на основе оценок, типа тестировщик стоит столько-то, разработчик столько-то, такую-то часть своего времени он будет тратить на тесты, что освободит столько-то времени тестировщика и т. п.

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

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

Отвратительная статья. "Вы все дураки и не лечитесь, только я знаю, что вам надо". И автор думает, что с таким настроем ему удастся кого-то убедить в необходимости автоматизированного тестирования? (а оно таки зачастую очень нужно, но такие вот, с позволения сказать, "евангелисты" только отбивают людям охоту его внедрять… Нужен ведь не такой "энтузазист", а специалист, который поможет внедрить малой кровью)

Вы плохо обо мне думаете, такого в статье я не писал!

«Нужен ведь не такой „энтузазист“, а специалист, который поможет внедрить малой кровью»

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

Врач, перед тем как лечить, проводит диагностику пациента, чтобы знать как и отчего лечить.

Если вы внимательно прочитаете эту отвратительную статью, то там для некоторых проблем даже наметки решения есть.

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

Если у вас уже есть решения — прошу, напишите!

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


Насчёт "намётков решения" из статьи — они, как вы понимаете, хорошо расписаны во многих других источниках :-). Но я писал не об этом, а о чисто психологическом моменте. Если с таким подходом продавить (а речь идёт именно о продавливании) автоматизированное тестирование — то получите вольный или невольный саботаж. При любой проблеме все будут радоваться, что вы сели в лужу — кроме, может быть, немногих чистых душой :-)

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

Такие виды тестирования не автоматизируются. Максимум, А/Б тестирование со снятием целевых метрик типа конверсии.

Строго говоря, автоматизируются, и даже двумя способами. Для интеграционного тестирования GUI есть сторонние решения вроде Селениума, а для тестирования логики можно и модульное применять.
Тестируется соотвествие нового дизайна макетам, но не степень офигивания пользователя от них :)
Это уже A/B тестирование и фокусгруппы
Такое можно отслеживать с помощью business-level metrics, например, количество продаж в интернет-магазине, или если мы про пример Скайпа — это сколько звонков, чатов делается в месяц через него. Если поменяли дизайн и количество звонков выросло — это хороший дизайн. Если количество звонков упало — это провал.

Ну а так, да, например, Скайп меняет дизайн ежемесячно — я уже не то, что офигеваю, я просто не понимаю, куда нужно нажать, чтобы просто початиться с человеком. :)
Я лично верю, что многие разработчики на самом деле хотят писать качественный код. Однако это ли то, что нужно заказчику? Для крупных поддерживаемых проектов тестирование уменьшает себестоимость введения новых фич, повышает надежность, а еще существует «поверье», что TDD формирует хорошую архитектуру кода. Очевидные плюсы. Жаль только, что многие проекты развиваются по совершенно иному сценарию:

  1. Нужно сделать Minimum Viable Product за заниженные в 2-3 раза сроки. Ну, вроде пока ничего страшного — жертвуются автоматическое тестирование и расширяемая архитектура, пишется миниальное решение и тестируется вручную, благо скудный набор фич позволяет. «А потом если что переделаем»
  2. Возникает набор дополнительных, «необходимых вчера» фич. Приоритет отдается им, проектирование архитектуры и тесты уходят на второй план.
  3. Проект потихоньку растет, из-за плохой архитектуры проект обрастает костылями и становится малонепригодным для тестирования, усложняется поддержка, рефакторинг напрашивается, но менеджмент по очевидным причинам не одобряет огромные трудозатраты на него.
  4. Проект развивается очень медленно, превознемогая регрессии и руководствуясь девизом «работает — не трогай».


Что необходимо чтобы так не происходило? Да черт его знает

Поменять культуру, картину мира в голове. ;)
В своей? — не вопрос. У всех? — едва ли.

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

Писать — может быть. Что коммитится в центральный репозиторий или его аналог — уже дело менеджера.

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

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

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

думать надо не над архитектурой самих тестов, а над архитектурой приложения в ключе покрытия тестами.

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

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

Как по мне, то менеджер — часть команды, а не «лезет» в неё. И менеджеру есть обычно дело, сделает команда задачу за три недели без тестов или за 4 с тестами. Причём в одних случаях, но сам будет защищать перед заказчиком срок с тестами, и убеждать команду тесты писать, а в других остальной команде нужно будет сначала его убедить.

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

Менеджер — не технический специалист

Почему? Менеджер — это очень размытое понятие. В том числе может быть техническим специалистом типа Королёва и Глушко

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

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

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

Всегда есть какой-то уровень детализации. Руководители бывают технические, которые могут принимать такие решения. Может быть кому-то потребуется обрисовать достигаемые этими решениями компромиссы. Т.е. типа «этот сайт должен работать к новому году, пусть и с глюками»
Классический тимлид — это совмещение менеджера и разработчика. Я слышал, что где-то бывают команды без лидов и прочих менеджеров, работающие с бизнесом по требованиям и приоритетам напрямую, да ещё не дающие оценок по времени разработки, но только слышал.

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

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

Я чаще встречал разделение руководства командой на два человека: ПМ и тимлид. ПМ занимается контактами с внешним миром по административным и финансовым вопросам, тимлид в эти контакты вовлекается в роли технического консультанта и сборщика технических требований, вплоть до «спасибо, а теперь иди, мы бюджет обсудим», но он осуществляет декомпозицию проекта на задачи и подзадачи, назначение конкретных исполнителей, первичный контроль за ними, установлением проектных/командных стандартов и т. п… ПМ же обычно мониторит общий прогресс исполнения, и напрямую в команду не лезет, вопросы типа «вот по этой задаче эстимейты превышены, что случилось?» он задаёт тимлиду прежде всего.

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

Именно такого ПМ я и называл в своих комментариях менеджером. Проясните свою позици пожалуйста, вы считаете что именно ПМ должен принимать решение о написании юнит тестов?

В описанной мною команде это должно быть совместное решение ПМ и тимлида, как двух менеджеров команды, как, грубо говоря, минфина, мвд и мида в двух лицах.
Вот у меня как раз возражения всегда на тему «не понимаю, как тестировать что-то сложное» и «понятия не имею, как будет выглядеть система, пока её не напишу (и не перепишу два раза)». Возможно это специфика области, разработка игр — у нас никогда не бывает чётких требований, всё кардинально меняется на лету, и компоненты системы совершенно отказываются изолироваться друг от друга, протягивая щупальца порой в совершенно неожиданные места. То есть вот скажем автоматические тесты для парсера скриптов, или для хитрого контейнера, или там для библиотеки конечных автоматов — это ОК, это я понимаю, но как тестировать что-то более высокоуровневое — игровую механику, рендер или UI — это уже за пределами моего понимания.
Не специалист в нише рендеринга и разработки игр.

Для рендера и UI могут подойти тесты, которые сравнивают результаты рендеринга (скриншоты) с эталонными с какой-то долей погрешности. Например, если кадр совпадает на 99% с эталонным, то все ок, если 95% — то все плохо.

Кроме этого на рендеринг наверняка performance тесты есть.

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

Здесь большое поле для творчества.
интеграционное тестирование — можно записывать сценарии поведения пользователя, реакцию системы (юнит умер после стрельбы, закончились патроны, уровень пройден и пр.) и прогонять эти сценарии.
Вот да, такую штуку я могу себе представить, и даже представлял (хотя сложностей с этим много, и реальной реализации почти ни разу не видел). А вот именно что юнит-тестирование — как-то не получается.
А на какие юниты это обычно делится?
А вот ни на какие обычно не делится. Для всего кода игровой механики, какой я видел, характерно было стремление к нескольким огромным классам, которые делали всё, что в эту механику было заложено, изредка делясь обязанностями с классами, у которых область действия была более очерченной (типа поиска пути). Мой личный более-менее удачный опыт был, когда я попробовал применить разбиение игровых объектов на компоненты a la Unity, но и он скатился, в конце концов, к тому, что взаимодействие _между_ компонентами — а это как раз самое интересное — было организованно в одном большом классе, называвшемся «логика уровня». В бОльших играх видел попытку организовать подсистемы («квестовая подсистема», «социальная подсистема»), но каждая из них в результате опять-таки оказывалась классом на 1000+ строк имплементации. То есть вот эта красивая картинка, где вся функциональность разбита на маленькие, легко тестируемые классы с небольшим количеством функций — она никак не получается. Но возможно я просто ни разу за 10+ лет не работал с хорошим архитектором (то что я сам плохой — я и так знаю).
У вас есть анализ причин этого? Юниты по идее должны следовать ментальной модели предметного специалиста. Человеку неудобно оперировать большими кусками информации и он делит ее на более мелкие. Если это не так, то либо предметная область либо технология не позволяет. Что именно в случае геймдева?
Я думаю проблема в предметной области довольно большая. У игрового кода очень высокая связность между разными частями потому, что правила того требуют. Тут есть такая проблема, что игра не моделирует какую-то реальность (у которой есть логичные, и не очень изменчивые законы — даже у финансов), а фантазию дизайнера, поэтому у неё могут возникать самые неожиданные взаимодействия, причём внезапно. Вчера классу Персонаж ничего не надо было знать о классе Дерево, а завтра — они вдруг лучшие друзья с интимным доступом к кишкам друг друга. Потому что так веселее.

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

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

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

github.com/MaxSavenkov/drdestructo2 — вот мой пет-прожект, можно посмотреть. Это правда довольно старый код, сейчас я наверное смог бы уже лучше, но как пример можно оценить. Самый сок находится в файле github.com/MaxSavenkov/drdestructo2/blob/master/src/GameStateLevel.cpp — скромных 2051 строк. Код местами комментирован.

Общие идеи кода описаны тут: github.com/MaxSavenkov/drdestructo2/blob/master/docs/ReadMe_Source.txt, но в целом идея была в том, чтобы разбить код на Компоненты, которые почти ничего не делают, а только пассивно содержат данные, и Процессоры, которые обрабатывают Компоненты каждого типа в один проход (например, всю физику, потом всю графику, потом весь звук). А весь код, которые требует взаимодействия _между_ разными компонентами (в т.ч. копирование данных из компонента в компонент, т.к. они дублируют данные — иначе бы Процессорам пришлось принимать на вход более чем один тип компонентов), находится в GameStateLevel :)
Может написать тесты на самые лютые методы? Например:
GameStateLevel::ControlsToPhysics
GameStateLevel::PhysicsToGraphics
GameStateLevel::FireWeapon
GameStateLevel::ProcessSingleCollision
GameStateLevel::Update


Там очень много условий и ветвлений — навряд ли такое качественно тестируется вручную. Кроме этого: «It grown organically, so be prepared.» — будет расти, будет меняться, будут появляться регрессии. ;) Ну и в третьих, если эти алгоритмы рефакторить, то лучше это делать на тестах.

Ну а так вообще конечно нужен отзыв эксперта в написании игр. Как такой код отрефакторить к какой-то стандартной игровой архитектуре.

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


GameStateLevel::ExitGame
GameStateLevel::PauseGame

метод


GameStateLevel::Update

просто просится в кандидаты на разбиение на более мелкие и тоже в отдельный класс (скорее всего не в одиночестве конечно). Легко должно быть вынести что-то вроде


GameStateLevel::TutorialTimerUpdate
GameStateLevel::LevelTimerUpdate
GameStateLevel::ReapplyKeyboardSettings

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

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

Культура программирования это конечно важно, но дело столько в культуре как таковой.
Отсутствие автоматического тестирования свидетельство, что программистам ведущим по крайней мере НЕ ИНТЕРЕСНО ПРОГРАММИРОВАНИЕ. Они привыкли делать свою работу определенным образом. Книги и статьи о программировании перестали читать много лет назад. И они ни чего не хочет менять, они искренне уверены, что тесты просто пустая трата времени. Продумывайте интерфейс, не совершайте ошибок и все будет ок.
Нормальному программисту как минимум должно быть интересно, что за тесты такие и действительно ли они помогают. А начальник программистов просто ОБЯЗАН изучать практики помогающие улучшить работу своих подчиненных и соответственно внедрять их.
Рядовые же программисты просто серая масса которой однозначно пофигу все. Пока деньги платят.
«Не можешь — научим, не хочешь — заставим!»

Нужно выстраивать систему мотивации, финансовой, карьерной, чтобы люди внедряли тесты. Например, не повышать до middle software engineer, пока программист не докажет на практике, что внедряет автоматические тесты.
>Например, не повышать до middle software engineer, пока программист не докажет на практике

Когда он докажет то доказывать придется работодателю, что он достоин этого работника.
«Повысьте вашу ценность и ценности потянутся к вам!» (Джим Рон)

Если сотрудник приносит больше ценности компании, то и получать он будет пропорционально.
Если сотрудник приносит больше ценности компании, то и получать он будет пропорционально.

Далеко не всегда в реальности именно так к сожалению. По разным причинам — где-то руководство просто не понимает какую ценность сотрудник приносит, где-то пытается сэкономить.

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

Я вот тесты рассматриваю прежде всего как документацию, на соответствие которой систему можно автоматически проверить. Но объективно число выявленных на этапах прогона тестов ошибок минимально (красные тесты при TDD и ко — не ошибки по факту). Главное, что они мне дают — повышают субъективную уверенность, что всё работает как я ожидаю, прежде всего что мой новый код не сломал старую логику. Но у многих коллег эта уверенность есть и без тестов. При этом им вполне нравится программировать.
1) В том то и дело что не Не пробовали может кто то и сделал пару тестов из под палки чисто для галочки но большинство не пробовало.
2) Я люблю писать тесты. Но есть ситуации когда я то же не пишу тесты потому что понимаю что овчинка не стоит выделки.Понимаю на основании опыта написания тестов.
И наоборот есть ситуации когда ОТЛАДКА через тесты экономит время.
Ну а когда с помощью теста кусочек кода отлажен, я просто пишу асерт начинаю отлаживать следующий кусочек кода в другом тесте.
Таким образом я экономлю время а тесты остаются как полезный артефакт от разработки.
1) Не пару тестов, а пару месяцев. Не из под палки, а из интереса. И не просто поробовали, а снимали метрики производительности, которіе показали, что скорость разработки уменьшается значительно, а количество проблем незначительно.
Если кто то проводил такие исследования то выложите их в открытый доступ пож
Далее результат может быть отрицательный потому что.
1) Разработчики изначально учились что замедляет процесс.
2) Разработчики пробовали писать тесты на то что не стоит тестировать. Простой код, или GUI (овчинка выделки не стоит).
3) Результат может появится когда кому ни будь приведется переписать функционал А это далеко не 2 месяца.
У меня тесты 5- 6 летней давности работают себе без проблем а стоит полезть в этот код, что то ломается ( не было бы тестов и не узнал бы что внес ошибку) и ее словили бы в продакшене возможно с воем и с претензиями денежными.

Причин может быть множество. Одна из них — нетестопригодный код. Но вывод люди сделали — на разработку и поддержку тестов тратится заметная доля ресурсов разработки, а польза от них минимальна. И у них есть цифры по заметному снижению производительности и цифры по практически неизменившемуся уровню багов. Как их можно убедить возобновить практику написания тестов?
Ответ только один включить голову и почитать «умные» книжки и статьи.
Как вариант предложить эксперимент
Сделать серьезные изменения в сложном коде коде
1) который был покрыт тестами.
2) который не был.
Делать должен тот кто этот код не писал.(или писал очень давно).
Вероятность внести ошибку во втором случае заставит разбираться как все работает досконально ( или положиться на авось).
В первом же случае проще разобраться в том что написано и есть ГАРАНТИЯ что я ни чего не сломал.

Я на вашей стороне, но на всякий случай добавлю: гарантия не 100% и важно чтобы разработчик это понимал. Не понимание этого нюанса в перспективе может привести к серъезным ошибкам и разочарованию в тестах.

Если тесты написаны правильно и покрывают все возможные сценарии (А именно так и должно быть при подходе через ТDD), то вероятность внесения ошибки ничтожно мала.
все возможные сценарии

Исчерпывающее тестирование невозможно кроме тривиальных случаев.
Для начала можно ограничиться сценариями из требований. Их обычно не очень много.
Ну на самом деле можно даже несколько больше, чем только сценариями. Это просто был комментарий к тому — что действительно все сценарии учесть невозможно.
Вы так безаппеляционно говорите, как будто не то что не знаете, а даже не допускаете, что могут быть ситуации, где тесты писать не имеет смысла.
Можно попробовать поставить задачу по другому — есть ли какие-то варианты, когда тесты будут выгодны?

Например для начала писать тесты только для того, что легко тестировать.

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


Что значит «минимальная польза»? Т. е. они не обнаруживают никаких ошибок или регрессий?

Как-то оценивалось функциональное покрытие тестов?
На этапе прогона тестов ошибок практически не обнаруживается.

Требование было 100% построчного покрытия для нового кода.
Я правильно понимаю, что вам клиенты (потребители) сообщали больше ошибок, чем вы обнаруживали тестами?



Если да, то тесты внедрены некорректно. Корректное внедрение повышает эффективность обнаружения ошибок.
Да, правильно. Вернее они сообщали об неожидаемом ими поведении, которое у нас зафиксировано не было, а после обсуждения принималось решение должно быть текущее поведение зафиксировано и клиенту сообщено «это не баг, это фича», или должно быть зафиксировано ожидаемое клиентом поведение и код приведён к нему, а клиенту «спасибо за баг-репорт».

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

Подробнее я рассказываю в этом видео: youtu.be/t376yJuLncE

Скорее это неполные требования. Ну типа не описано поведение калькулятора при попытке деления на ноль. Соотвественно и тестов нет. Приходит репорт от пользователя «страшное сообщение о каком-то исключении», а там решаем должно быть это исключение или что-то другое выводится, а может кнопка деления недоступна должна быть. В любом случае пишется тест, фиксирующий решение.
Кстати, метрика построчного покрытия кода тестами часто вводит в заблуждение. Более лучшие метрики — это покрытие требований тестами, или покрытие тестами определенных моделей (классов) дефектов.
По поводу уверенности.
Она может быть есть если ты работаешь один, а вот по мере увеличения количества работающих увеличиваются шансы что тебя кто ни будь «сломает».
Не говоря уш о том, что если придется дорабатывать свой же функционал пару лет спустя тесты помогут.
И главное тесты это инструмент и пользоваться им должен уметь каждый программист.
Как каждый столяр должен пользоваться лобзиком, топором, бензопилой и прочим. Каждому инструменту свое место.
Умнть — да. Но тезис біл о том, что руководитель команды программистов должен их внедрять в свою команду.

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

Ну вообще не нужны обычно нет, часто говорят «вот там где по чётким ТЗ работают, там можно их использовать, а у нас аджайл или вообще бардак».

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


Ну и последнее: регулярно вижу на митингах по оценке тасков пойдущих в спринт как разработчики говорят что-то вроде: "Здесь на 2-12-бесконечность часов больше нужно, потому что нужно модифицировать кусок который делал человек который уже уволился, как он это сделал никто не знает, тестов чтобы хотя бы примерно убедится что ничего лишнего не поменялось нет. А значит придется тратить время на изучение не только куска который нужно поменять, но и массы других вещей." В результате разработчик недоволен потому что копается в ужасном по его мнению легаси, менеджер недоволен потому что нормальных точных сроков на такой таск никто не даст, клиент не доволен потому что типовой таск, который уже выполнялся в другой части системы за Х часов здесь требует Х + У часов которые нужно оплачивать, да еще и без гарантий что разработчики уложатся.

> но для каждого метода разработчик его написавший в момент когда он его написал должен весьма четко представлять собственно цель его создания и границы его применимости хотя бы. А значит тесты уже можно и нужно использовать.

Можно, конечно, даже до написания метода тесты написать. Но не всегда это просто с одной стороны, с другой, если по опыту знаешь, что после демо требования изменятся с вероятностью 90% и половину тестов выкинуть надо будет, то желания писать их как жест доброй воли, пропадает. Особенно на фиксед прайс.
Я вот тесты рассматриваю прежде всего как документацию, на соответствие которой систему можно автоматически проверить. Но объективно число выявленных на этапах прогона тестов ошибок минимально (красные тесты при TDD и ко — не ошибки по факту).

Что значит не ошибки — а что?

Видимо несоответствие документации и реальной работы продукта. Впрочем если такое несоответствие трактуется не в пользу тестов, то тесты были написаны неудачно, либо не хватает опыта, либо требования поменялись в процессе. Во втором случае впрочем стоило бы сначала тесты и поправить.

Процесс TDD:
1) пишем тесты и убеждаемся, что они красные
2) добиваемся, чтобы они стали зелёными
3) рефакторим, проверяя, что тесты зелёные
Ещё не реализованная функциональность. При TDD падение теста сразу после его написания — норма. Вот если написал тест и он зелёный — значит, скорее всего, ошибка в тесте.

Это не значит, что все красные тесты не ошибки. Есть красные тесты которые ошибки.


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


Единственное, тут вопрос в качестве тестов и в легкости их разработки — это может серьезно повлиять на результат.

Я не говорил «все», я говорил, чтов TDD — красные тесты неотъемлемая часть процесса, ошибкой не являющейся. Естественно это не касается случаев, когда красные тесты попадаются когда их не ожидаешь.
Отдельное спасибо за определение тестопригодности приложения.
Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории