Pull to refresh

Comments 67

Не смотрели в сторону использования редиса для хранения сессии? В томкате есть готовый коннектор.

Понятно что вам нужно переписывать решение с хранением предыдущих view но тем не менее.

Это же перевод. Не "вам", а "им".

UFO just landed and posted this here

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

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

UFO just landed and posted this here

Строкой, может быть чтобы не десериализовывать )) лишний раз.

Хотя ситуация - дичь

Ага, иначе статья называлась бы "Как мы оптимизировали загрузку процессора")))

Вот да. Плохо спроектированное решение (не подумали об ограничении глубины истории) привело к трагичным (для памяти) результатам — какая внезапная неожиданность!

Вообще странное решение конвертировать весь экран в строку и хранить в этой строке строку с предыдущим экраном.
Можно ж в базе хранить экраны как сущность и в этой сущности сохранять айди предыдущего экрана. Будет у вас стэк хоть на миллион фреймов с одной единственной конвертацией в джейсон.


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


"name": "\"Вася\""

Был бы повод насторожиться, как минимум. Но тесты, я так понимаю, написаны на отцепись, если вообще есть.

Не было неправильного конвертирования, в том и дело

У них вложенный json хранится строкой и каждый раз при сериализации в строку json удваивал эскейп слеши

Да, я понимаю.
Я поэтому и написал "условно неправильное". Правильное, с точки зрения спецификации, но не то, что ожидалось разработчиком.

Одно ужасное решение заменено другим не менее ужасным.

Хорошо, что автор перевода на Хабре не сделал третье ужасное решение и не сгенерил КДПВ в Кандинском 2.1 (с гроба бедного Василия Васильевича уже можно электричество добывать, наверное).

Просто поблочил превью статей с помощью uBlock. Полет нормальный.

UFO just landed and posted this here

Я видел экзотичное решение похожей проблемы экономии памяти: массивные объекты в памяти или Redis архивировались gzip и распаковывались при чтении.

В целом отличное решение, особенно если чанки небольшие, как тут

Согласен. Решение не экзотичное, а вполне приличное)

Если у вас пишет, что недостаточно места при выполнении команды
cat /dev/zero > file.log

то попробуйте
cat /dev/zero | gzip >file.log

мда .... а ведь это еще не ИИ!
(размышляет - как спросить ЧатЖПТ какие еще могут быть короткие варианты для "я олбанский вирус, запустите меня пожалуйст")

Хранение серилизованных объектов в памяти (иногда с упаковкой) для экономии памяти - типичное решение, которое используется сплошь и рядом

Кодировать в base64 и не экранировать сотню раз подряд? 🤔

Вообще не понял, зачем и почему возникает вложенное экранирование

Вложенное экранирование возникает изза того, что они ложили json как строку внутрь другого json

Какой чел вообще додумался делать матрёшку... Это же не возникла мысль "А не делаю-ка я фигню". Чё со свободным доступом к состояниям?

Возможно первоначально было ограничение на 1 предыдущий экран, а потом с годами кто-то доработал по заказу пользователей, кто знает...

Вложенное кодирование в base64 ещё хуже.

А ещё можно было сжать эту строку. Судя по большому числу повторяющиеся символов был бы профит.

Я всегда знал что укладывать json внутрь другого как строку — некрасиво, а теперь буду знать что именно в нём некрасивого :-)

Я в одном крупном банке видел как была с виду нормальная REST API, в ответ выдававшая json, внутри которого был svg-файл. Со всеми экранированиями, почти как в статье. Размер увеличивался примерно раза в полтора-два, не говоря уже про то, что потом этот svg просто отображался как картинка в браузере.

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

как-будто получилось O(n^2) по памяти, как в задаче про шахматную доску и зерна пшеницы.

И там и здесь O(2^n), что хуже.

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

Да нет, это классический индусский кодинг. Причём слово “индусский” здесь не указывает на национальность или вероисповедания.

Классические тесты такое не отловят. На тестовых данных все ок будет.

Не понимаю, о каких "классических" тестах вы говорите. Превращение \" в \\\" это тривиальный кейс для любого юнит-теста над строками.

В данном случае внутренний формат хранения состояния был никому не интересен (был бы интересен — такую фигню бы не нагородили), а значит и тестов на формат не было бы.


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

Разве тест вида: .Put, Put, assert(json, "{...}") где {...} - текст с двойными кавычками не самый что ни на есть классический unit test на этот код?

А в качестве текста для сравнения json, скопированный из отладочного вывода?

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

Как видно из 300MB, формат влияет на внешнее поведение. Ну и да, смысл в том чтобы задуматься, что там должно быть. Так то можно любой assert поломать просто копируя actual в excepted.

Ну и да, смысл в том чтобы задуматься, что там должно быть.

Вот в комментарии, на который вы изначально отвечали, человек и пишет, что если бы этот формат считался важным и о нём задумывались, то такой ерунды бы и не получилось. Тут (не)написание тестов точно не является первопричиной проблемы.


Как видно из 300MB, формат влияет на внешнее поведение.

И я бы предпочёл видеть в проекте тесты, валидирующие нужные свойства (в данном случае, в первую очередь performance тесты на уровне всего приложения), а не просто проверки, что внутреннее представление получилось именно таким, как задумывалось.

если бы этот формат считался важным и о нём задумывались

— Шеф, но я не думаю...
— Вот этим я от вас и отличаюсь! (c) Bonkers

Ну мое мнение - важны разные типы тестов. Performance тест поймал бы это только если бы кто-то запустил проверку с большим количеством предыдущих экранов (сотни) и не факт что кто-то стал бы добавлять этот сценарий.

А проверить unit тестом этот метод ничего не стоит, тут ведь и запись состояния идет. Выглядит на мой взгляд логично проверить, что все состояние там записано корректно.

По TDD так и вовсе сложно представить, что этот баг возникнет.

Типичный тест внутреннего стейта: сохранили в стейт - восстановили - сверили что восстановилось тоже самое что сохраняли. Прогнали N раз с разными параметрами. Все ок. Тест на внутренний стейт не нужен и будет удален при любом изменении формата. Он мешает больше чем помогает.

Перформанс тест вероятно тоже ничего не найдёт. Тут завит от того догадались сделать огромную историю или нет. Угадайка чистая. Хотя вероятно если бы догадались, то кто-нибудь такой кейс прогнал бы локально и сразу бы починил.

Меня побуждает написать unit test на state то, что метод public.

  public String toJson() {...jo.put("previous", previous.toJson());
}

Будь это что то вроде

public class State
{
  public void addScreen(Screen screen) {}
  public Screen returnPreviousScreen() {}
}

то и тестировать можно было бы только как вы описали.

Но ок, согласен, тут сложно предугадать нужен ли тест или нет.

Бесит, как в современном интернете работают кнопки "назад-вперёд" в браузере. Нажал на ссылку, и пока страница грузится - заметил краем глаза что-то интересное на странице, с которой уходишь. Нажал "назад" - а там всё берётся не из кеша, а опять тянется с интернета, и динамически меняется, того блока, что заинтересовал, больше нет и неясно как на него выйти, там теперь что-то другое. Потом, после возвращения на предыдущую страницу я хочу просто мгновенно оказаться там же, где был, а вместо этого (при условии небыстрого интернета) происходит следующее: сначала я попадаю на свежеперезагрузившуюся страницу в самый верх, начинаю быстро скроллить до места, где остановился, тут начинают подгружаться картинки, фреймы с рекламой и текст, который я читаю, дёргается и прыгает вверх-вниз, и наконец, когда всё загрузилось, срабатывает скрипт, который по идее должен поставить скроллинг страницы в старое положение, но не учитывает, что пользователь уже давно сам скроллит и читает, и текст в очередной раз выдёргивают и помещают скроллинг хрен пойми на какую позицию, заставляя снова скроллить и искать где я остановился. А если пропал интернет, я тупо не могу сделать "назад", хотя казалось бы, что проще - возьми данные страницы из кеша! И сохранение страниц на диск - та же боль: вместо того, чтобы молча оффлайн сохранить страницу в файл, браузер начинает её заново выкачивать, часто при этом происходит какая-нибудь ошибка и сохранение не удаётся (где такое видано?), а в мобильных браузерах и вовсе по непонятным причинам поубирали экспорт страницы в .html или хотя бы в .pdf. Зачем всё это?

Вот да, полностью поддерживаю.

Даже не понятно какой процент контента грузится из кэша при переходе на предыдущую страницу. Нам бы хотелось чтобы было 100%.

Но увы, SEO, маркетинг и эффективные менеджеры победили.

Там в KPI есть метрики которые крутятся если есть загрузка страницы. Из-за этих метрик появилось такое явление как "протухание" страницы. Не сессии, а страницы!

В особо тяжких случаях, для накрутки счетчиков и показа большего количества рекламы текущая страница сама перезагружается раз в несколько секунд. Хотя с этим начали бороться и уже реже встречается. Но сам факт существования такого явления удуручает.

Насчёт процента не скажу, но у Хрома, вроде бы, появился хороший анализатор bf-cache, вы сможете сами посмотреть почему страница не кешируется. Там кое-как расписано (просто иногда гуглить надо, чтобы расшифровать):

https://developer.chrome.com/docs/devtools/application/back-forward-cache/

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

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

В Opera есть сохранение для просмотра в оффлайне и экспорт в PDF.

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

Вот это как раз древняя проблема, из времён до history api

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

Ничего не поубирали. У себя в хроме только что проверил - кнопка скачивания страницы имеется.

В браузере тоже так подумали и не так давно внедрили новую фичу - Back/forward cache, которая сохраняет снапшоты с предыдущими страницами и позволяет быстро восстанавливать. Но, нужно чтобы сайт не использовал некоторые фичи JS - https://web.dev/bfcache/

UFO just landed and posted this here

По приведенной ссылке есть ссылка на сайт мозиллы, где описывается, как использовать этот кеш в Firefox 1.5 :D

UFO just landed and posted this here

Как джавист со стажем скажу, что когда видишь вопрос "почему на клиента 300mb?" и при этом рядом есть слово Java, то ответ сам собой напрашивается )))) Загадка не сложная )))

Приманил заголовок, а всё так банально…

Очень прошу прощения, но:

1960-е годы: Бортовой компьютер Аполлона с 72 Кб памяти доставляет человека на луну и обратно...
2023-й год: *строчка на 1.5 Гб из обратных слешей*

Где мы свернули не туда ?!)))

В той точке, в которой фразу про "640 кБ хватит каждому" стали воспринимать как повод для стёба, а не как руководство к действию)

1) зато код можно писать как текст

2) зато код можно писать не на той машине, "которая полетит" (которая с уникальной и неповторимой архитектурой команд, способом храниения, выполнения, задержек и других ограничений, о которых нужно помнить), а которая у тебя дома (вот скажите - как часто джаваскрипт программисты сидя за десктопами размышляют о том, как их объекты выглядят в памяти мобилок?)

Эх... так надеялся в конце статьи увидеть "после этих изменений среднее потребление памяти пользователем уменьшилось с xx до yy МБ"

Sign up to leave a comment.

Articles