Embedded HandbookПриложения
Все разделы › XXII. Программная инженерия
STM32F103, STM32F407, STM32G431, STM32L431 · уровень средний · 7 мин чтения
Открыть в интерактивном справочнике

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 % случаев.

Отсюда два практических следствия:

  1. После каждой правки гоняют весь набор тестов, а не только тот, что ловил исходную ошибку, — иначе регрессию найдёт заказчик.
  2. Правка перед самой сдачей опаснее всего: её уже некому поймать. Отсюда заморозка изменений перед выпуском и правило «в кандидата идут только исправления по найденным дефектам».

Набор тестов и сборка по каждому изменению — это ровно то, что делает CI из раздела 110; защитное программирование из раздела 129 уменьшает долю правок, которые ломают соседнее.


182.6 Наращивание вместо водопада

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

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

Что даёт скелет сразу:


182.7 Грабли

«Требования у нас в голове». Тогда и проверять нечего: приёмка превращается в спор о том, что имелось в виду. Двадцать строк в файле рядом с кодом лучше, чем идеальный документ, которого нет.

Тесты пишут в конце. Ворота, поставленные после приёмки, ловят ошибки по цене поля — модель выше показывает разницу в 4,7 раза.

Правка без теста на неё. Ошибка вернётся: тот же код, та же ситуация. Тест на исправленную ошибку — самый дешёвый тест из всех, условие для него уже известно.

Исправляют «заодно» соседнее. В кандидате на выпуск каждая лишняя правка — это 7 % шанса новой ошибки без ворот впереди.

Считают, что дисциплина процесса нужна только большим командам. Разработчик-одиночка платит те же 68 часов за ошибку в поле — просто из своего времени.


182.8 Итоги

Дальше: раздел 183 «Сроки и люди: бригада, опоздание, оценка по трём точкам».

Открыть в интерактивном справочнике