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

Большая часть моего пути в качестве разработчика программного обеспечения заключалась в написании кода JavaScript, и я чувствую, что синдром NIH (Not Invented Here) намного сильнее проявляется в сообществе JS. Каждый день выходит новая библиотека для решения какой-либо задачи. Некоторые из них полезны, например https://www.npmjs.com/package/is-even.

Так что да, может быть, пока вы читаете эту статью, я пытался написать свой JQuery и свой CSS-фреймворк (и с треском провалился), но на самом деле я никогда не думал, что создам свой вроде Storage Engine. Спойлер: я этого не сделал — по крайней мере, не так, как должен был.

Этот пост открывает серию эссе о пути моей команды к внедрению автономного режима в приложении Ionic.

Изображение на обложке:https://www.blog.bixlabs.com/post/offline-first-mobile-apps

Оффлайн что ли?

Мне нравится определение в документации по Android.

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

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

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

Где мы были

Как уже упоминалось, наше мобильное приложение было гибридным, написанным на Ionic. Бэкенд был написан на NodeJS, в основном это бессерверные функции с AWS Lambdas. Для базы данных мы использовали MongoDB.

Между нашим приложением и AWS per si существовал BaaS (бэкенд как услуга). Это обеспечило комбинацию между платформой Parse и AWS. Он предоставляет некоторые возможности, такие как аутентификация, хранение файлов, тип ORM и так далее. Вроде бы замечательно, но бесплатного обеда не бывает, это приносит некоторые проблемы, вроде меньшей гибкости.

В общем, вот как все было спроектировано.

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

По характеристикам у нас было следующее:

  • цикл — пользователи могли создавать свои учебные циклы;
  • регистрация исследований — наши пользователи могли регистрировать свои исследования и иметь о них статистику;
  • таймер для учебы — пользователь может запустить таймер для определенного предмета и может установить будильник, который будет оповещаться, когда время истекло.

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

Начните думать об оффлайне

Затем мы начали думать о нашей офлайн-реализации. Сначала это выглядело хорошо и просто. У нас был код TypeScript, который является просто надмножеством JavaScript, а JavaScript хорошо работает с JSON. И это то, что документ MongoDB является правильным? Это JSON.

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

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

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

Вы когда-нибудь задумывались о реализации в автономном режиме? Ну, я могу вспомнить свои мысли по этому поводу. Я такой: «Круто, это просто вопрос сохранения данных на локальном устройстве, а потом, когда они подключатся, просто отправить их на сервер».

Мой план был:

  • код только читает из локального хранилища (сделаем JSON.stringify в объектах);
  • когда данные получены, обновить локальное хранилище;
  • все записи сначала выполняются в локальном хранилище;
  • отправить на сервер при наличии соединения.

Вы знаете, оглядываясь назад, это все еще кажется хорошим планом, потому что некоторые из этих идей я почерпнул из того, как Firebase делает для Cloud Firestore. Но в том-то и проблема, что это далеко не просто.

Основные вопросы по этому поводу: Синхронизация и Эффективность Local Storage. Мы будем говорить об этих проблемах в следующих постах, но позвольте мне обобщить их.

Эффективность локального хранилища

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

Проблемы, с которыми мы столкнулись:

  • плохая производительность при поиске конкретных данных
  • плохая производительность при поиске диапазона данных
  • агрегированные расчеты
  • сохранение данных в локальном хранилище

Синхронизация

Наш первый враг был сильнее. Нам нужно будет обработать синхронизацию, нам нужно будет ответить на эти вопросы:

  • когда данные отправляются на сервер?
  • откуда мы знаем, какие данные мы должны хранить? текущая или входящая? (конфликты)
  • как обрабатывать удаления?

Краткое содержание

Мы были командой из ОДНОГО разработчика (мы были в процессе заключения контракта с еще одним), у нас не было хорошего технического руководства, и мы торопились (похоже, это путь стартапа). Итак, мы приняли много неверных решений, и я считаю, что самое серьезное из них — это не столько экспериментировать, сколько следовало бы.

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

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

Вот и все. До встречи!

Рекомендации