1 added
1 removed
Original
2026-01-01
Modified
2026-02-26
1
<p>При разработке приложения часто возникают сложности с удобством доступа к вложенным данным. Например, сложно быстро извлечь последние комментарии к вопросам в Q&A (Вопросы и Ответы), если комментарии вложены внутрь самих вопросов. В таком случае необходимо обойти все вопросы, собрать комментарии и отсортировать их по времени.</p>
1
<p>При разработке приложения часто возникают сложности с удобством доступа к вложенным данным. Например, сложно быстро извлечь последние комментарии к вопросам в Q&A (Вопросы и Ответы), если комментарии вложены внутрь самих вопросов. В таком случае необходимо обойти все вопросы, собрать комментарии и отсортировать их по времени.</p>
2
<p>Возьмем для примера<a>Q&A Хекслета</a>. У каждого вопроса есть количество лайков и комментарии, у которых в свою очередь тоже есть лайки. Эти данные можно представить так:</p>
2
<p>Возьмем для примера<a>Q&A Хекслета</a>. У каждого вопроса есть количество лайков и комментарии, у которых в свою очередь тоже есть лайки. Эти данные можно представить так:</p>
3
<p>Иерархическое представление данных хорошо отражает их структуру. Сразу видно, что к чему относится. Данные удобно выводить и достаточно удобно изменять. Особенно если вывод на экране совпадает с их структурой, и данные между собой не пересекаются. Вопросы и Ответы Хекслета как раз такой пример. Каждый вопрос живет своей независимой жизнью (кое-какие зависимости есть, но они не касаются самих данных).</p>
3
<p>Иерархическое представление данных хорошо отражает их структуру. Сразу видно, что к чему относится. Данные удобно выводить и достаточно удобно изменять. Особенно если вывод на экране совпадает с их структурой, и данные между собой не пересекаются. Вопросы и Ответы Хекслета как раз такой пример. Каждый вопрос живет своей независимой жизнью (кое-какие зависимости есть, но они не касаются самих данных).</p>
4
<p>Однако, если данные связаны, то иерархическая структура усложняет сквозные выборки. Представьте себе, что надо выводить 10 последних комментариев. Как это сделать? Придется ходить по всем топикам, брать все комментарии, объединять и искать самые свежие.</p>
4
<p>Однако, если данные связаны, то иерархическая структура усложняет сквозные выборки. Представьте себе, что надо выводить 10 последних комментариев. Как это сделать? Придется ходить по всем топикам, брать все комментарии, объединять и искать самые свежие.</p>
5
<p>Тут стоит сказать, что большая часть нужных выборок должна делать на бекенде и отправляться клиенту в готовом виде. Если же нужно делать такие расчеты на клиенте, то к организации объекта состояния можно подойти с другой стороны.</p>
5
<p>Тут стоит сказать, что большая часть нужных выборок должна делать на бекенде и отправляться клиенту в готовом виде. Если же нужно делать такие расчеты на клиенте, то к организации объекта состояния можно подойти с другой стороны.</p>
6
<h2>Создание индексов</h2>
6
<h2>Создание индексов</h2>
7
<p>Один из способов выйти из этой ситуации - начать дублировать данные. Создавать дополнительные структуры, оптимизированные под конкретные задачи. И хотя, в общем, это не лишено смысла, все же ручной способ поддерживать эти структуры ничего хорошего не принесет. В тех же базах данных за формирование индексов отвечает сама база данных. Нам как программистам не надо об этом заботиться. А здесь придется внедрять дополнительную синхронизацию во все этапы: добавление, изменение и удаление.</p>
7
<p>Один из способов выйти из этой ситуации - начать дублировать данные. Создавать дополнительные структуры, оптимизированные под конкретные задачи. И хотя, в общем, это не лишено смысла, все же ручной способ поддерживать эти структуры ничего хорошего не принесет. В тех же базах данных за формирование индексов отвечает сама база данных. Нам как программистам не надо об этом заботиться. А здесь придется внедрять дополнительную синхронизацию во все этапы: добавление, изменение и удаление.</p>
8
<p>Ниже пример создания объекта, оптимизированного под лайкнутые посты конкретными пользователями. Выборка вопросов, которые лайкнул конкретный пользователь (user1), превращается в простую операцию извлечения данных из объекта по ключу.</p>
8
<p>Ниже пример создания объекта, оптимизированного под лайкнутые посты конкретными пользователями. Выборка вопросов, которые лайкнул конкретный пользователь (user1), превращается в простую операцию извлечения данных из объекта по ключу.</p>
9
<p>Но тут возникает новая проблема: синхронизация данных. При изменении лайков (например, пользователь убрал лайк), нужно обновить оба объекта:</p>
9
<p>Но тут возникает новая проблема: синхронизация данных. При изменении лайков (например, пользователь убрал лайк), нужно обновить оба объекта:</p>
10
<p>Эти действия нужно выполнять при каждом изменении (добавление, удаление, изменение), и это легко приводит к ошибкам и рассогласованности данных.</p>
10
<p>Эти действия нужно выполнять при каждом изменении (добавление, удаление, изменение), и это легко приводит к ошибкам и рассогласованности данных.</p>
11
<p>Именно поэтому клиентское приложение редко занимается такими вещами вручную. Подобные структуры (индексы) автоматически создаются и поддерживаются на бэкенде или с помощью специальных библиотек управления состоянием. А сейчас активно развиваются полноценные клиентские базы данных, которые умеют с этим работать.</p>
11
<p>Именно поэтому клиентское приложение редко занимается такими вещами вручную. Подобные структуры (индексы) автоматически создаются и поддерживаются на бэкенде или с помощью специальных библиотек управления состоянием. А сейчас активно развиваются полноценные клиентские базы данных, которые умеют с этим работать.</p>
12
<h2>Нормализация данных</h2>
12
<h2>Нормализация данных</h2>
13
<p>Другой способ - нормализовать данные, прямо как в реляционных базах данных. Представить их плоскими массивами. Например, так:</p>
13
<p>Другой способ - нормализовать данные, прямо как в реляционных базах данных. Представить их плоскими массивами. Например, так:</p>
14
<p>Нормализованные данные существенно упрощают выполнение разнообразных выборок. Например, получение последних комментариев ко всем постам теперь выглядит проще и быстрее:</p>
14
<p>Нормализованные данные существенно упрощают выполнение разнообразных выборок. Например, получение последних комментариев ко всем постам теперь выглядит проще и быстрее:</p>
15
<p>Также упрощается получение постов, лайкнутых конкретным пользователем:</p>
15
<p>Также упрощается получение постов, лайкнутых конкретным пользователем:</p>
16
<p>Нормализованные данные тоже требуют синхронизации, но в основном для удаления. В нашем примере удаление поста должно приводить к удалению комментариев и лайков.</p>
16
<p>Нормализованные данные тоже требуют синхронизации, но в основном для удаления. В нашем примере удаление поста должно приводить к удалению комментариев и лайков.</p>
17
<p>И нормализованные данные требуют чуть более сложного кода при простых запросах типа "все комментарии конкретного поста":</p>
17
<p>И нормализованные данные требуют чуть более сложного кода при простых запросах типа "все комментарии конкретного поста":</p>
18
-
<p>Но в целом это небольшая цена за преимущества, которые вы получите: простоту поддержки, отсутствие дублировани�� и легкость масштабирования. Именно поэтому большинство современных фронтенд-фреймворков и библиотек управления состоянием рекомендуют использовать именно нормализованный подход к хранению данных.</p>
18
+
<p>Но в целом это небольшая цена за преимущества, которые вы получите: простоту поддержки, отсутствие дублирования и легкость масштабирования. Именно поэтому большинство современных фронтенд-фреймворков и библиотек управления состоянием рекомендуют использовать именно нормализованный подход к хранению данных.</p>
19
<p>Что по производительности? Является это проблемой или нет - вопрос открытый. Как правило, нет. Фронтенд очень редко оперирует большими количествами, например, десятками и сотнями тысяч. Чаще всего размеры коллекций ограничиваются сотней элементов. Но если производительность важна, то для этого используют разнообразные механизмы от кеширования до использования полноценных баз данных.</p>
19
<p>Что по производительности? Является это проблемой или нет - вопрос открытый. Как правило, нет. Фронтенд очень редко оперирует большими количествами, например, десятками и сотнями тысяч. Чаще всего размеры коллекций ограничиваются сотней элементов. Но если производительность важна, то для этого используют разнообразные механизмы от кеширования до использования полноценных баз данных.</p>
20
<h2>Какой подход выбрать?</h2>
20
<h2>Какой подход выбрать?</h2>
21
<p>Во многом ответ зависит от задачи и механизма управления состоянием. Как правило, в этих библиотеках есть документация, которая раскрывает как оптимальнее хранить данные внутри.</p>
21
<p>Во многом ответ зависит от задачи и механизма управления состоянием. Как правило, в этих библиотеках есть документация, которая раскрывает как оптимальнее хранить данные внутри.</p>
22
<p>Если же данные хранятся в обычных объектах без использования библиотек, то можно пойти следующим путем:</p>
22
<p>Если же данные хранятся в обычных объектах без использования библиотек, то можно пойти следующим путем:</p>
23
<ul><li>Для простоты всегда делать все плоским. Привыкнув к этому подходу, потом проще работать с любыми данными.</li>
23
<ul><li>Для простоты всегда делать все плоским. Привыкнув к этому подходу, потом проще работать с любыми данными.</li>
24
<li>Использовать вложенные структуры там где нет связи между данными и использовать плоские, там где нужно постоянно анализировать весь набор.</li>
24
<li>Использовать вложенные структуры там где нет связи между данными и использовать плоские, там где нужно постоянно анализировать весь набор.</li>
25
</ul><h2>Итог</h2>
25
</ul><h2>Итог</h2>
26
<p>Большинство фронтенд-приложений лучше всего работают с нормализованными данными, поскольку такой подход упрощает поддержку и масштабирование. Используйте иерархию только тогда, когда ваши данные полностью независимы друг от друга, и вы уверены, что это не изменится со временем.</p>
26
<p>Большинство фронтенд-приложений лучше всего работают с нормализованными данными, поскольку такой подход упрощает поддержку и масштабирование. Используйте иерархию только тогда, когда ваши данные полностью независимы друг от друга, и вы уверены, что это не изменится со временем.</p>