182. Жизненный цикл прошивки и цена ошибки
Части с первой по двадцать первую — про то, как заставить железо работать. Эта часть — про то, как довести работающий макет до изделия, которое выпускают партиями и чинят годами. Начнём с самого денежного вопроса: почему одна и та же ошибка стоит час на бумаге и две недели в поле.
Числа ниже — не «известно, что», а модель с явными допущениями:
_verify/soft182/defects.py. Все допущения названы в тексте, и любое
из них можно поменять в одной строке и пересчитать.
Как это называется в документации
Оригинал Перевод software lifecycle жизненный цикл разработки requirement требование traceability matrix матрица прослеживаемости, требование → проверка design / code review обзор архитектуры, ревью кода unit / integration / acceptance test модульный, интеграционный, приёмочный тест defect, bug дефект, ошибка rework переделка regression регрессия, возврат старой ошибки technical debt технический долг shift left сдвиг проверок к началу incremental delivery наращивание, поставка кусками
182.1 Этапы и что остаётся после каждого
| Этап | Что на выходе | Чем проверяется |
|---|---|---|
| требования | что устройство обязано делать и в каких пределах | обзор требований |
| архитектура | разбиение на модули, карта памяти, бюджеты времени | обзор архитектуры |
| код | модули прошивки | ревью кода, модульные тесты |
| интеграция | собранная прошивка на плате | интеграционные тесты, стенд |
| приёмка | прошивка-кандидат | приёмочные испытания |
| поле | партия изделий | отзывы, телеметрия, обновления |
Важно не название этапа, а простое свойство: каждый следующий этап опирается на предыдущий. Ошибка в требовании к диапазону измерения переживает архитектуру, код и тесты — и каждый из них придётся переделать, когда требование исправят.
182.2 Почему ошибка дорожает
Допущение модели — час на саму правку плюс переделка всего, что успели сделать между внесением ошибки и её обнаружением. Переделка по этапам: требования 1 ч, архитектура 2 ч, код 6 ч, модульные тесты 2 ч, интеграция 3 ч, приёмка 4 ч, поле 58 ч (разбор случая плюс перепрошивка партии).
| Где нашли | Ошибка в требовании | Ошибка в коде |
|---|---|---|
| требования | 1 ч | — |
| архитектура | 3 ч | — |
| код | 9 ч | 1 ч |
| модульные тесты | 11 ч | 3 ч |
| интеграция | 14 ч | 6 ч |
| приёмка | 18 ч | 10 ч |
| поле | 76 ч | 68 ч |
Ошибка в требовании, дожившая до поля, обходится в 76 раз дороже, чем найденная на своём этапе. Ошибка в коде — в 68 раз. Ни одна из этих цифр не про сложность самой правки: правка и там и там занимает час. Дорого стоит всё, что придётся переделать вокруг неё.
182.3 Две организации работы на одних и тех же 100 ошибках
Допущения: из 100 ошибок 30 внесены в требованиях, 15 в архитектуре, 55 в коде. Каждые ворота ловят свою долю того, что до них дошло; доли ниже — для ошибок требований / архитектуры / кода:
| Ворота | Требования | Архитектура | Код |
|---|---|---|---|
| обзор требований | 50 % | — | — |
| обзор архитектуры | 40 % | 50 % | — |
| ревью кода | 30 % | 40 % | 60 % |
| модульные тесты | 10 % | 30 % | 60 % |
| интеграционные тесты | 30 % | 50 % | 40 % |
| приёмочные испытания | 60 % | 60 % | 50 % |
Что не поймали — уходит в поле.
A. Проверяем только в конце, приёмочными испытаниями.
| Где поймали | Штук | Часов |
|---|---|---|
| приёмка | 54,5 | 743 |
| поле | 45,5 | 3226 |
| всего | 100 | 3969 |
B. Обзоры, ревью, модульные, интеграционные и приёмочные тесты.
| Где поймали | Штук | Часов |
|---|---|---|
| требования | 15,0 | 15 |
| архитектура | 13,5 | 26 |
| код | 38,7 | 78 |
| модульные тесты | 15,2 | 59 |
| интеграция | 6,8 | 64 |
| приёмка | 6,0 | 84 |
| поле | 4,9 | 347 |
| всего | 100 | 672 |
Сами проверки тоже стоят времени: обзор требований 8 ч, обзор архитектуры 8 ч, настройка ревью кода 40 ч, каркас модульных тестов 80 ч, стенд интеграции 40 ч — 176 ч разовых вложений. С ними процесс B обходится в 848 ч против 3969 ч, то есть в 4,7 раза дешевле, а вложения окупаются на 5,3 ошибки — на шестой найденной ошибке проверки уже отработали своё.
Полезно смотреть не на общую сумму, а на последнюю строку: в процессе A в поле уходит 45,5 ошибки из ста, в процессе B — 4,9. Именно эта строка превращается в рекламации, выезды и внеплановые обновления.
182.4 Матрица требование → проверка
Матрица прослеживаемости — таблица из двух колонок, которую заполняют сразу, а не перед сдачей. Слева проверяемое требование, справа — чем именно оно проверено:
| Требование | Чем проверено |
|---|---|
| измерение тока 0…20 А с погрешностью не хуже 1 % | стенд с эталонным шунтом, протокол на 11 точках |
| устройство переживает переполюсовку питания | опыт по 173.1, ток в обратном включении |
| часы уходят не более чем на 10 с в сутки | 174.4: расчёт по нагрузочной ёмкости и прогон сутки |
| прошивка обновляется по UART и откатывается | сценарий на стенде: прерывание обновления питанием |
| сторожевой таймер перезапускает зависшую задачу | тест с искусственным зависанием задачи |
Требование, которое нечем проверить, — не требование, а пожелание: «устройство должно быть надёжным» проверить нельзя, а «после 1000 циклов включения не должно быть отказов» — можно.
Матрица даёт два ответа, которых иначе нет: какие требования ещё не проверены и какие тесты ничего не проверяют.
182.5 Правка вносит правку
Исправление — это тоже изменение кода, и оно тоже может внести ошибку. Пусть это случается в 7 % правок. Тогда на одну ошибку приходится в среднем 1,075 правки, а десять правок подряд обходятся без новой ошибки только в 48 % случаев.
Отсюда два практических следствия:
- После каждой правки гоняют весь набор тестов, а не только тот, что ловил исходную ошибку, — иначе регрессию найдёт заказчик.
- Правка перед самой сдачей опаснее всего: её уже некому поймать. Отсюда заморозка изменений перед выпуском и правило «в кандидата идут только исправления по найденным дефектам».
Набор тестов и сборка по каждому изменению — это ровно то, что делает CI из раздела 110; защитное программирование из раздела 129 уменьшает долю правок, которые ломают соседнее.
182.6 Наращивание вместо водопада
Модель выше не требует делать этапы подряд один раз. Наоборот: самое дешёвое расположение ворот — как можно ближе к месту, где ошибка вносится, а это значит короткие круги.
Рабочий приём для прошивки: с первой недели иметь скелет, который собирается, мигает светодиодом, отвечает по UART и прошивается на плату. Дальше каждая неделя добавляет один кусок — драйвер, задачу, формат кадра, — и каждый кусок проходит свои ворота. Тогда интеграция не превращается в отдельный этап-катастрофу в конце: она происходит каждую неделю по чуть-чуть.
Что даёт скелет сразу:
- прошивка всегда в собираемом состоянии — «сломал сборку» видно в тот же день;
- есть куда добавлять тесты: каркас модульных тестов заводится один раз;
- видно бюджет: сколько занято Flash и RAM — с первой недели, а не за неделю до сдачи;
- железо и прошивка идут навстречу друг другу: плату можно проверить скелетом, пока логика ещё не написана.
182.7 Грабли
«Требования у нас в голове». Тогда и проверять нечего: приёмка превращается в спор о том, что имелось в виду. Двадцать строк в файле рядом с кодом лучше, чем идеальный документ, которого нет.
Тесты пишут в конце. Ворота, поставленные после приёмки, ловят ошибки по цене поля — модель выше показывает разницу в 4,7 раза.
Правка без теста на неё. Ошибка вернётся: тот же код, та же ситуация. Тест на исправленную ошибку — самый дешёвый тест из всех, условие для него уже известно.
Исправляют «заодно» соседнее. В кандидате на выпуск каждая лишняя правка — это 7 % шанса новой ошибки без ворот впереди.
Считают, что дисциплина процесса нужна только большим командам. Разработчик-одиночка платит те же 68 часов за ошибку в поле — просто из своего времени.
182.8 Итоги
- Каждый этап опирается на предыдущий, поэтому цена ошибки растёт не от сложности правки, а от объёма переделки: 1 ч на своём этапе против 76 ч в поле для ошибки в требовании и 68 ч для ошибки в коде.
- На одних и тех же 100 ошибках проверки по ходу дела дают 848 ч против 3969 ч и 4,9 ошибки в поле вместо 45,5.
- Вложения в проверки — 176 ч в модели — окупаются на 5,3 ошибки.
- Требование без способа проверки — пожелание; матрица требование → проверка показывает и непроверенные требования, и бесполезные тесты.
- Правка вносит новую ошибку в 7 % случаев, поэтому после каждой правки гоняют весь набор тестов, а перед выпуском изменения замораживают.
Дальше: раздел 183 «Сроки и люди: бригада, опоздание, оценка по трём точкам».