SOA в JSON
VK API, например в методе wall.get, возвращает список постов. В этих постах могут быть атачменты: картинки, видео и музыка. Как их отдает вк: отдельно указывается поле "type"
с значением "image"
, "video"
или "music"
и отдельно данные по атачу в зависимости от типа.
Как парсить это в типизированном языке? Например в Go
требуется перед парсингом JSON
указать, какие поля каких типов мы хотим вытащить. А тут эти поля мы можем узнать только во время парсинга. Поэтому есть только два костыльных решения:
-
Сделать структуру
ImageOrVideoOrMusic
в которую парсить все возможные поля, а те поля которых нет игнорировать. Понятно какие поля в этой структуре: поля картинок, поля видео и поля для музыки. Почему костыль: много памяти на эту структуру, много кода, структура, которая называется "картинка или видео или музыка" по факту хранит "картинка И невалидное видео И невалидная музыка ИЛИ невалидная картинка И видео И невалидная музыка ИЛИ невалидная картинка И невалидное видео И музыка", то есть расхождение между синтаксисом и семантикой. -
Сделать два парсинга: первый в тривиальную структуру с полем только для типа, второй парсинг в нужную структуру в зависимости от типа. Почему костыль: два прохода на парсинг, временная структура.
Почему вообще возникли такие проблемы и можно ли от них избавиться? Корень проблемы в том, что JSON
как формат пришел из динамического языка JS
позволяет в массиве (списке) хранить данные разных типов. У нас это список обьектов Картинка|Музыка|Видео
. Причем нам еще повезло, что мы смогли четко ограничить типы этих обьектов, могло быть такое, что эти обьекты содержат абсолютно разные данные в разных форматах.
По сути это AOS - Array Of Structs, только вместо структур здесь одна из структур фиксированного набора. Кто знаком с алгебраическими типами знает, что это сумма типов. Одним из подходов к работе с AOS является преобразование его в SOA - Struct Of Arrays, структуру, в которой поля это массивы значений исходных структур. В случае выше можно было сделать что-то аналогичное на уровне поля type: разбить поле с атачами на три поля: список картинок, список видео и список музыки. Хранить эти списки в SOA или в AOS уже не важно как, обычно используют AOS, а на преимущества SOA кладут болт. Так, у нас будет три, возможно пустых, поля "images"
, "videos"
и "musics"
с списками фиксированной структуры. Запарсится это тривиально в подобную структуру: