Главное правило — использовать заголовочные файлы как определения интерфейсов. Однако такой подход требует внимательно следить за тем, что помещается в заголовочный файл. Желательно не помещать в него ничего, кроме объявлений функций, а также констант и имен структур, необходимых функциям.
Не загромождайте интерфейсные заголовочные файлы структурами данных, константами и определениями типов, которые нужны только реализации. Это не просто вопрос беспорядка: подобный беспорядок приводит к нежелательным зависимостям. Ограничьте видимость деталей реализации. Исходите из предположения, что детали реализации будут изменяться. Чем меньше мест, где код знает детали, тем меньше кода вам придется просматривать и изменять.
Чистая встраиваемая архитектура позволяет выполнять послойное тестирование, потому что модули взаимодействуют посредством интерфейсов. Каждый интерфейс обеспечивает шов, или точку подстановки, для тестирования вне целевого окружения.
Принцип DRY и директивы условной компиляции
Одно из использований возможности подстановки, которое часто упускают из виду, связано с особенностями обработки разных целевых платформ или операционных систем программами на C и C++. Для этого часто используются директивы условной компиляции, включающие и выключающие сегменты кода. Я вспоминаю один особенно тяжелый случай, когда в телекоммуникационном приложении директива #ifdef BOARD_V2 встречалась несколько тысяч раз.
Повторяющийся код нарушает принцип «не повторяйся» (Don’t Repeat Yourself; DRY)[61]. Если #ifdef BOARD_V2 встречается один раз, в этом нет никакой проблемы.
Можно, если реализовать слой аппаратных абстракций и скрыть определение типа оборудования в этом слое. Если слой HAL предоставляет набор интерфейсов, вместо условной компиляции можно взвалить всю работу на компоновщика (редактора связей) или использовать некоторую форму связывания во время выполнения для подключения программного обеспечения к оборудованию.
Заключение
Программисты, разрабатывающие встраиваемое программное обеспечение, могут многое взять из опыта разработки обычного программного обеспечения. Если вы занимаетесь разработкой встраиваемого программного обеспечения, то найдете в этой книге много мудрых и полезных советов и идей, которые пригодятся и вам.
Не позволяйте всему вашему коду превращаться в микропрограммы — это вредно для долгого и доброго здоровья вашего продукта. Возможность тестирования исключительно в целевом окружении — вредна для долгого и доброго здоровья вашего продукта. Следование принципам чистой встраиваемой архитектуры — полезно для долгого и доброго здоровья вашего продукта.
Часть VI. Детали
Глава 30. База данных — это деталь
С архитектурной точки зрения база данных не является сущностью — это деталь, которая не должна подниматься до уровня архитектурного элемента. Ее отношение к архитектуре программной системы сопоставимо с отношением дверной ручки к архитектуре здания.
Я понимаю, что эти слова могут показаться провокационными. Но верьте мне, я знаю, о чем говорю. А теперь позвольте мне пояснить: я не имею в виду модель данных. Структура, которую вы придаете данным в своем приложении, очень важна для архитектуры системы. Но база данных — это не модель данных. База данных — это часть программного обеспечения. База данных — это утилита, обеспечивающая доступ к данным. С архитектурной точки зрения эта утилита не имеет никакого значения, это низкоуровневая деталь — механизм. А хороший архитектор не позволяет низкоуровневым механизмам просачиваться в архитектуру системы.
Реляционные базы данных
Принципы реляционных баз данных были определены Эдгаром Коддом в 1970 году. К середине 1980-х годов реляционная модель разрослась и превратилась в доминирующую форму хранения данных. Такая популярность появилась не на пустом месте: реляционная модель элегантна, дисциплинированна и надежна. Это отличная технология хранения и доступа к данным.
Но какой бы блестящей, полезной и близкой к математике ни выглядела технология, она не перестает быть просто технологией. А значит, она — деталь.
Реляционные таблицы удобны для некоторых видов доступа к данным, но в упорядочивании данных по записям в таблицах нет ничего архитектурно значимого. Варианты использования в приложении не должны знать и заботиться о таких вещах. В действительности о табличной организации данных должны знать только низкоуровневые вспомогательные функции во внешних кругах архитектуры.