Манифест разработчика умных систем: 15 принципов
Мы предлагаем вашему вниманию статью Владислава Зайцева (vvzvlad), приглашенного гостя нашего блога. Владислав давно занимается темой «умных домов», и обобщив свой опыт, он предлагает следующие основные принципы дизайна такого рода систем.
Сегодня я хочу поговорить с вами об «умных» домах в частности и IoT-устройствах в целом. Но это будет не обычная статья: тут не будет железок, ссылок на производителей, кусков кода и репозитариев на гитхабе. Сегодня мы будем обсуждать нечто более высокоуровневое — принципы, по которым организуются «умные» системы.
Продолжая читать статью, вы соглашаетесь с тем, что вас устраивает следующий disclaimer.
1) Все эти пункты касаются только потребительских IoT-систем (читай «умных домов»). Тех, что человек может купить в магазине и установить без привлечения специализированных инсталляторов/интеграторов.
2) Часть этих принципов не применима к промышленным системам (там свои требования и принципы), а также, к системам, где есть отделённые от пользователя эксплуатанты (например, умный дом, который устанавливается и обслуживается специально обученными людьми).
Также часть принципов не применима к системам уровня «игрушка для гиков», к самодельным и open-source системам, у которых нет единого product owner.
3) И, конечно, всё написанное ниже — это исключительно моё мнение, основанное на моём многолетнем опыте. Вы имеете право не соглашаться с ним.
Умный дом — это система, которая берёт на себя часть повседневных забот человека. Отсюда следует первый и самый основной принцип:
1. Умный дом должен облегчать жизнь и делать её проще.
Умный дом — система для жизни, а не игрушка для гиков. Любые системы, пользоваться1 которыми сложнее, чем обычными выключателями — не умный дом.
Любая новинка должна тестироваться на соответствие этому принципу. Если она не облегчает жизнь, и вы не понимаете, как сделать так, чтобы она облегчала, ей не место в умном доме. Вы можете попробовать представить её как обучающую систему.
Второй по важности принцип касается того, как пользователь взаимодействует с системой:
2. Хороший пользовательский опыт важнее функциональности.
Грош цена крутому инструменту, которым нельзя нормально пользоваться. Удобные и надежные устройства с ограниченным функционалом имеют больше шансов на успех, чем сложные изделия на «все случаи жизни».
2.1. Удобные интерфейсы лучше кастомизируемости.
Не понимаете, как сохранить и кучу функций, и простой интерфейс? Запихиваете все функции подряд в надежде, что пользователь сам разберётся, что ему надо? Вон из профессии!
Не понимаете, как совместить удобство и кучу настроек? Пожертвуйте настройками. Любая функциональность будет круче, чем обычный выключатель, а вот излишняя сложность легко заставит пользователя вернуться к выключателю.
То же самое относится и к качеству работы. Кнопка, которая просто включает свет, лучше, чем регулирующий яркость слайдер, который иногда глючит:
2.2. Качество реализованных функций важнее их количества.
Мало надежного, но проверенного функционала лучше, чем много, но работающего кое-как.
Один из механизмов, закреплённых в человеческой психике эволюцией — более активная реакция на отрицательные стимулы. Отрицательные факторы важнее положительных: пропустить приближение опасного хищника гораздо страшнее, чем не заметить и не съесть вкусный фрукт на дереве. Если в вашей системе нет каких-то функций, это не страшно, это всего лишь отсутствие положительного стимула. А вот функция существующая, но работающая плохо — это отрицательный стимул: он запоминается легче и помнится дольше.
2.3. Внедрение системы не должно снижать привычную скорость работы.
Задержки недопустимы, так как ухудшают пользовательский опыт. Это тоже отрицательный стимул. Если человек не замечает задержки2 между щелчком обычного выключателя и включением света, он не должен заметить её и в вашей системе.
Современное железо работает с очень высокой скоростью. Нет проблемы достичь частот в десятки мегагерц на микроконтроллерах и как минимум десятков килобит в секунду даже по радиоканалу. Если вы в этих условиях не можете сделать систему, задержек в работе которой пользователь не ощущает — вон из профессии!
2.4. Система не должна ломать уже сформированные привычки пользователя.
Ваша система — лишь небольшой кусочек жизни человека. Время жизни человека превышает срок эксплуатации системы в лучшем случае в пару раз, а в худшем — на порядок. Ваша система уйдёт так же, как и придёт, а жизнь человека продолжится. И в этой жизни у человека есть сформированные привычки касаемо предпочтительной яркости света, местоположения выключателей, как ему удобно включать свет и управлять климатом у себя дома.
Нельзя пытаться насильно менять эти привычки. Предлагать — можно. Заставлять — нельзя.
Нельзя сказать пользователю «теперь ты будешь включать свет с телефона — это стильно, модно, молодёжно». Это нарушение данного принципа и нескольких других.
А что же делать?
2.5. Система должна приносить новый опыт, а не пытаться заменять старый.
Если вы считаете, что ваш способ управления системами дома лучше, чем старый, предложите его пользователю. Если это действительно удобнее, он сам выберет новый (да, разным людям подходят разные способы). Всё, что вы можете (и должны) сделать — предоставить ему выбор.
Важное место в умном доме занимает логика работы. То, что определяет, по каким правилам этот умный дом будет работать. И следующий важный принцип как раз об этом:
3. Пользователя нельзя ограничивать в доступной ему логике.
Если пользователь хочет при повышении температуры в комнате включать чайник3, дайте ему возможность делать это. Должна быть исключена ситуация, когда для совершения определенного действия нет ни физических, ни программных ограничений, но оно недоступно, потому что разработчик подумал «это никому никогда не потребуется».
3.1. Как можно проще: для написания логики не должно требоваться специальных знаний об устройстве системы
Если у вас есть устройства разных версий с разными протоколами, позаботьтесь о том, чтобы пользователь об этом знал только в реально необходимых случаях, когда без этого не обойтись. Если вы можете избавить пользователя от получения специальных знаний, пусть и ценой времени разработчиков, сделайте это. Разработчик потратит два дня, а тысяча пользователей по часу. Сорок восемь часов против тысячи? Ответ очевиден.
Как тебе спится, Джон — серийный программист?
3.2. Устройства с одинаковыми функциями должны управляться одинаково.
Пользователь не обязан знать, что клапан для воды управляется одними командами, а кран — другими. Если и тот и другой управляют водой в трубе, то они оба должны иметь на пользовательском уровне одинаковые интерфейсы: «открыть воду» и «закрыть воду».
Мы все живём в физическом мире. Тело и мозг человека сформированы для взаимодействия с физическими предметами. Отсюда принцип:
4. Физические устройства управления лучше виртуальных.
Любые, даже самые лучшие приложения на телефоне с виртуальными кнопками управления проигрывают обычному физическому выключателю в нужном месте.
Другое дело, что выключатель должен размещаться именно в нужном месте. Отсюда ещё одно важное правило:
5. Радио лучше проводов.
Проводные системы обладают надёжностью, но только радиосвязь позволяет установить новый выключатель или реле для светильника не делая ремонт заново. И перенести, если вам наскучило предыдущее место. Но у этого принципа есть и свои исключения:
5.1. Плохое радио хуже проводов.
Хорошее радио — это такое, которое позволяет не задумываться о том, на каком расстоянии от центрального контроллера надо размещать устройства. Хорошее радио — это протоколы с mesh-сетью: ZigBee, Z-Wave, 6LoWPAN и так далее.
Все остальные варианты — это плохое радио. Wi-Fi — плохое радио. Самодельные протоколы отдельных фирм (их знают самодельщики под названием »433 МГц», хотя они могут быть и на других частотах, и очень сильно отличаться друг от друга) — плохое радио.
Wi-Fi плох тем, что на его основе невозможно сделать полноценные «спящие» устройства, и сложно сделать автоматическую настройку, а также проблемами совместимости с другими Wi-Fi устройствами в доме. Простые самодельные протоколы плохи тем, что зачастую не содержат в себе ни контроля доставки, ни шифрования, ни доступных спецификаций. Ни то, ни другое не имеет mesh-маршрутизации, что часто оборачивается проблемами вида «а я не могу в тот угол выключатель поставить — слишком далеко от передатчика».
Нельзя сделать систему со стопроцентной надёжностью и без необходимости обслуживания. Устройства ломаются, в сети возникают скачки напряжения, из квартиры соседей сверху льётся вода, батарейки садятся, пластик трескается, ребёнок выливает на светильник суп и так далее. Но:
6. Ремонт, обновление, обслуживание и диагностика должны быть простыми.
В B2B всё понятно: есть пользователь, есть разработчик, а есть эксплуатант — человек или организация, которые знают, как устроена система, и могут с ней работать на профессиональном уровне. Никто не требует от бухгалтера знания программирования под 1C, этим занимается специальный человек. И никто не требует от человека, который арендует офис, понимания, как в нём работает вентиляция — его дело сказать: «У нас в офисе душно».
Грамотное решение о покупке системы основывается на расчете совокупной стоимости владения, которая складывается из цены системы и расходов на ее эксплуатацию.
В системах, которые человек использует у себя дома, всё сложнее. Там эксплуатант и пользователь — одно и то же лицо, и вдобавок зачастую не обладающее необходимыми знаниями о системе. К сожалению, таковы ограничения потребительского рынка. Отсюда следующие принципы:
6.1. Устройство должно либо работать, либо не работать. Третьего не дано.
Вероятность работы, частичная работа и неправильная работа недопустимы. Нельзя допускать ситуаций, в которых ваше устройство работает через раз или не работает один раз из десяти. Если вы считаете, что ваше устройство функционирует неправильно, стоит отключить его вообще — для безопасности и для сохранения положительного пользовательского опыта. Заменять устройство неприятно, но лучше заставить пользователя заменить его, чем формировать мнение «работает через раз» о системе. Система должна быть в строго определённом состоянии: если она сломалась, значит, она не работает, если она не сломалась, значит, она работает.
Если вы твёрдо уверены, что деградация функциональности допустима, всё равно стоит предупредить об этом пользователя внятным сообщением: «Обнаружен выход из строя второго канала диммера. Необходимо заменить диммер. Продолжить использовать первый канал диммера? Да/Нет»
6.2. Заменить сломанное устройство должно быть легко.
Система должна быть модульной. Если у пользователя ломается датчик, ему должно быть необходимо заменить только датчик. Нельзя требовать менять реле вместе с пультом управления, потому что оно, видите ли, привязывается к нему на этапе производства.
Нельзя даже сказать «новый датчик может установить только наш специалист», потому что, очевидно, с развитием вашей системы специалистов не хватит на миллионы возможных пользователей, а значит, в какой-то момент начнутся проблемы. Конечно, пользователь не будет ремонтировать устройства сам, но при поломке он должен иметь возможность их заменить.
6.3. Понятные сообщения.
Если что-то пошло не так, пользователь должен знать об этом, и знать, что именно пошло не так.
Нельзя сказать пользователю «Ошибка #45», подразумевая, что это сообщение поймёт только сотрудник техподдержки. Ему надо сказать: «Устройство не отвечает. Попробуйте перезагрузить его, привязать заново или обратиться в сервис. Ошибка #45».
Нельзя обнаружить, что устройство не отвечает (если у вас есть возможность это сделать), и не сказать об этом пользователю. Получать сообщение о проблемах не очень приятно, но гораздо неприятнее понять, что устройство не работает уже неделю, именно в тот момент, когда оно вам срочно понадобилось.
6.4. Отсутствие лишней информации в сообщениях.
Но в то же время не надо вываливать на пользователя отладочные дампы и многострочные логи. Информация либо нужна пользователю, как в предыдущем пункте, потому что она включает сведения о том, что именно пошло не так, либо не нужна, если эта дополнительная информация непонятна, потому что адресована не ему.
Не надо показывать пользователю сотню однотипных сообщений: «связь с устройством потеряна», «связь с устройством восстановлена». Решите наконец: либо это критичная проблема, и о ней надо сообщить правильным образом — «Неустойчивая связь с устройством», — либо, раз связь получилось восстановить, это не важная информация, и показывать её не надо4.
6.5. Для обслуживания не должны быть необходимы специальные знания и оборудование.
Даёте пользователю возможность обновлять прошивку — пусть она обновляется через стандартный интерфейс (USB/BT/Wi-Fi), или не упоминайте в пользовательской документации об обновлении прошивки с помощью SPI-программатора вообще.
Нельзя требовать от пользователя рассчитывать битовые маски для конфигурации устройства, если эта конфигурация требуется в обычной эксплуатации.
6.6. Система не должна требовать постоянного обслуживания.
Если раз в месяц у исполнительного блока слетает привязка, и пользователю надо лезть к люстре и привязывать его заново — это плохая система. Если в выключателе надо менять батарейки раз в два месяца — это плохая система. Даже средний срок необходимости обслуживания каждого устройства в полгода — плохо: уже для двадцати устройств в доме пользователю придётся предпринимать какие-то действия в среднем каждые девять дней.
6.7. В системе должна быть возможность обновления или расширения.
Затраты на расширение системы должны расти линейно. Новый блок должен обходиться в стоимость нового блока.
Не должно быть ситуации, когда для добавления нового датчика надо купить новый контроллер, потому что старый не поддерживает более шести датчиков5.
Не должно быть ситуации, когда новая прошивка датчика может работать только с новой версией управляющего блока.
Такие ограничения положительно влияют на прибыль, заставляя пользователей покупать новые устройства, но это дорога в ад — потеряв доверие пользователей из-за подобных трюков, вы потеряете гораздо больше, чем могли бы заработать.
7. Самодостаточность: внешние сети — это опция, а не необходимость.
Система, в которой команды ходят только через внешний сервер — плохая система. Вы можете сколько угодно хвастаться удобными интерфейсами, модными приложениями и крутыми нейросетями, но это всё неважно, если у пользователя вместе с падением интернета пропала возможность включить свет в туалете. Разработчик, ты правда считаешь такую систему хорошей?
А если серьезно, то не очень понимаю, почему этот пункт — это не само-собой разумеющаяся штука. Завязывая систему на внешний сервер вы создаете точку отказа с надежностью обычного сервера, но одновременно для всех ваших пользователей. Внешние сервисы это круто, они позволяют расширить функционал, но не должны быть единственным вариантом оперативного управления. Дополнительного канала управления, резервного хранения, анализа данных — сколько угодно.
8. Централизованность: отсутствие центрального хаба ограничивает доступную логику.
Однако, не стоит бросаться и в другую крайность — пытаться сделать систему децентрализованную, а потому абсолютно надежную.
Децентрализованная система — это когда выключатель говорит лампочке «включись», а датчик температуры при понижении этой самой температуры сам включает обогреватель. Распределённая система проигрывает централизованной просто потому, что такая система хорошо существует только в рамках самой простой парадигмы взаимодействия устройств — «устройство управляет другим устройством». Как только сложность системы возрастает, такая система порождает больше вопросов, чем ответов. Если датчиков температуры несколько, то обогреватель должен принимать команды от всех? Или сам должен опрашивать датчики? А если надо принимать решение о включении на основе тенденции, где хранить данные архива? На каждом обогревателе? А не жирно? На каждом устройстве? И гонять трафик при каждом запросе? А где хранить и как изменять логику? А если логика включает внешние элементы? А как хранить логику на «глупых» устройствах? А как её обновлять?
Все эти вопросы исчезают, если смириться и признать необходимость центрального хаба как точки взаимодействия данных и места хранения пользовательской логики. Пусть все устройства будут «глупыми», способными отдавать данные и принимать команды, а задача по хранению архивных данных, обработке этих данных, принятию решений и взаимодействию с внешними сервисами ляжет на тот самый центральный контроллер.
Децентрализованность, кстати, можно сохранить, пусть и частично: ничто не мешает при отсутствии ответа от хаба посылать команды напрямую, как fail-safe режим. Логики не будет, но зато свет включить будет возможно.
9. Система не должна производить потенциально опасные действия без подтверждения или уведомления пользователя.
Пока мы не живём в мире, где программист ответственен за ущерб, причиненный его программой (хорошо на эту тему написано тут), в программах будет много ошибок. Они будут и в софте умного дома. Единственная возможность, при которой эти ошибки не будут приводить к катастрофическим последствиям — это ограничение самостоятельных действий системы. Потенциально опасные действия должны совершаться как минимум с ведома пользователя, а лучше с его подтверждения. Свет включать можно автоматически: баг в программе приведёт к тому, что пользователь будет разбужен ночью или получит счёт на лишние сто рублей в конце месяца. Неприятно, но вряд ли опасно. Например, включать автоматически воду, если нет механизмов, гарантированно отключающих её при потопе — нельзя. А вот выключать воду — можно, так как это не опасное действие.
Этот принцип не утверждает, что обязательно необходимо запретить автоматическое управление всеми обогревателями, котлами, печами, чайниками и тому подобными вещами. Речь, скорее, о том, что, если вы уж делаете потенциально опасное устройство с программным управлением, позаботьтесь о том, чтобы его опасность не вышла на пользовательский уровень: в управляемом чайнике должны быть «железные» цепи, отключающие его при перегреве; ванна, которая наливается сама, должна иметь датчики затопления; утюг должен иметь возможность отключения, но включаться обратно только при нажатии «железной» кнопки, и так далее.
10. Система должна иметь возможность самоконтроля и самодиагностики.
Настоящий разработчик умных систем должен быть немного параноиком. Нельзя доверять интернету, он может пропасть. Нельзя доверять коду, в нем могут быть баги. Может быть, хотя бы железу можно доверять? Нет. Нельзя доверять своему железу. Реле может залипать, симисторы самопроизвольно открываться, предохранители перегорать. Наконец, пользователь может включать киловаттный чайник в розетку, рассчитанную на 100 Вт. Нужны датчики напряжения, тока, температуры. Вышла температура за пределы? Выключаем всё, отправляем предупреждение. Вышел ток за пределы — выключаем. Отключили реле, а на выходе всё еще есть напряжение? Уведомление. Включили, а напряжения нет? Уведомление!
11. Система должна иметь возможность ручного управления.
И даже при всех этих параноидальных штуках, все равно будет ситуация, когда проверки не справились, и у вас что-то сломалось. Выключатель в комнате, роутер, центральный хаб. А свет в туалете пользователю включить хочется. Какой вывод?
Всегда должна быть кнопка, которой можно сделать «закат солнца вручную». Которой можно включить или выключить свет ВОТПРЯМЩАС. Потому что новый хаб привезут завтра, выключатель можно купить новый чуть позже, а свет в комнате хочется выключить именно этим вечером, чтобы спокойно поспать.
12. Разработчики и хакеры настолько же важны, как и обычные пользователи.
Обычные пользователи сделают вам кассу, а хакеры6 — придумают новые функции. Производитель не сможет и не должен разработать все сценарии использования системы, так как заведомо не обладает знаниями во всех областях и не может оценить эффект от разработки подобных направлений. Вполне возможно, что вашей управляемой розеткой окажется безумно удобно управлять термостатом самогонного аппарата, потому что в библиотеке решений есть PID-регулятор, и теперь все самогонщики массово покупают ваши системы. Пример несколько надуманный, но основной посыл в том, что ценой некоторых усилий стоит создавать комфортную среду для хакеров, потому что они добавляют движущей силы вашей системе.
13. Открытость: система должна иметь API для интеграции с другими системами.
Вы не сможете покрыть своими устройствами все потребности клиентов. Всегда будут устройства, которых нет у вас, но есть у других производителей. Или есть у вас, но у других производителей лучше. Или вы будете таким производителем, у которого единичное устройство лучше всех. Для подключения вашей системы к другим необходим открытый и хорошо задокументированный API. Если у вас нет API, вы отказываете пользователям в возможности построения гетерогенных систем.
14. Документированность: документация — такая же важная часть системы, как код и железо.
Какое бы у вас не было крутое железо, и какой бы классный софт вы не написали, это не будет иметь значения, если пользователь не разберётся с тем, как вашу систему запустить и как с ней работать. Хорошая документация — это такая, при работе с которой у пользователя не возникает и мысли об обращении в поддержку или негативной оценки умственных возможностей разработчика. Написать такую документацию практически невозможно, но надо к этому стремиться.
И наконец, последний принцип (но далеко не последний в плане важности):
15. Самодостаточность и самоподдерживаемость: система должна продолжать работать, даже если компания работать прекратила
Человек живет 70–90 лет, система у него дома — 5–10 лет (в лучшем случае), а компании зачастую меньше. Не стоит делать систему, возможность работы с которой вы утащите за собой в могилу. Пожалейте пользователей. Проектируйте систему так, чтобы работа с ней была возможна, даже если компания и разработчики давно канули в Лету.
Привязка нового устройства происходит с получением токена с сервера разработчика? Сделайте кнопку «Пропустить получение токена». При первом включении системы надо обновить прошивку с сайта? Сделайте так, чтобы при недоступности сайта заливалась дефолтная прошивка. И так далее.
В этой статье я попытался описать весь опыт использования, работы и проектирования таких систем, сжатый в 15 основных принципов. Часть из них может показаться надуманными, часть — спорными (и это нормально), часть — банальными (и это тоже нормально).
Но если вы задумались хотя бы над одним из них, значит, статья писалась не зря.
Сноски и комментарии
1. Говоря «пользоваться», я имею ввиду не процесс настройки, а процесс обычного взаимодействия с системой.
2. Обратите внимание, я говорю не «задержка должна быть такой же», а «пользователь не должен заметить». Практика показывает, что человек не замечает задержки примерно до 300 мс.
3. Возможно, он вырос в средней Азии и считает, что лучшее средство от жары — горячий зеленый чай.
4. Разумеется, когда я говорю «информацию показывать не надо», это означает, что не стоит присылать пользователю сообщение об этом каждый раз. Её надо показывать по запросу пользователя — при нажатии кнопки «показать логи» или «показать отладочную информацию». Не надо считать пользователей идиотами, но надо уважать их время.
5. Конечно, невозможно спроектировать систему, которая поддерживала бы бесконечное количество устройств. Ограничения будут всегда, но задача разработчика сделать так, чтобы они не играли роли в 99% случаев. Ограничение в шесть датчиков — неприемлемо. Сто-двести устройств в одной сети — достаточное количество для большинства пользователей умных домов.
6. Я говорю о хакерах в первоначальном значении этого слова, по RFC1983, а не как о взломщиках.