Библиотека сайта rus-linux.net
Проект GPSD
Глава 7 из книги "Архитектура приложений с открытым исходным кодом", том 2.
Оригинал: GPSD, глава из книги
"The Architecture of Open Source Applications" том 2
Автор: Eric Raymond
Перевод: Н.Ромоданов
7.10. Усвоенные уроки
Проектировать программное обеспечение трудно; в нем обычно также есть ошибки и темные закоулки, и проект GPSD не стал исключением из этого правила. Самой большой ошибкой в истории этого проекта была разработка исходного протокола, который использовался перед использованием JSON для запросов и получения информации GPS. На то, чтобы от него отказаться, потребовались годы усилий и мы усвоили уроки, связанные как ошибочным первоначальным проектированием, так и с его исправлением.
С исходным протоколом были связаны две серьезные проблемы:
- Плохая расширяемость. В нем использовались теги запросов и ответов, содержащие каждый одну букву без учета регистра. Так, например, запрос на получение долготы и широты был "P", а ответ выглядел, например, "P -75.32 40.05". К тому же, парсер интерпретировал запрос, например, "PA", как запрос "P" с последующим запросом "А" (altitude - высота). Поскольку возможности демона постепенно расширялись, мы буквально были вытолкнуты из пространства команд.
- Несоответствие между неявной моделью поведения датчиков, подразумеваемой в протоколе, и тем как датчики ведут себя на самом деле. Старый протокол состоял из запросов/ответов: посылался запрос о местоположении (или высоты, или еще чего-нибудь), который возвращал ответ через некоторое время. На самом деле, как правило, не представляется возможным запрашивать ответ от датчиков GPS или других датчиков, относящихся к навигации; они выдают поток ответов, и лучшее, что запрос может сделать, это запросить кэш. Такое несоответствие поощряло неаккуратную обработку данных в приложениях: слишком часто они запрашивают данные о местоположении, не запрашивая время или иную проверочную информацию, касающуюся качества ответа, что на практике может легко привести к тому, что пользователю будут представлены устаревшие или неправильные данные.
Еще в 2006 году стало ясно, что старый дизайн протокола был несовершенным, но для того, чтобы разработать новый протокол, потребовалось почти три года проектных эскизов и фальшстартов. После этого переход занял два года, что стало причиной головной боли у разработчиков клиентских приложений. Стоимость этого перехода могла бы быть большей, если бы проект не поставлялся в виде библиотек клиентской стороны, которые изолировали пользователей от большинства деталей протокола, но вначале у нас не было достаточно хорошего API этих библиотек.
Если бы мы знали тогда, что мы знаем теперь, то протокол на основе JSON был бы внедрен на пять лет раньше, и в проекте интерфейса API клиентских библиотек потребовалось бы делать гораздо меньше изменений. Но есть ряд уроков которые можно усвоить только благодаря практике и эксперименту.
Есть по крайней мере две рекомендации по проектированию, которые нужно иметь ввиду для того, чтобы в будущих демонах сервисов избегать повторения ошибок:
- Проектирование возможности расширения. Если в протоколе приложения вашего демона может не хватать пространства имен, как было в нашем старом протоколе, то вы сделали этот протокол неправильно. Переоценка краткосрочных затрат и недооценка долгосрочных преимуществ таких метапротоколов, как XML и JSON, являются ошибками, которые все еще остаются достаточно типичными.
- Библиотеки клиентской стороны являются лучшим подходом, нежели предоставление доступа ко всем деталям протокола приложения. Внутренняя реализация библиотеки может быть адаптирована для многих версий протокола приложения, существенно снижая как сложность интерфейса, так и показатель наличия дефектов, в сравнении с альтернативным вариантом, когда каждый автор приложения должен разрабатывать специальное решение. Это различие выливается в гораздо меньшее количество сообщений об ошибках на трекере вашего проекта.
Одним из возможных ответов на наш упор на расширяемость, причем не только в протоколе приложений GPSD, но и в других частях архитектуры проекта, например, в интерфейс драйверов пакетов, является отказ от расширяемости как от нечто лишнего, что ведет изменению назначения проекта. Программисты Unix, прошедшие школу в традиции «делать что-то одно хорошо», могут спросить, действительно ли в 2011 году нужен больший набор команд gpsd
, чем было в 2006 году, и почему gpsd теперь работает с датчики, которые не являются датчиками GPS, например, с магнитными компасами и морскими приемниками Marine AIS, и почему мы обдумываем такие возможности, как слежение за воздушными судами ADS-B.
Это справедливые вопросы. Мы можем получить ответ, если взглянем на фактическую сложность добавление нового типа устройства. По очень веским причинам, в том числе из-за относительно низкого объема данных и высоких уровней электрических шумов, что исторически связанно с последовательным подключением датчиков, почти все протоколы ответов датчиков GPS и других навигационных датчиков выглядят во многом одинаково: маленькие пакеты с проверочной контрольной суммой некоторого вида. Такие протоколы неудобно обрабатывать, но их действительно нетрудно отличать друг от друга и анализировать, а дополнительные затрат на добавление нового протокола, как правило, меньше, чем делать для каждого протокола что-то отдельное. Затраты даже на самые сложные из поддерживаемых нами протоколов с добавлением собственных генераторов ответов, например, для Marine AIS, составляют порядка 3 тыс. строк на каждый протокол. Драйвера плюс анализатор пакетов и связанные с ними генераторы ответов в формате JSON составляют приблизительно в общей сложности 18 тыс. строк кода.
Если это сравнивать с 43 тыс. строк кода всего проекта в целом, то мы видим, что большая часть затрат по сложности сосредоточена в GPSD на самом деле в коде фреймворка, окружающего драйверы, и (что важно) в инструментальных средствах тестирования и во фреймворке проверки правильности демона. Их дублирование привело бы к проекту намного большего размера, чем просто создание любого отдельного парсера пакетов. Так что написание проекта, эквивалентного GPSD, для протокола пакетов, который не обрабатывается в GPSD, потребовало бы гораздо больше работы, чем добавление еще одного драйвера и набора тестов для самого GPSD. Напротив, наиболее экономичный подход (и с наименьшим накапливаемым влиянием на показатель дефектов) представляет собой увеличение в GPSD количества драйверов пакетов для большого количества различных типов датчиков.
«То одно», ради чего проект GPSD разрабатывался так, чтобы он делал это хорошо, является работа с любым набор датчиков, которые передают пакеты с различными контрольными суммами. То, что выглядит как изменение назначения, является, на самом деле, предотвращением ситуации, кв которой потребовалось бы писать много различных и дублирующих друг-друга демонов обработки. Вместо этого, разработчики приложений получили один относительно простой интерфейс API и выгоду благодаря нашей трудной экспертной победе в проектировании и тестировании большего количества типов датчиков.
То, что отличает GPSD от простой кучи возможностей нечеткого назначения, это не просто удача или черная магия, а грамотное применение известных лучших приемов разработки программного обеспечения. Отдача от них начинается с низкого уровня дефектов в настоящее время, и продолжается благодаря возможностью поддерживать новые функции без особых усилий или существенного влияния на уровень дефектности в будущем.
Возможно, самый важный урок, который мы получили для других проектов с открытым кодом, заключается в следующем: снижение дефектности асимптотически близко к нулю является сложной, но не невозможной задачей даже для такого широко внедряемого и разнообразного по назначению проекта, каким является проект GPSD. Этого можно достичь с помощью правильной архитектуры, хорошей практики кодирования, и действительными намерениями сосредоточиться на тестировании - и самым важным условием является дисциплина, которой надо следовать в этих трех направлениях.