fk0, легенда (07.11.2019 12:59, просмотров: 957) ответил SciFi на Говорят, "test-driven development" в этих случаях помогает. Сделал рефакторинг, прогнал тесты, чувствуешь себя сухо и комфортно. Хотел попробовать, но с этими тестами столько геморроя (особенно симулировать железо), что забил. Плетём лапти по
Железо нужно симулировать не на уровне битов и фронтов сигналов, а на уровне высокоуровневых операций (например, чтение-запись блоков данных в EEPROM делается через функцию HAL)... Потом на сам HAL пишутся тесты и с осциллографом в руках на реальном железе изучается их работа. Потом ПО разрабатывается на ПК, с подмененным слоем HAL, где функции виртуальные (EEPROM как файл). Там где в синтетической платформе нужна логика (клапан открыли -- через пол секунды сработал датчик) или GUI (чтоб видеть вывод и руками симулировать ввод, чтоб не делать в натуре стенд с лампочками и тумблерами) -- HAL лишь протаскивает нужные функции из C-кода в Tcl. Остальное дописывается на Tcl/Tk в 10 раз быстрей. Что касается тестирования, то здесь есть несколько разных подходов:
1) Юнит-тестирование, применимо только к хорошо изолируемым "юнитам", классам в C++ с ограниченным функционалом, которые не имеют огромной зависимости от лежащих ниже API (которые придётся тоже симулировать, что уже достаточно сложно). Юнит-тестирование подходит только для хорошо изолируемых модулей. ПК-программисты этого не понимают, пытаются применить везде и в итоге во-первых сложно, во-вторых тесты проходит, а по факту не работает (потому, что отсутствующие слои нижележащих API симулируются не так, как оно есть в действительности).
2) "Интеграционное" тестирование, я четкого названия не знаю. Когда со всей пирамиды разных слоёв API отрывается верхняя часть, а нижняя остаётся такая какая есть. За исключением HAL, который замещается на другой, для возможности запуска на ПК. Такие тесты могут осуществляться на разных слоях API, что важно. Тесты проверяют, что по факту вызовов API очередного слоя, этот слой и все нижележащие работают верно, что достигается нужный результат, что в HAL попадают нужные запросы (тесты могут наблюдать за состоянием HAL через какой-либо механизм, вплоть до парсинга логов, тесты пишутся скорей на C, потому, что связывать каждый слой с Tcl -- муторно). Данные тесты очень важны, жизненно. Без них в принципе сложно или невозможно выстраивание пирамиды ПО достаточно большой высоты, со множеством слоёв -- развалится как вавилонская башня, если нельзя толком опереться на гарантированно рабочие нижние слои и нужно всё отлаживать в целом и одновременно. Данный способ тестирования реализует принцип "разделяй и властвуй" и позволяет уменьшить сложность и объём одновременно отлаживаемого ПО. Почему-то об этом мало где, нигде практически, не пишут.
3) Функциональное тестирование. Когда подменяется только HAL, который в конечном счёте является и источником входных воздействий или сигналов, и проверяет результат (для этого скриптинг на Tcl очень помогает, потому, что писать тесты на C было бы сложно, долго и неудобно). Проверяется, что программа в целом реализует нужный функцинал. Данный способ плохо подходит для отладки больших систем, но он принципиально необходим как гарантия работоспособности.
И в любом случае архитектура ПО должна напоминать пирамиду. Пирамида должна уметь частично разбиратся. Т.е. когда нижние слои ничего не знают о верхних и могут обращаться к верхним лишь косвенным образом (через делегаты, коллбэки, широковещательные события), верхние знают о нижних и умеют их использовать напрямую (путём вызова функций). Важно, чтоб пирамиду всегда можно было разобрать сняв верхние слои и она при этом не сломалась (собиралась, запускалась). Для этого все зависимости должны быть развёрнуты строго в одну сторону (вниз), зависимостей направленных вверх между слоями не должно быть. Зависимости одном слое возможны. Зависимости вниз через слой (с пропуском) -- желательно минимизировать, т.к. они лишают возможности подстановки/замены нижнего слоя другой реализацией. И сами зависимости, разумеется, должны реализоваться через интерфейсы и не подразумевать определённую реализацию под интерфейсом (что позволяет сменить реализацию более нижнего слоя). Опять же, про архитектуру почему-то мало где или нигде не пишут. По крайней мере в области embedded-программирования.
[ZX]