Search
Write a publication
Pull to refresh

Простая минификация Json тел запросов / ответов с Kotlin Serialization

Level of difficultyEasy
Reading time3 min
Views1.1K

Привет!

Недавно в рамках одного из проектов на стеке KMP, Ktor и Kotlin Serialization мы с командой решили провести эксперимент и определить возможность и целесобразность минификации тел запросов / ответов на Json.

Да, мы знаем про GraphQL, Protobuf и др., но в нашем случае имел место необузданный интерес наколхозить такое решение. И при всей его наивности удалось сократить средний размер итоговых джсонов (после всех внутренних оптимизаций) на 15–20%.

Вводные данные:

  1. Большое приложение на KMP с таргетами iOS, Android, Web и Desktop;

  2. Фронтенд и бэкенд написаны на Ktor и швыряются Json'ами по HTTP;

  3. Монорепа и по сути один KMP проект.

Структура проекта:

frontend‑app — модуль с реализацией фронтенда на KMP;

backend‑app — модуль с реализацией бэкенда на Kotlin + Ktor.

http‑model — модуль с моделями, общими между бэкендом и фронтендом; чистый Kotlin и Kotlin Serialization.

Задача

У нас есть списочный Json, который весит 4 754 байт. По сути единственной сущностью списка является следующий объект:

{
  "interestId": "f5092d67-1ba7-4e7a-8eed-75ba2726c242",
  "title": "Антенны дальнего действия",
  "imageUrl": null,
  "category": {
    "interestCategoryId": "6ac16b9f-9d2b-4bd4-b2aa-a5d35d727ecd",
    "title": "Аналог",
    "interestCategoryOrder": 0
  },
  "interestOrder": 0
}

Объект и его структура (включая ключи) дублируются n кол‑во раз, где n — размер списка, что логично для Json формата.

А вот наша модель Interest, общая между бэкендом и фронтендом, лежащая в модуле common‑model:

@Serializable
data class Interest(
  val interestId: Uuid,
  val title: String,
  val imageUrl: String?,
  val category: InterestCategory,
  val interestOrder: Int
)

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

Рождается предположение: «А зачем нам сохранять читаемость Json? Для кого?»

Соответственно, обновленная модель:

@Serializable
data class Interest(
  @SerialName("iid")
  val interestId: Uuid,

  @SerialName("t")
  val title: String,

  @SerialName("iu")
  val imageUrl: String?,

  @SerialName("c")
  val category: InterestCategory, // В InterestCategory аналогично

  @SerialName("io")
  val interestOrder: Int
)

Обновленный объект Json:

{
  "iid": "f5092d67-1ba7-4e7a-8eed-75ba2726c242",
  "t": "Антенны дальнего действия",
  "iu": null,
  "c": {
    "ici": "6ac16b9f-9d2b-4bd4-b2aa-a5d35d727ecd",
    "t": "Аналог",
    "ico": 0
  },
  "io": 0
}

Итоговый вес изначального Json'а с минифицированным объектом — 3 890 байт, т. е. ~ 80% от исходного. 20% веса банально занимал нейминг ключей. А ведь зависимость ~ O(nk), где n — размер списка, а k — вложенность объекта списка.

Какие могут быть проблемы?

Единственное за чем необходимо было следить, чтобы в рамках одной модели не было двух идентичных значений @SerialName.

При грамотном версионировании и пряморуком деливери, никаких других проблем не будет.

Использовали бы мы это в проде?

Уже использовали в рамках того же проекта. Работает хорошо, на метрики повлияло в позитивном ключе. В каких‑то местах менее существенно, в каких‑то ощутимо.

Для нас это был безболезненный и дешёвый вариант: на всё про всё ушла ~ 1 человеко‑ночь под пивом, в то время как банальная миграция на Protobuf или GraphQL была бы на порядок сложнее, запутаннее и менее привлекательной для заказчиков.

Внимание!

С нашим мультиплатформенным стеком это действительно было неплохим решеним, однако если, скажем, Ваш проект состоит из нескольких команд: веба на JS, отдельно нативных мобилок и отдельно бэка на, например, Java, нужно серьёзно задуматься.

Стоят ли эти 15–20% прироста производительности написания очень качественной документации и спецификации и постоянного синка нечитаемого нейминга в случае каких‑то изменений?

Моё мнение — не стоит. Зависит от масштаба проекта, команды и радикальности руководства.

Tags:
Hubs:
+2
Comments12

Articles