Создание подключенного к сети продукта может выглядеть завершенным задолго до того, как будет закончена вся инженерная работа над ним. Прототип стабилен, данные поступают в облако, приложение отображает правильные значения, и первая партия устройств уже находится в руках пользователей. На этом этапе бэкэнд может быть достаточно простым, чтобы команда знала практически каждое устройство в отдельности. Инициализация может осуществляться с помощью скрипта, изменения конфигурации могут вноситься вручную, и если что-то пойдет не так, инженер обычно может напрямую определить проблему.
Затем устройство должно начать использоваться в реальном мире. Появляется вторая аппаратная версия. Некоторые клиенты по-прежнему используют первую версию. Версии прошивки начинают расходиться. Для разных клиентов или рынков требуется новая конфигурация, а старые устройства по-прежнему нуждаются в обновлениях и поддержке.
Ничего принципиально не сломано. Программное обеспечение устройства просто приобрело свой собственный жизненный цикл.
Этот переход легко упустить из виду, поскольку прототип может продолжать прекрасно работать. Но как только в реальных условиях приходится использовать несколько версий одного и того же физического продукта, бэкэнд перестаёт быть просто инфраструктурой за оборудованием. Он становится частью самой архитектуры продукта.
Рабочий прототип, обеспечивающий подключение к сети, пока не является масштабируемым продуктом.
Прототип выполняет важную задачу: доказывает работоспособность системы от начала до конца. Устройство выполняет свою основную функцию, микропрограмма взаимодействует с бэкэндом, телеметрия поступает туда, куда нужно, команды отправляются обратно, а мобильный или веб-интерфейс предоставляет пользователю доступ к этим функциям.
Как правило, не удается доказать, насколько хорошо одна и та же система справляется с разнообразием.
Первые двадцать устройств могут работать на одной и той же прошивке, быть собраны на одном и том же аппаратном уровне и настраиваться одними и теми же инженерами. На этом этапе вполне разумно использовать ручную регистрацию, прямые изменения конфигурации или небольшой скрипт для адаптации. Создание инструментов производственного уровня до того, как продукт докажет свою эффективность, может быть преждевременным.
Масштабирование меняет проблему. Устройства остаются в автономном режиме, заменяются, работают на разных версиях прошивки и требуют различных конфигураций от клиентов. Служба поддержки должна отличать устройство, которое так и не было корректно настроено, от устройства с неправильной конфигурацией или просто недоступного.
Задолженность по прототипам часто начинается так: не с неудачного решения, а с временного, которое сохраняется и после того, как продукт был усовершенствован. И одним из первых факторов, которые заставляют этот переход стать очевидным, является само оборудование. Новая версия не просто заменяет старую; она должна сосуществовать с ней.
Каждая новая версия аппаратного обеспечения создает проблемы, связанные с жизненным циклом программного обеспечения.
Новая версия оборудования редко становится идеальной заменой старой. На практике обе версии остаются в эксплуатации, иногда годами. Добавьте к этому переходную партию, несколько веток прошивки и конфигурации, разработанные специально для клиентов, и парк оборудования быстро станет гораздо более разнообразным, чем предполагала первоначальная модель продукта.
Программный слой больше не может рассматривать каждый модуль как абстрактное «устройство». Ему необходимо знать, на что способен именно этот модуль.
В обновленной плате может использоваться другой датчик, коммуникационный модуль или контроллер. Команда, действительная для последней версии, может не поддерживаться более ранней. Значения калибровки могут изменяться. Ограничения конфигурации могут смещаться. Пакет микропрограммного обеспечения, подходящий для одного поколения, может быть небезопасен для другого.
Инженеры, занимающиеся разработкой физических изделий, уже работают по этому принципу. Два компонента, которые выглядят почти одинаково, не взаимозаменяемы, если различаются их версии, допуски или технические характеристики. Взаимодействующие продукты создают ту же проблему на программном уровне: платформе необходим надежный способ понять, с какой версией физического изделия она взаимодействует и какие правила к ней применяются.
Рассмотрим продукт, первая версия которого использует одну процедуру калибровки, а вторая вводит новый датчик и другой набор параметров. Для клиента оба устройства могут оставаться одним и тем же продуктом. Для платформы же это не так.
Если эти различия не представлены явно, они, как правило, проникают в логику приложения в виде частных случаев. Один рабочий процесс проверяет диапазон серийных номеров. Другой использует версию прошивки в качестве заменителя поколения оборудования. Третий содержит исключение, добавленное после того, как служба поддержки обнаружила, что более старая партия ведет себя иначе в полевых условиях. Ни одно из этих исправлений само по себе не выглядит особенно опасным, но вместе они затрудняют понимание любых будущих изменений.
Устаревшее оборудование редко исчезает в срок. Команды разработчиков, естественно, сосредотачиваются на новейшей версии, в то время как клиенты часто используют более ранние версии гораздо дольше, чем ожидалось. Поэтому платформа должна поддерживать несколько поколений одновременно, а не предполагать, что установленная база когда-либо соберется на одном текущем уровне.
Как только это произойдёт, эволюция аппаратного обеспечения и управление жизненным циклом программного обеспечения станут неразделимыми. Платформа должна знать не только, где находится устройство и подключено ли оно к сети, но и что это за устройство, какие программы оно может запускать, как его следует настроить и какие изменения можно безопасно внести.
И прежде чем на любой из этих вопросов можно будет дать достоверные ответы, каждое устройство должно быть введено в систему единообразным образом.
На этапе выделения ресурсов прекращается ручная разработка для масштабирования.
При небольшом количестве устройств процесс инициализации кажется простым: создать запись об устройстве, ввести серийный номер, сгенерировать учетные данные, назначить устройство клиенту, применить конфигурацию и двигаться дальше. Однако для нескольких десятков устройств выполнение части этих операций вручную может оставаться оптимальным вариантом.
Однако в производственных масштабах процесс инициализации находится на пересечении идентификации устройства, учетных данных, права собственности, конфигурации и состояния жизненного цикла. Ошибка, допущенная во время ввода устройства в эксплуатацию, может повлиять на его работу и поддержку еще долго после того, как оно покинет завод.
Таблица может уже не соответствовать тому, что фактически установлено. Для замены устройства необходимо правильно связать его с клиентом, не допуская при этом присвоения неверной учетной записи. Сброс к заводским настройкам создает еще один путь в этом процессе. Установщик может назначить устройство неправильной учетной записи, и тогда службе поддержки придется определять, находится ли оно в автономном режиме, неправильно настроено или просто имеет неправильную конфигурацию.
Если для ответа на эти вопросы разработчику обычно требуется проверить базу данных или запустить внутренний скрипт, то этот процесс перестает масштабироваться вместе с продуктом.
Дублирование — ещё один тревожный сигнал. Каждый вариант продукта начинает приобретать свой собственный сценарий подключения, инструмент настройки или рабочий процесс установки. Эти различия могут показаться незначительными, но основная задача остаётся той же. Процесс подготовки ресурсов превратился из задачи настройки, привязанной к конкретному устройству, в многоразовую инфраструктуру платформы.
И зачастую это не единственная функция, которую необходимо сделать многоразовой.
Платформенный слой должен стать многократно используемой инфраструктурой.
Когда несколько продуктов или аппаратных модификаций начинают удовлетворять одним и тем же базовым потребностям, некоторые программные возможности перестают быть специфичными для конкретного продукта. Хорошими примерами являются идентификация устройств, предоставление ресурсов, подключение, телеметрия, доставка встроенного ПО, состояние жизненного цикла, отслеживание состояния парка устройств и диагностика. Перестройка этих функций для каждого нового варианта приводит к увеличению объема кода и количества операционных путей, требующих поддержки, без повышения уникальности самого продукта.
Команды редко ставят перед собой цель создать такое дублирование. Небольшие различия накапливаются вокруг каждого продукта, пока команда не начинает поддерживать несколько реализаций того, что стало одной и той же инженерной задачей.
Более четкое разграничение — это отделение продуктового слоя от платформенного слоя. Продуктовый слой включает в себя поведение, рабочие процессы, интерфейсы, интеграции и предметную логику, которые делают конкретное устройство ценным. Платформенный слой обрабатывает механизмы, которые должны оставаться неизменными даже при изменении аппаратного обеспечения.
По мере того, как подключенные продукты выходят за рамки своего первого выпуска, настройка устройств, управление жизненным циклом устройств, управление парком устройств и инструменты поддержки становятся общей инфраструктурой, а не отдельными проектными задачами. Платформа PaaS для предприятий в сфере IoT может обеспечить такой многоразовый уровень платформы для нескольких продуктов или вариантов продуктов, обрабатывая стандартное управление устройствами и данными с помощью многократно используемых строительных блоков, в то время как инженерные команды сосредотачивают свои усилия на разработке оборудования, рабочих процессов и пользовательского опыта.
Единая основа должна оставлять место для реальных различий в продуктах. Новое устройство может потребовать другой модели данных, потока конфигурации, интеграции или логики управления, и эти различия должны оставаться легко внедряемыми. Цель состоит в том, чтобы просто избежать ситуации, когда каждое различие влечет за собой создание нового реестра устройств, конвейера телеметрии, механизма предоставления ресурсов или набора инструментов управления парком устройств.
Платформа может казаться излишней накладной расходом во время разработки первого продукта, а ко второму или третьему — уже ценным активом. Как только будут налажены общие операционные механизмы, новый вариант сможет унаследовать работающую основу, вместо того чтобы поставляться с ещё одним бэкэндом, который команде придётся поддерживать на протяжении всего жизненного цикла продукта.
Разработка индивидуальных решений должна осуществляться только в тех случаях, когда продукт действительно отличается от заявленного.
Многоразовая платформа не должна делать подключенные продукты более универсальными. Ее задача — исключить повторную разработку тех компонентов, которые не обеспечивают дифференциации.
Индивидуальные решения по-прежнему должны касаться поведения устройства, специфической для предметной области логики, рабочих процессов, пользовательского опыта, специализированных интеграций и того, как конкретный продукт взаимодействует с физическим миром. Именно в этих областях инженерные решения могут сделать один продукт значительно лучше другого.
Редко кому следует уделять одинаковое внимание, так это окружающей операционной инфраструктуре. Базовая и промышленная версии одной и той же машины могут нуждаться в разных датчиках, элементах управления и интерфейсах, но им не должны требоваться отдельные способы идентификации устройств, отслеживания версий прошивки или управления парком оборудования.
Я бы предпочёл, чтобы инженеры тратили это время на совершенствование работы продукта в реальных условиях, а не на перестройку уже существующих механизмов для другого продукта. Общая основа не уменьшает возможности для индивидуальной разработки; она защищает эти усилия от того, чтобы они были поглощены инфраструктурой.
Настоящее испытание наступит, когда команда приступит к работе над вторым продуктом.
Хорошая платформа упрощает создание следующего продукта по сравнению с первым.
Если для работы над вторым продуктом требуется практически та же самая платформа, что и для первого продукта, то на самом деле повторно использовано очень мало ресурсов.
Новый вариант должен унаследовать те части операционной модели, которые не изменились: потоки предоставления ресурсов, идентификация, механизмы жизненного цикла, инструменты для управления автопарком, процессы обработки встроенного программного обеспечения, прозрачность поддержки и общие интеграции. Инженерные усилия затем направляются на устранение различий — возможно, на новый пакет датчиков, другой рабочий процесс управления или интеграцию, специфичную для клиента, — вместо того, чтобы перестраивать фундамент.
Новое поколение оборудования подвергает эту идею большему давлению. Его возможности могут существенно измениться, в то время как старые устройства остаются в эксплуатации. Зрелая платформа может поддерживать оба варианта, не заставляя команду поддерживать два отдельных стека платформ для того, что клиенты по-прежнему воспринимают как одно семейство продуктов.
Ничто из этого не требует единой монолитной серверной части. Разные продукты могут нуждаться в четких архитектурных границах. Важно избегать повторной реализации одной и той же инженерной задачи без веской причины.
Именно тогда платформа становится активом, а не просто накопленными накладными расходами. Служба поддержки использует меньше параллельных инструментов, релизы следуют более последовательным путям, а добавление еще одного продукта становится контролируемым расширением, а не еще одной внутренней системой, которую компания будет наследовать бесконечно.
Рассматривайте платформу как часть архитектуры продукта.
При проектировании физических продуктов учитываются возможности доработок, ремонтопригодность, технологичность производства и будущие изменения. К разработке программного обеспечения для подключенных устройств применяется тот же подход.
Первая серверная часть может быть временной. То же самое относится к первому скрипту инициализации или инструменту поддержки. В этом нет ничего плохого. Проблемы начинаются, когда эти временные механизмы незаметно превращаются в постоянную архитектуру, в то время как сам продукт продолжает развиваться.
К тому времени подключенный продукт перестает быть просто оборудованием, прошивкой и приложением. Он также зависит от инфраструктуры, которая идентифицирует каждое устройство, понимает его возможности, применяет правильную конфигурацию, поддерживает обновления и помогает командам диагностировать проблемы спустя годы после выпуска.
Как только этот слой рассматривается как архитектура продукта, разделение становится более ясным: стандартные механизмы остаются многоразовыми, в то время как индивидуальная работа направлена на то, что действительно отличает один продукт или семейство продуктов от другого.
Самая мощная платформа — это не просто та, которая делает возможным создание первого подключенного продукта. Это та, которая позволяет команде разработчиков создавать второй, третий и четвертый продукты, не получая каждый раз новую серверную часть.

