Skip to content
 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Задание

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

Репозиторий содержит некоторе решение некоторой задачи. И задача и решене здесь приведены только для наглядности. Ответ на каждый вопрос принимается исключительно про ваш реальный опыт над реальным проектом. Мы ожидаем развернутых ответов.

Решением задания будет написание ответов на вопросы ниже. Ответ можно отправить в свободной форме.

Аутентификация

Для аутентификации в этом репозитории используется jwt токен. Технология известная, зарекомендовавшая себя. Давайте в ней усомнимся. Как минимум - в целесообразности гонять в каждом http запросе такой большой кусок данных. Расскажите о проектах с вашим участием, где использовалась другая техника авторизации. Если в таких проектах вы бы могли выбирать - выбрали бы вы аутентификацию через jwt? Если да, то почему? В каком проекте, в котором вы участвовали, вы бы наоборот, вместо jwt выбрали что-то другое и почему?

Для большинства случаев client-server общения, действительно, JWT подходит более чем отлично. Если искать альтернативу, то конечно можем просто сравнить два подхода:

  1. Stateless, куда и попадает сам JWT
  2. Stateful, куда попадает, например, session

Относительно размера постоянно пересылаемых данных, здесь мы экономим, потому что по сути к базе запроса мы добавляем только куку с, скорее всего, sessionId и expiresAt. Не могу сказать, что часто использовал именно этот подход в своих проектах, потому что у него есть большой trafeoff по поддержанию механизма для хранения и инвалидации собственно самих сессий, в то время как JWT не требует таких издержек на разработческий ресурс. НО! Я бы конечно мог рассмотреть сессии в проектах, где есть следующие узкие места:

  1. Размер JWT тормозит общий тайминг запроса (с момента инициации отправки до момента получения ответа от сервера).
  2. saltRounds может внезапно начать тормозить валидацию токена ("превращение" токена в юзера). Если запросов много и раундов много (а понизить кол-во раундов мы не можем по какой-либо причине).
  3. Приходится во многих обработчиках запросов добавлять получение роли, разрешения, и т.п. Тогда нам было бы конечно удобнее разово создать сессию с этими даннами, а далее просто по куке получать их. Хотя в подобных местах я просто использую гибридный подход JWT + кэш в каком-нибудь Redis или TarantoolDB.

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

Идентификация

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

uuid мог бы стать проблемой везде, где используется SQL ДБ и нужна высокая скорость записи. Т.к. "рандомная" (грубо говоря) генерация требует бОльшего хранения, чем какой-нибудь autoinc INT/BIGINT. Без детального ресерча, можно примерно предположить, что разница будет как минимум на один порядок. Что очень много для условных миллионов записей.

  • Это можно парировать тем, что мы не хотим показывать юзеру, что он id 777 (вдруг не хотим распространять инфу о том, сколько юзеров было в системе до его регистрации). Но 777 всегда можно зашифровать с постоянным секретом и отдать юзеру строку, которая затем дешифруется в 777 на сервере.

Также, для дебаггинга, когда мы хотим понимать последовательность записей, это намного удобнее делать с autoinc'ом.

Организация кода

В этом репозитории, серверный код сделан на базе NestJS. DI, services, controllers, middleware, decorators - в этом, как и во многих других подходах есть плюсы и выгоды. Расскажите с примерами из опыта о реальной пользе того или иного механизма организации кода лично для вас или для вашей команды, а может быть - для компании. Если есть какой-то механим, который также - для вас, команды или компании наоборот - создавал сложности - тоже расскажите.

Nest.js для меня сильный фаворит именно благодаря своему DI, а именно о пользе:

  1. Возможность разграничивать бизнес логику (сущности и бизнес требования) от деталей (база данных, провайдеры интеграций и т.п.). Инверсия зависмости от деталей - это самая главная суперсила DI и Clean Architecture от Дяди Боба в целом. Так мы делаем software, собственно, soft - мягким, гибким и легким в изменении. На своем опыте познал на сколько это важно, когда собирал проекты с ограниченным разработческим ресурсом.
  2. В добавок к пункту выше, мы также можем собирать прототипы быстро, но без последующего переписывания аля "гипотеза проверена, теперь уже давайте писать нормальный чистый код". Потому что DI позволяет нам создавать изначально только абстракные сервисы вроде game-tapper.i.service.ts (i - интерфейс в нейминге файлов). Используя эти абстракции, мы максимально быстро набрасываем в контроллерах бизнес логику. Когда мы хотим потестить/показать приложение, в качестве первой быстрой детали мы можем добавить просто запись в локальный json и делаем имплементацию абстрактного сервиса в game-tapper.json.service.ts. Мы не замарчиваемся на миграции, конфликты схем, поднятие баз. Мы просто быстро доставляем запрошенные требования бизнесу. Когда мы закончили с основной бизнес логикой и готовы выбирать базу данных, мы просто создаем импелментацию game-tapper.pg.service.ts (PostgreSQL).
  3. Больше про базы данных. Это очень mission-critical решение, которое нужно выбрать исходя из обоснований. Когда кодовая база пустая, эти решения просто невозможно принять. Но после готовой бизнес логики, с пониманием основных паттернов запросов, это можно сделать максимально обоснованно.
  4. Еще это большое упрощение для тестирования. Потому что простые unit тесты еще проще писать по абстракциям.

Но Nest.js проект можно легко превратить в клубок из циклических зависимостей (маркер того, насколько плохой maintainability у приложения). Чтобы этого избежать, я использую паттерн monorepo в Nest.js. В корне появляются apps и libs.

  • В apps хранятся единицы деплоя, например, backend, worker.
  • В каждом таком приложении есть ресурсы, например, games. У каждого ресурса может быть свой личный набор сервисов.
  • Иногда сервисы нужно переиспользовать между ресерсами или даже apps. Такие сервисы энкапсулируются в libs.

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

Реактивность

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

Да, были ситуации, где реактивность React скорее мешала. Обычно это частые и необязательные ререндеры. Самый типичный кейс для меня: drag-and-drop редакторы, где координаты элементов меняются постоянно во время перетаскивания.

Если делать это "вручную" через общий state, легко поймать лишние ререндеры всего дерева. Поэтому в таких задачах я обычно использую соответсвующие библиотеки чтобы не изобретать велосипед. Либо паттерны вроде debouncing, для более кастомного контроля.

Что именно мне неудобно в React в таких сценариях:

  1. Нужно постоянно следить за ссылочной стабильностью (useCallback/useMemo), иначе оптимизации быстро разваливаются.
  2. Родительские апдейты легко тянут за собой лишние ререндеры детей, хотя это может и не нужно.
  3. Для high-frequency UI приходится строить гибридный подход, а не полагаться только на "чистую" реактивность.

По альтернативам: у меня есть опыт с Flutter. В задачах с частыми координатными апдейтами Flutter часто дает более предсказуемую производительность за счет собственного рендер-пайплайна и явной модели перерисовки через widget tree. React я бы все равно выбирал для web-экосистемы и скорости продуктовой разработки, но для визуально-насыщенных интерактивных сцен Flutter обычно ощущается стабильнее по FPS и проще в профилировании.

В качестве другой альтернативы, где React частые ререндеры снижают производительность - это gamedev. В целом, многие браузерные игры можно писать на чистом React, но нам нужен хороший FPS, который достигается в вэбе через рендер в <canvas />. Можно, например, в таком случае написать собственный рендер в requestAnimationFrame() или воспользоваться готовыми фреймворками вроде Three.js, Babylon.js. В качестве пет-проекта я как раз пишу игру с графическим слоем на Babylon.js и React.js в качестве переферийного UI, где у него почти нет tradeoff'ов.

Если говорить исключительно об обычном UI, а не экзотике вроде геймдева, можно также рассмотреть Svelte, где нет VDOM диффа и изменение стейт переменной x не влечет за собой перерисовку всего дерева после родителя, где произошло изменение. В Svelte поменяются только те части, где x используется. Хотя здесь меня не совсем устраивает tradeoff в файлах *.svelte и *.svelte.ts - сильная зависимость от фреймворка, что противоречит Clean Architecture. Нужно выбирать исходя из конкретной ситуации.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages