Хабрахабр

[Перевод] Данные по-прежнему важнее

Вот цитата из Линуса Торвальдса за 2006 год:

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

Что очень похоже на «правило представления» Эрика Реймонда от 2003 года:

Сверните знания в данные, чтобы логика программы стала глупой и надёжной.

Здесь просто резюме идей, подобных мысли Роба Пайка от 1989 года:

Если вы выбрали правильные структуры данных и всё хорошо организовали, то алгоритмы почти всегда будут самоочевидными. Доминируют данные. Структуры данных, а не алгоритмы, играют центральную роль в программировании.

Он цитирует Фреда Брукса из 1975 года:

Представление — суть программирования

За мастерством стоит изобретательность, благодаря которой появляются
экономичные и быстрые программы. Почти всегда это является результатом
стратегического прорыва, а не тактического умения. Иногда таким стратегическим
прорывом является алгоритм, как, например, быстрое преобразование Фурье,
предложенное Кули и Тьюки, или замена n² сравнений на n log n при сортировке.

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

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

Приведу несколько реальных примеров.

Эту систему изначально создавали с расчётом на невероятную масштабируемость при большой нагрузке на CPU. Ничего синхронного. Везде обратные вызовы, очереди и рабочие пулы.

Первая заключалась в том, что «нагрузка на процессор» оказалась не такой уж и интенсивной — одна задача занимала максимум несколько миллисекунд. Но было две проблемы. Вторая проблема заключалась в том, что «высокомасштабируемая распределённая система» в реальности работала только на одной машине. Так что бóльшая часть архитектуры приносила больше вреда, чем пользы. Потому что вся связь между асинхронными компонентами осуществлялась с использованием файлов в локальной файловой системе, которая теперь стала узким местом для любого масштабирования. Почему? Основная часть проекта была посвящена всей этой дополнительной архитектуре, которая «очевидно» была необходима, чтобы справиться с «большой нагрузкой» на CPU. Оригинальный дизайн вообще не привязывался к данным, за исключением защиты локальных файлов во имя «простоты».

Эта система следовала дизайну микросервисов из одноцелевых приложений с API-интерфейсами REST. Одним из компонентов была база данных, в которой хранятся документы (в основном ответы на стандартные формы и другие электронные документы). Естественно, она выставляла API для сохранения и извлечения данных, но довольно быстро возникла необходимость в более сложной функциональности поиска. Разработчики посчитали, что добавление этой функции к существующему API документа противоречит принципам проектирования микросервисов. Поскольку 'search' по сути отличается от 'get/put', то архитектура не должна их объединять. Кроме того, для работы с индексом они планировали использовать сторонний инструмент, поэтому создание нового сервиса 'search' имело смысл ещё и по этой причине.

Эти данные обновлялись динамически, поэтому любой компонент, который изменял данные документа через главный API БД, должен был также отправить запрос на обновление индекса через поисковый API. В итоге был создан поисковый API и поисковый индекс, который по существу стал дубликатом данных в основной БД. С помощью REST API это невозможно сделать без состояния гонки, поэтому два набора данных время от времени выходили из синхронизации.

Позже разработчики признали, что поисковый индекс следует объединить с общим сервисом документов, и это сделало систему намного более ремонтопригодной. Несмотря на то, что обещала архитектура, два API были тесно связаны через их зависимости от данных. «Делать одно» работает на уровне данных, но не на уровне глаголов.

Эта система была своего рода автоматизированным конвейером развёртывания. Изначальная группа разработчиков хотела сделать достаточно гибкий инструмент, чтобы решить проблемы деплоя по всей компании. Они написали набор подключаемых компонентов с файловой системой конфигурации, которая не только настраивала компоненты, но и выступала в качестве предметно-ориентированного языка (DSL) для программирования того, как компоненты вписываются в конвейер.

Был длинный список известных ошибок, которые никто никогда не исправлял. Перенесёмся на несколько лет вперед, и инструмент превратился в «ту самую программу». Никто не использовал гибкость DSL. Никто не хотел прикасаться к коду из страха что-нибудь сломать. Все пользователи копировали и вставляли одну и ту же гарантированно рабочую конфигурацию, что и все остальные.

Хотя в первоначальном проектном документе часто использовались такие слова, как «модульный», «разъединённый», «расширяемый» и «настраиваемый», он вообще ничего не говорил о данных. Что пошло не так? Со временем компоненты делали всё больше и больше недокументированных предположений о том, что входит или не входит в блоб JSON. Таким образом, зависимости данных между компонентами обрабатывались нерегламентированным способом с использованием глобально общего блоба JSON. Конечно, DSL позволял переставлять компоненты в любом порядке, но большинство конфигураций не работали.

Я выбрал эти три проекта, потому что на их примере легко объяснить общий тезис, не трогая остальных. Однажды я попытался создать веб-сайт, а вместо этого завис над какой-то раболепской базой данных XML, которая даже не решала моих проблем с данными. Был ещё проект, который превратился в сломанное подобие половины функциональности make, снова потому, что я не думал, что мне действительно нужно. Я уже писал о времени, потраченном на создание бесконечной иерархии классов ООП, которую следовало закодировать в данных.

Обновление:

Мои реальные коллеги знают, что я гораздо больше заинтересован на исправлении реальных проблем, а не на обвинении тех, кто эти проблемы породил, но, ладно, вот что я думаю о разработчиках, причастных к этим проектам. Видимо, многие всё равно считают, что я пытаюсь кого-то высмеять.

Многих из нас можно в этом обвинить (меня тоже), но это действительно раздражает коллег. Честно говоря, первая ситуация явно произошла по той причине, что архитектор системы был больше заинтересован в применении научной работы, чем в решении реальной проблемы. Если вы узнаёте себя, не обижайтесь, пожалуйста, просто остановитесь (хотя я бы предпочёл работать с распределённой системой на одном узле, чем с любой системой на моей «базе данных XML»). Ведь им придётся помогать в поддержке, когда нам надоест игрушка.

Иногда кажется, что все вокруг говорят, как замечательно разделить сервисы, но никто не говорит о том, когда лучше этого не делать. Во втором примере нет ничего личного. Люди всё время учатся на собственном горьком опыте.

Третья история на самом деле произошла с одними из самых умных людей, с которыми мне когда-либо доводилось работать.

(Конец обновления).

Он также очень удобен для выявления ложных «экспертов» с их советами. Вопрос «Что сказано о проблемах, создаваемых данными?» оказывается довольно полезной лакмусовой бумажкой для хорошего проектирования систем. Они покажут вам удивительно красивую архитектуру, но ничего не скажут о том, для каких данных она подходит, и (что важно) для каких данных не подходит. Проблемы с архитектурой сложных, запутанных систем — это проблемы с данными, поэтому ложные эксперты любят их игнорировать.

Это звучит красиво и даёт красивые диаграммы, но это обратное мышление. Например, ложный эксперт может сказать, что вы должны использовать систему pub/sub, потому что системы pub/sub слабо связаны, а слабо связанные компоненты более ремонтопригодны. Pub/sub не делает ваши компоненты слабо связанными; pub/sub сам слабо связан, что может соответствовать или не соответствовать потребностям ваших данных.

Функциональное программирование, service mesh, RPC, шаблоны проектирования, циклы событий, что угодно, у всех свои достоинства. С другой стороны, большое значение имеет хорошо спроектированная архитектура, ориентированная на данные. Но лично я видел, что гораздо более успешные системы в продакшне работают на скучных старых СУБД.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть