All streams
Search
Write a publication
Pull to refresh
47
0
Дмитрий Казаков @DmitryKazakov8

Front-end архитектор

Send message

В классической есть домены - это папка pages. Логичная и непротиворечивая система, когда страница или группа страниц есть отдельная сущность, которую можно вынести в микрофронт при необходимости. Не нужно других синтетических абстракций фич, энтити, виджетов - "страница" есть семантическая сущность веб-приложений изначально с изобретения веба. Она включает в себя отображение и бизнес-логику, изолированную от остальных страниц.

С развитием компонентного подхода пришел концепт переиспользуемости, то есть в src/components кладутся однообразные компоненты типа Button, Form, Cart. Они могут использовать глобальные вызовы api и читать данные из глобальных сторов globalStores, но могут и через пропы принимать что-то кастомное, специфичное для страницы, на которой используются. Это логичное, минималистичное и удобное деление и называется "классической структурой", и в статье показан ее кастомный вариант, который хорошо масштабируется и интуитивно используется, несмотря на определенную чрезмерную интерпретацию (типа pages и layouts почему-то кладутся в components).

Внимательно читаю вашу дискуссию, но я тут на светлой стороне, хотя в словах Клерика она звучит грубо иногда)

В этом треде вы что-то в абстракции ушли) На деле оба за домены, просто в классической структуре домен это `pages/somePage`, а в фсд это сгруппированно в некую features или виджет или куда там еще. Конечно, в классической все удобнее - можно решить на уровне роутера. Допустим, некая страница разрослась до больших размеров и у нее десяток связанных подстраниц, решили выделить в отдельный проект - в этом случае выносится только папка страницы

const routes = createRouterConfig({ 
  maning: { 
    path: '/maning/*', 
    // loader: () => import('./pages/maning'), 
    loader: () => import('https://some-url/component.js'), 
    props: { globalComponents, globalApi, globalActions, globalStores } 
  } 
});

Вот и получился микрофронт. Внутрь переданы пропсы с глобальными слоями, которые микрофронтом кладутся в контекст и используются оттуда вместо es-импортов (ts-типы линкуются разными способами). При этом он внутри по той же самой "классической" структуре имеет те же самые папки, просто все его слои работают только внутри этого микрофронта.

Это прекрасно ложится на большие проекты.

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

Я не про fsd сейчас, просто зацепился за сам концепт)

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

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

Мутабельность можно сделать и с помощью других паттернов, прокси вовсе не обязательны. Главное - интерфейс, что при мутации значения происходит ререндер. Что не нужно делать ни useReducer, ни setValue. И жесткие ограничения на интеграцию с другими системами реактивности Реакт тоже не красят - намерение плотно привязать на его экосистему и его подходы как раз и мешают более эффективным решениям "стать общепринятым стандартом". Как бы сообщество ни хотело исправить это - получаем только новую пачку хуков, решающих проблемы, которых и не должно было бы быть.

Статья просто пронизана болью, даже выводы дочитать не смог. Болью веб-студии, которой попадаются классические заказчики, которые не знают, что им нужно, и не понимают сложности внедрения и изменения функционала. Будто вернулся на 10 лет назад, когда тоже в такой конторе работал) К сожалению, это очень неблагодарная и рисковая сфера как для бизнеса, так и для разработчиков. И научить всех клиентов "сформировать план работ и выстроить грамотную коммуникацию" точно не получится. Остается посочувствовать и пожелать удачи.

Это повод сказать, что Реакт очень медленно развивается, и этот релиз - в основном работа над ошибками, а не большой шаг вперед. Есть библиотеки как mobx, которые уже давно продвинули его на несколько шагов вперед, сделав удобный механизм работы со стейтом, и оставив Реакт только для рендера компонентов.

Я думаю, что именно на этом Реакт и должен концентрироваться, а не перерастать в большую неэффективную систему, пробуя на аудитории новые подходы в виде хуков (функции в функции с сайд-эффектами и невидимым кешем) со строгими правилами (или не очень строгими, а очень странными, как в случае с новым use) или серверные компоненты.

К сожалению, state.props = props; очень не понравится mobx, если в MyComponentLocalState будет зависимость от этих пропов или геттеры - скажет, что синхронно менять значения при рендере нельзя. Поэтому придется использовать useEffect

Спасибо за статью. Под "в этот раз опирались на более объективные критерии, и выбор был очевидным", как понимаю, имеется в виду MobX? Если так - могу посоветовать пару удобных подходов mobx-stateful-fn и mobx-use-store - они дают очень удобные механизмы. Там же рядом и неплохой роутер, вдруг пригодится)

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

Но библиотека хорошая, спасибо за статью.

Почему плохо - я привел несколько аргументов в комментарии выше.
Про сильную связанность с view, про сложность с SSR, про невозможность вызова вне Реакта (например до рендеринга приложения или в ответ на какую-то реакцию), про сложности генерации реалтаймовых валидаторов, про отсутствие возможности протестировать вне компонентов, про слабую связь со стором (например для вывода нотификаций).
Как хорошо - делать независимый от фреймворка слой апи, при необходимости передавая в него разные сущности типа сторов, экшенов, локализации. Пример я приводил здесь https://github.com/mobxjs-ru/api-by-config

На мой взгляд, сокращение имен классов - это экономия на спичках в ущерб DX.

  1. При сжатии gzip/brotli экономия на большой html будет в байтах, максимум - в паре килобайт. Это не повлияет на оценку Lighthouse и на пользовательский опыт, если вы не гонитесь за тысячными долями процента перфоманса

  2. При чтении дерева элементов в инспекторе видим несемантичные j1 g83 классы, соответственно как найти место в коде, в котором нужно поправить стиль? Можно переключиться на React Dev Tools, выбрать элемент, потом обратно в инспектор, проверить там новые стили, и дальше - копать код проекта, перебирая папки и файлы в рандомном порядке. Проблема усугубляется тем больше, чем больше разработчиков в компании, и чем хуже знаешь кодовую базу проекта. Частично проблема решится CSS maps, но тоже много лишних телодвижений.

    При этом семантичные CSS Modules сразу покажут где находится файл - src-components-layouts-userMenu src-pages-user.

  3. При регистрации ошибки в Sentry например, разработчик смотрит путь, который пользователь накликал (в Сентри это логируется). И в случае сокращенных имен он увидит click[.j1] - как с этим работать? Скорость дебага значительно увеличится.

  4. Для автотестов стабильные имена [path][name]__[local]--[hash:base64:5] можно использовать как уникальные идентификаторы элементов в ряде случаев и обойтись без data-test-id или id (если не учитывать в селекторе hash). Также можно дать не сильно разбирающемуся в автотестах сотруднику визуальный инструмент накликивания пользовательских сценариев. Тогда он передаст разработчику семантичный список действий click[.src-components-layouts-userMenu] и разработчик при необходимости очень быстро добавит id либо оставит селекторы в оригинальном виде, если эти классы достаточно специфичны.

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

Должен быть контект для решения задачи. "Наш продукт имеет систему виджетов, которые могут получать данные из разных источников, поэтому рассмотрим вариант когда url для фетча передается в компонент из внешнего источника". Дальше - "допустим, вы решили делать фетчинг через кастомный хук, расскажите, какие минусы и плюсы у этого решения и как бы вы это реализовали". Вот это была бы достойная задача на собеседование, проверяющая глубину опыта. А без контекста - это конь в вакууме, проверяющий читали ли вы документацию Реакта и fetch, чтобы проверить самую базовую базу

Ну вот позвольте рассказать, как я бы воспринял эту задачу, чтобы объяснить мою позицию.
Я работал в десятке компаний и сделал больше сотни сайтов, половина - на Реакте. Каждый день вырабатывал практики, как организовать слои приложения так, чтобы они были одновременно независимыми и при этом легко интегрировались друг в друга.
Я ожидаю, что на собеседовании проверят не то, как я различаю == и ===, и не чему будет равно [] == true, а проверят реальный опыт на реальных задачах, чтобы я смог показать глубину опыта.
Мне дают на собеседовании задачу про "компонент получает url", на что я сразу напрягаюсь, "компонент функциональный", на что соответственно сразу думаю про SSR, "хук, которых фетчит данные", на что сразу думаю - куда я попал?
Первое, что я отвечу - так делать нельзя и только джуны могут так делать. Расскажу про все, что перечислил в первом посте, займет минут 20. У собеседующего время ограничено, он не проверил мое "знание хуков Реакта", но получил море как бы не связанной с изначальным намерением информации.

Адекватный собеседующий скажет "тогда давайте заменим получение данных по апи просто на асинхронную функцию", и тогда я сразу соглашуть написать то решение, которое приведено в статье - с зависимостями во втором аргументе useEffect и с возвращением псевдо-прерывающей функции, чтобы при размаунте результат не обрабатывался. Конечно, добавил бы про обсерваблы, про варианты обхода ручного (!cancelled), про унификацию обработки, про типизацию ошибок, про коннект к разным частям приложения, про слои и т.п. еще на час беседы, но т.к. время ограничено и я четко понял, что задачей хотят проверить "понимание основ React", то опустил бы.

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

В итоге - мы оба потратили много времени на обсуждение организации апи и по итогу часа я выполнил 1 задачу из 3. Собеседующий так и записал, пришло письмо от HR "вы нам не подходите". История не особо выдуманная, на опыте было немало такого) Может, это мои заморочки, что не готов обсуждать совсем базовые штуки (шутка про Яндекс, в который я прошел около 20 собесов в разное время, чтобы увидеть какая дичь у них в коде), но и на джуна я не собеседуюсь - а такие вопросы тем не менее в каждой первой компании.

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

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

Да, как отправную точку - отлично, но в выводе статьи - "Задачка позволяет проверить, как кандидат понимает устройство рендеринга React...", то есть ответ "так нельзя" скорее всего приведет к тому, что интервьюер либо решит, что задачу кандидат не решил и не знает основ, либо не сможет проверить эти знания потому что под рукой нет более подходящей задачи. То есть все же считаю что правильно сказал - определенные разрабы отсекутся этой задачей, потому что она проверяет для интервьюера одно, а для соискателя может быть совсем другое (знание архитектур, а не setState и useEffect Реакта)

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

Эта задача проверяет исключительно понимание реализации на функциональных компонентах Реакта с использованием хуков. Для проверки этого можно придумать пример порелевантней, потому что если использовать кейс получения данных по апи - то адекватный ответ для всех, кроме джунов, это - "так делать нельзя". А джуны как раз будут пилить setState, useEffect, обрабатывать ошибки и бороться с race condition) То есть как раз "уверенно владеющие основами" люди. Если надо найти именно таких - то статья релевантная, хотя лучше бы без вызова апи, потому что отсекает более опытных разрабов.

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

  • как организовать апи, чтобы можно было вызывать как из Реакта, так и из экшенов / моделей / реакций, и при этом в Реакте можно было узнать состояние запроса и отобразить лоадер

  • как сделать изоморфные вызовы во всех этих кейсах, чтобы SSR дожидался выполнения всех вызовов из всех мест и показывал финальный html пользователю, при этом при ошибке критичных запросов редиректил на страницу 500 или применял другую стратегию

  • как организовать типизированные запросы (чтобы не строки передавать в качестве урла, а аргументы функции) и обогащение запросов хедерами типа авторизации (это тема про "отдельный независимый слой апи")

  • как тестировать апи с моками и отдельно от вью/моделей и других слоев, а также в связке с ними

  • как сделать реалтаймовую валидацию входящих-исходящих данных исходя из TS-моделей

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

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

В дополнение к предыдущим комментаторам, всегда можно добавить соответствующие редиректы вручную. Для node js например таким кодом:

    if (req.url.endsWith('.js') || req.url.endsWith('.css')) {
      const acceptedCompression = getAcceptedCompression(req);

      if (acceptedCompression) {
        req.url = `${req.url}.${acceptedCompression.extension}`;
      }
    }

Полный пример - тут.

Полумеры для production не подойдут) Либо делать качественную обработку, либо пожертвовать чанками. Никто не будет следить вручную за всеми зависимостями, которые используют чанки - раз сделаешь импорт lodash - прибавится 500кб в несжатом виде, условно. Поэтому и написал в статье, что для тех проектов, в которых нужно минимальное количество js на старте, esbuild не подходит

Rollup+swc это аналог webpack+swc. Postcss как я указал в статье уже используется, то есть с css проблем не будет. Скорость однозначно лучше у esbuild, а на счет поддержки ts - можно же использовать esbuild+swc, тогда все, что поддерживает swc, можно использовать.

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Date of birth
Registered
Activity