Search
Write a publication
Pull to refresh

Comments 25

А зачем нам сохранять читаемость Json? Для кого?

Для удобного дебага, чтения логов и т.д.

Статья про то, что в Kotlin Serialization есть аннотация, позволяющая управлять именем сериализуемого свойства? Как и у любой другой библиотеки для работы с JSON?

Спасибо за комментарий)

Мы логи на сервере пишем после десериализации запросов и до сериализации ответов, и соответственно в них всё чистенько и читаемо, т. к. пишем по неймингу пропертей, а не полей в джсоне. Зачем дебажить сам джсон на корректность сериализации/десериализации — не знаю. С таким же успехом можно подебажить протокол HTTP. А если идея с помощью, например, чарлика подменять запросы, то для таких вещей есть дев и стейдж окружения, где минификации нет)

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

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

API Binance, Bybit и т.д. В теории любое приложение с публичным WS API и мощным потоком данных.

Стоят ли эти 15–20% прироста производительности...

Моё мнение — не стоит.

Так смотря о чем речь. Биржевые или финансовые данные сохраняют формат десятилетиями. Почему б и не оптимизировать? Особенно когда ты их стримишь по 10к в секунду. А волатильные форматы не стоит, конечно.

Да, в таких кейсах, конечно, есть смысл использовать, как в статье написано, зависит от кейса и команды. Мне кажется, там нужно что-то постабильнее

Мы логи на сервере пишем после десериализации запросов и до сериализации ответов

А ещё логи бывают вне приложения. Например, на балансерах/гейтвеях.

Для таких вещей есть дев и стейдж окружения, где минификации нет.

У вас замена имен у свойств при сериализации вшита в описание самих структур. Каким образом это отключается в разных окружениях?

Кажется, вам нужно было просто включить сжатие ответов и всё https://docs.spring.io/spring-boot/how-to/webserver.html#howto.webserver.enable-response-compression

В статье есть блок в конце, обратите на него внимание, пожалуйста. Это решение даже не рассматривается в проектах с балансерами и т.

Отключается с помощью настроек конфигурации Kotlin Serialization. Плюс, в статье демо пример, на самом деле всё чуточку сложнее. Привести весь листинг кода не было целью.

P. S. Спасибо за статью про сжатие, обязательно почитаем. Только у нас в этом проекте не Spring, а Ktor, но ничего, поменяем стек.

Спасибо, но уже не актуально( Наш 400к сеньор уже нашел индусский туториал 😎

А потом меняется команда разработчиков и следующие проклинают предыдущих за "оптимизацию" кода

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

А так это никому не мешает, сами джсоны на проде мы на корректность не дебажим, да и команда на этом проекте небольшая и все знали об эксперименте)

QA будуть "в восторге" от такой оптимизации. Отладка каких-то багов с некорректной обработкой АПИ вызовов тоже затрудняется. А gzip вам не подошёл?

Пост в тему

gzip тоже использовали) это своего рода эксперимент

Вы правы, Gzip на больших json-ах сработает еще лучше.

Продолжая тему сексуальных девиаций:

[
	{ id: 1,  status: "new", date: { created: new Date }, parent: null },
	{ id: 4,  status: "new", date: { created: new Date }, parent: null },
	{ id: 7,  status: "done", date: { created: new Date }, parent: null },
	{ id: 10, status: "done", date: { created: new Date }, parent: null },
]
["id","status","new","date","created",1754216838166,{"d4":5},"parent",{"_0":1,"s1":2,"o3":6,"n7":0},{"d4":5},{"_0":4,"s1":2,"o3":9,"n7":0},"done",{"d4":5},{"_0":7,"s1":11,"o3":12,"n7":0},{"d4":5},{"_0":10,"s1":11,"o3":14,"n7":0},[8,10,13,15]]

-30%

А зачем null передавать и нули - эти поля можно не передавать :/

Если данные сжимаются, то повторяемые поля почти не влияют на итоговый вес — замена ключей, описанная в статье, несёт больше минусов, чем плюсов. Стоит прописать дефолтные значения для полей, как минимум null в нуллабельные типы, и отключить сериализацию дефолтных значений (encodeDefaults = false), плюс выключить prettyPrint, вот и ещё -30% экономии будет.

А разве одно другому мешает?

Можно, но статья не об этом)

Как не об этом? Минификация json - не передавать в json поля с дефолтными значениями

Здесь про конкретный кейс минификации букав. Но, безусловно, вы правы, null тоже не имеет смысла передавать явно.

Аннотации прописывали ручками? Это подходит, когда нас есть монолит multiplatform, dtoшки у нас лежат в commonMain. В случае микросервисов, когда data классы у всех свои, это проблема.

Мне кажется, здесь уместна автоматизация на уровне плагинов Gradle, например, с использованием KSP процессоров. Тогда о синхронизации позаботился бы сам Gradle, возможно с кодогенерацией.

Конечно, я только размышляю, могу ошибаться. Но есть идеи, которые можно глянуть как пример:

Fritz2 Lenses processor https://github.com/jwstegemann/fritz2/blob/master/lenses-annotation-processor - интересный подход, когда необходимая функциональность реализуется через функции-расширения (в данном случае через companion objects)

Kotlin RPC https://github.com/rjaros/kilua-rpc - интересная реализация RPC, которая берёт на себя реализацию "общения" клиент-сервер, мы только описываем интерфейс, а код (в данном случае через Ktor client и Ktor server) генерируется - именно здесь возможна минификация протокола - возможно, вообще можно сериализацию сделать бинарной по идеологии protobuf.

Конечная идея в том, что приложения (клиент-сервер или микросервисы) будут оперировать читаемыми объектами, а по сети они будут гоняться в ужатом нечитаемом виде - прозрачный подход. Да, минус в том, что какой-нибудь перехватчик трафика типа wireshark или DevTools браузера будут малополезны, но всегда можно предусмотреть отладочный режим, когда будут гоняться исходные джончики, а в проде (где, собственно, только там и нужно экономить трафик) как положено.

Ну и про сжатие http gzip уже писали. а если написать бинарную сериализацию (а то и использовать готовую https://kotlinlang.org/api/kotlinx.serialization/kotlinx-serialization-protobuf/kotlinx.serialization.protobuf/-proto-buf/ ) то можно комбинировать все упомянутые техники, и дополнительно, например, шифровать.

Впрочем, возможно, хватит и только http gzip + kotlinx-serialization-protobuf, это дёшево и сердито.

Да, всё верно. Наше решение очень быстро, дёшево и сердито, но, как вы верно подметили, и как я упомянул в конце статьи, в случае микросервисов встает вопрос о более "классических" решениях.

Спасибо за комментарий!

Козел светлый, изначально было двое, после половины ящика остался один.

Sign up to leave a comment.

Articles