Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

Проект GPSD

Глава 7 из книги "Архитектура приложений с открытым исходным кодом", том 2.
Оригинал: GPSD, глава из книги "The Architecture of Open Source Applications" том 2
Автор: Eric Raymond
Перевод: Н.Ромоданов

7.8. JSON и архитектонавты

Одно из самых значительных преобразований в истории проекта произошло, когда мы перешли от первоначально используемого протокола сообщений к использованию JSON в качестве метапротокола и передачи клиентам объектов JSON. В исходном протоколе использовались однобуквенные символы в качестве команд и ответов, и т. к. возможности демона постепенно увеличивались, мы буквально задыхались в пространстве односимвольных имен.

Переход на JSON был большой победой. JSON сочетает в себе традиционные достоинства Unix использования чисто текстового формата - легко просматривать, легко редактировать с помощью стандартных инструментов, легко создавать с помощью программ - с возможностью передавать структурированную информацию более богатыми и гибкими способами.

Отобразив типы сообщений в объекты JSON, мы обеспечили, что любое сообщение может содержать объединение строковых, числовых и логические данных и структур (возможность, которой не было в старом протоколе). Благодаря тому, что типы сообщений идентифицируются с помощью атрибута class, мы обеспечили, что у нас всегда будет возможность добавлять новые типы сообщений, которые не будут мешать использовать старые.

Это решение не обошлось без затрат. Парсеру JSON требуется несколько больше вычислительных ресурсов, чем очень простому и ограниченному парсеру, который он заменил, и, конечно, в новом парсере больше строк кода (что предполагает больше мест для возникновения дефектов). Кроме того, обычные анализаторы JSON для того, чтобы справиться с массивами переменной длины и со словарями, которые описываются в JSON, требуют динамического распределения памяти, а динамическое распределение памяти является пресловутой причиной появления дефектов.

Мы справились с этими проблемами несколькими способами. Первым шагом было написание парсера на C для (достаточно) большого подмножества JSON, в котором используется исключительно статическое распределение памяти. Это потребовало принять некоторые незначительные ограничения, например, объекты в нашем диалекте JSON не могут содержать значение null, а массивы всегда имеют фиксированную максимальную длину. Приняв эти ограничения, мы смогли втиснуть парсер в 600 строк кода на языке C.

Затем мы построили полный набор юнит-тестов для парсера с тем, чтобы проверять отсутствие ошибок в операциях. Наконец, для встроенных систем с очень жесткими ограничениями, где накладные расходы для JSON могут быть слишком высокими, мы написали экспортный механизм с совместно используемой памятью, который позволяет обходиться без полного разбора и отправки сообщений JSON полностью в случае, если демон и его клиент имеет доступ к общей памяти.

JSON уже не используется только для веб-приложений. Мы считаем, что любой, кто проектирует протокол для приложения, должен рассматривать подход, похожий на используемый в проекте GPSD. Конечно, идея создания протокола поверх стандартного метапротокола не нова; поклонники XML пользуются ей в течение многих лет, и это имеет смысл для протоколов со сложной структурой документов. JSON обладает преимуществом за счет более низких накладных расходов, чем в случае с XML, и он лучше подходит при обходе массивов и структур записей.

7.9. Проектирование с минимизацией количества дефектов

Любое программное обеспечение, которое используется в навигационных системах и находится между пользователем и датчиком GPS или другим датчиком, определяющим месторасположение, потенциально является жизненно-важным, особенно в море или в воздухе. В навигационном программном обеспечении с открытым исходным кодом стараются уклониться от этой проблемы при помощи добавления соглашения об отказе от ответственности, в котором говорится: «Не полагайтесь на это, если это может поставить под угрозу жизнь».

Мы считаем, что подобные отказы бесполезны и опасны: бесполезны, поскольку системные интеграторы, весьма вероятно, относятся к ним формально и их игнорируют, и опасны, поскольку они способствуют тому, что разработчики опрометчиво считают, что дефекты в кода не будут иметь серьезных последствий, и что допустимо сглаживать острые углы в сфере обеспечения качества программ.

Разработчики проекта GPSD считают, что единственной приемлемой политикой является проект с нулевым количеством дефектов. Из-за того, что программное обеспечение остается сложным, мы этого еще не совсем достигли, но если учесть размер проекта GPSD, время работы над ним и его сложность, то мы подошли очень близко.

Нашей стратегией для этого является сочетание принципов архитектуры и политики кодирования, которые направлены на то, чтобы исключить возможность появления дефектов в поставляемом коде.

Один из важных принципов состоит в следующем: демон gpsd никогда не использует динамическое распределение памяти - нет ни malloc, ни calloc, и нет никаких обращений к функциям или библиотекам, в которых они требуются. Благодаря этому одним махом исчезает самая пресловутая причина дефектов, имеющая место при кодировании на языке C. У нас нет никаких утечек памяти и нет никаких ошибок двойных malloc или двойных free и никогда их не будет.

Нам это сходит с рук, поскольку все датчики, с которыми мы работаем, передают пакеты с относительно небольшой фиксированной максимальной длиной, а работа демона состоит в их обработке и отправке их клиентам почти без буферизации. Тем не менее, отказ от использования malloc требует дисциплины при кодировании и некоторых конструктивных компромиссов, некоторые из которых мы уже отметили при рассмотрении парсера JSON. Мы добровольно идем на эти затраты с тем, чтобы уменьшить количество дефектов.

Полезным побочным эффектом этой политики является то, что повышается эффективность чеккеров (checker) статического кода, например, splint, cppcheck и Coverity. Это ведет нас к другому крупному политическому выбору; мы интенсивно используем оба этих инструмента аудита кода, а также специально настроенный фреймворк регрессионного тестирования. Мы не знаем ни о каких других проектах, кроме GPSD, которые полностью аннотированы для использования splint, и сильно подозреваем, что ничего подобного еще не существует.

Строгая модульная архитектура GPSD помогает нам и здесь. Границы модулей служат в качестве точек отсечения, куда мы можем подсоединять специальные страховочные средства, и мы достаточно систематически это делаем. С помощью нашего обычного регрессионного тестирования проверяется все - от поведения плавающей точки на серверном оборудовании и до анализа JSON с тем, чтобы исправить сообщения о функционировании, поступающие из более чем семидесяти различных журналов датчиков.

Следует признать, что нам было несколько легче быть тщательными, чем многим другим приложениям, поскольку в демоне нет пользовательского интерфейса; окружающая его среда является простым набором последовательных потоков данных и ее относительно легко моделировать. Но, как и с отказом от использования malloc, фактическое использование этого преимущества требует правильного к нему отношения, что в частности означает, что нужно быть готовым тратить на проектирование и кодирование тестовых инструментальных средств и страховочных средств столько же времени, сколько мы тратим на создание кода. Это политика, которой, как мы думаем, могут и должны подражать другие проекты с открытым исходным кодом.

Когда я пишу эту статью (июль 2011 года), трекер ошибок проекта GPSD пуст. Он бывает пустым в течение недель, и на опыте появления сообщений об ошибках в прошлом, мы можем предполагать, что он будет оставаться таким же и далее. У нас в течение шести лет в коде не было критических ошибок. Когда у нас возникают ошибки, они, как правило, связаны к некоторым несущественными отсутствующими функциями или несоответствием спецификациеям, что легко исправляется в течение нескольких минут.

Это не означает, что проект был непрерывной идиллией. Далее мы рассмотрим некоторые из наших ошибок ...


7.10. Усвоенные уроки