Я сейчас занимаюсь переработкой и улучшением документации, в частности, DX гайдлайнов. И сегодня хочу поднять такую тему, как корпоративная архитектура. Данный пост больше о причинах, чем о конкретных практиках. По мере прогресса в работе я буду выкладывать прикладные советы.
Корпоративная архитектура обеспечивает структуру, управление и стандартизацию кодовой базы. Без корпоративной архитектуры проекты одной компании могут сильно отличаться друг от друга, даже если они написаны на одинаковом стеке. И это ведет к следующим проблемам:
Этот список можно продолжать и дальше, но все тезисы сводятся к тому, что без архитектуры увеличивается время и стоимость разработки, и уменьшаются довольство разработчиков и стабильность приложения.
Более прикладные советы будут в следующих постах, а резюмируя этот пост, я бы посоветовал обзавестись простой и короткой документацией, которая лежит на видном для всех месте и регулярно обновляется.
@js_is_easy
Корпоративная архитектура обеспечивает структуру, управление и стандартизацию кодовой базы. Без корпоративной архитектуры проекты одной компании могут сильно отличаться друг от друга, даже если они написаны на одинаковом стеке. И это ведет к следующим проблемам:
1.
Масштабируемость. Если заказчики захотят добавить одинаковый или похожий модуль в несколько проектов, то в каждом проекте разработчики будут изобретать свои велосипеды.2.
Коллаборация и поддержка. Когда разработчик переходит из одного проекта в другой, или просто временно подменяет кого-то, то переключение между проектами отнимает много ресурсов, а потом еще проблемы на ревью, т.к. у другой команды принято “по-другому”.3
. Повторное использование кода. Когда нет четких правил, где и что хранить, UI рано или поздно начинает смешиваться с логикой, и чтобы перенести компонент из одного проекта в другой, приходится его очищать от бизнес-логики.4
. Корпоративный набор библиотек. Здесь проблема, как во 2 и 3 пунктах вместе взятых, когда на каждом проекте свой зоопарк менеджеров, состояний и других взаимозаменяемых пакетов.Этот список можно продолжать и дальше, но все тезисы сводятся к тому, что без архитектуры увеличивается время и стоимость разработки, и уменьшаются довольство разработчиков и стабильность приложения.
Более прикладные советы будут в следующих постах, а резюмируя этот пост, я бы посоветовал обзавестись простой и короткой документацией, которая лежит на видном для всех месте и регулярно обновляется.
@js_is_easy
👍13❤4🤔2
Если рассматривать проблему коллаборации из предыдущего поста в рамках моей компании, то один из его пунктов заключался в том, что конфиги Eslint, prettier и TypeScript отличались от проекта к проекту иногда достаточно сильно. Для решения этой проблемы было решено вынести все конфиги в единое место.
Я создал монорепу с помощью lerna и добавил пакеты настроек линтеров и TS. Внутри пакетов ничего сверхъестественного: обычный package.json + соответствующий файл конфига (.eslintrc.js, prettier.config.js, tsconfig.json)
Дальше – конфиги подключаются довольно просто:
1. Устанавливаем пакеты в проект:
В результате получается, что все настройки линтеров спрятаны в пакеты, как и их зависимости. Например, в package.json проектов теперь нет явной зависимости eslint и его плагинов, все это содержится внутри пакета
Планируем добавить аналогичные общие конфиги для сборщиков и тестов (пока в процессе стандартизации).
P.S. Этот подход будет применен только к свежим и будущим проектам. Кардинальное изменение правил линтинга для старых проектов приведет к тому, что вся IDE будет светиться красным, а если исправлять эти ошибки, то испортится история коммитов.
P.P.S. Настройки можно наследовать и относительным путем. На случай, если у вас монорепа и выносить настройки в отдельный пакет нет желания.
@js_is_easy
Я создал монорепу с помощью lerna и добавил пакеты настроек линтеров и TS. Внутри пакетов ничего сверхъестественного: обычный package.json + соответствующий файл конфига (.eslintrc.js, prettier.config.js, tsconfig.json)
Дальше – конфиги подключаются довольно просто:
1. Устанавливаем пакеты в проект:
npm i @our-tools/eslint-config @our-tools/prettier-config @our-tools/ts-config
2. Наследуем каждый инструмент соответствующим образом (примеры на картинке). Я предпочитаю наследовать конфиги eslint и prettier в файле package.json. Да, это менее популярно, чем отдельные файлы, но, как показывает практика, желающих переопределить правила линтинга в файле package.json оказывается меньше 🤷♂️.В результате получается, что все настройки линтеров спрятаны в пакеты, как и их зависимости. Например, в package.json проектов теперь нет явной зависимости eslint и его плагинов, все это содержится внутри пакета
@our-tools/eslint-config
. Естественно, инфа по использованию конфигов прописана в хэндбуке и онбординг доке.Планируем добавить аналогичные общие конфиги для сборщиков и тестов (пока в процессе стандартизации).
P.S. Этот подход будет применен только к свежим и будущим проектам. Кардинальное изменение правил линтинга для старых проектов приведет к тому, что вся IDE будет светиться красным, а если исправлять эти ошибки, то испортится история коммитов.
P.P.S. Настройки можно наследовать и относительным путем. На случай, если у вас монорепа и выносить настройки в отдельный пакет нет желания.
@js_is_easy
👍11❤3🤔2
Стартовый шаблон
Еще одно решение, позволяющее организовывать разработку и поддерживать корпоративную архитектуру – это стартовый шаблон.
Реализация идеи довольно проста: создать проект-шаблон, включающий все базовые корпоративные зависимости, настройки и рекомендации, а затем форкать его для каждого нового проекта. Шаблон удобно обновлять и поддерживать. Проекты, основанные на этом шаблоне, можно обновлять путем мержа из шаблона.
Минус данного решения заключается в том, что оно не очень гибкое. Один шаблон – один тип проекта. Если активно развиваются не только основные приложения, но и виджеты, то придется обзавестись несколькими шаблонами, так как каждый тип проектов будет иметь свою специфику и зависимости. Например, самостоятельному приложению нужны зависимости react и react-router, а виджету - Storybook.
В качестве альтернативы можно рассмотреть генераторы, такие как Yeoman или Mustache.js (или даже их комбинацию с шаблонами). Они достаточно гибкие, но требуют больше времени на разработку и поддержку.
@js_is_easy
Еще одно решение, позволяющее организовывать разработку и поддерживать корпоративную архитектуру – это стартовый шаблон.
Реализация идеи довольно проста: создать проект-шаблон, включающий все базовые корпоративные зависимости, настройки и рекомендации, а затем форкать его для каждого нового проекта. Шаблон удобно обновлять и поддерживать. Проекты, основанные на этом шаблоне, можно обновлять путем мержа из шаблона.
Минус данного решения заключается в том, что оно не очень гибкое. Один шаблон – один тип проекта. Если активно развиваются не только основные приложения, но и виджеты, то придется обзавестись несколькими шаблонами, так как каждый тип проектов будет иметь свою специфику и зависимости. Например, самостоятельному приложению нужны зависимости react и react-router, а виджету - Storybook.
В качестве альтернативы можно рассмотреть генераторы, такие как Yeoman или Mustache.js (или даже их комбинацию с шаблонами). Они достаточно гибкие, но требуют больше времени на разработку и поддержку.
@js_is_easy
👍10❤2🔥2
Теперь вернемся на несколько уровней выше, к конкретным архитектурам.
Когда мы согласовывали корпоративную архитектуру, то рассматривали 3 варианта: Microfrontend через Module Federation, Atomic Design System и Feature Sliced Design. Старые проекты внутри себя уже были разделены на формальные модули, так что внедрение MF приняли единогласно, т.к. даже независимые деплои уже давали профит.
Однако сами по себе микрофронты никак не организуют код внутри модулей, поэтому нужно было решить, что внедрять дальше: ADS или FSD. На мой взгляд, FSD – отличная методология с самодостаточной философией и подходом, и я хотел протестировать ее на реальном проекте и понять все подводные, но… бэкграунд проектов сыграл свою роль:
1. Пара команд уже успешно внедрили ADS к себе в проекты в тестовом режиме.
2. С FSD ни у кого не было боевого опыта, поэтому переход мог быть достаточно долгим и болезненным.
3. Когда мы разрабатывали UI-кит, то договорились с дизайнерами, что они тоже будут следовать ADS методологии.
Да, ADS имеет свои недочеты, например, нет четкого соглашения, где хранить бизнес-логику и вспомогательные утилиты. На данный момент мы просто условились не спускать бизнес логику ниже уровня страниц, а универсальные утилиты переедут в отдельную внутреннюю репу с тулзами. Кстати, у нас UI-кит – это отдельная репа, и в MF приложениях, в большинстве случаев, почти не будет атомов, молекул и организмов. Они будут тянуться прямиком из кита.
Резюмируя, хочу сказать, что не надо внедрять что-либо просто потому что это сейчас модно. Сделайте анализ, оцените технический скилл и настрой команды, изучите бэкграунд проектов и потом принимайте решение.
P. S. Позже я планирую разобрать плюсы и минусы каждого подхода более подробно, а пока, те, кто заинтересован, переходите по соответствующим ссылкам в первом абзаце.
@js_is_easy
Когда мы согласовывали корпоративную архитектуру, то рассматривали 3 варианта: Microfrontend через Module Federation, Atomic Design System и Feature Sliced Design. Старые проекты внутри себя уже были разделены на формальные модули, так что внедрение MF приняли единогласно, т.к. даже независимые деплои уже давали профит.
Однако сами по себе микрофронты никак не организуют код внутри модулей, поэтому нужно было решить, что внедрять дальше: ADS или FSD. На мой взгляд, FSD – отличная методология с самодостаточной философией и подходом, и я хотел протестировать ее на реальном проекте и понять все подводные, но… бэкграунд проектов сыграл свою роль:
1. Пара команд уже успешно внедрили ADS к себе в проекты в тестовом режиме.
2. С FSD ни у кого не было боевого опыта, поэтому переход мог быть достаточно долгим и болезненным.
3. Когда мы разрабатывали UI-кит, то договорились с дизайнерами, что они тоже будут следовать ADS методологии.
Да, ADS имеет свои недочеты, например, нет четкого соглашения, где хранить бизнес-логику и вспомогательные утилиты. На данный момент мы просто условились не спускать бизнес логику ниже уровня страниц, а универсальные утилиты переедут в отдельную внутреннюю репу с тулзами. Кстати, у нас UI-кит – это отдельная репа, и в MF приложениях, в большинстве случаев, почти не будет атомов, молекул и организмов. Они будут тянуться прямиком из кита.
Резюмируя, хочу сказать, что не надо внедрять что-либо просто потому что это сейчас модно. Сделайте анализ, оцените технический скилл и настрой команды, изучите бэкграунд проектов и потом принимайте решение.
P. S. Позже я планирую разобрать плюсы и минусы каждого подхода более подробно, а пока, те, кто заинтересован, переходите по соответствующим ссылкам в первом абзаце.
@js_is_easy
👍9❤2🔥1
Ребята из iOS Такой 🍏 пригласили меня в гости на стрим. Мы из разных областей программирования, поэтому выбрали нейтральную тему для обсуждения: "Chat GPT и Нейронные сети".
Будем обсуждать прикладное использование нейронок в программировании и не только.
Залетайте в это воскресенье, 14 мая, в 18:00 по МСК на трансляцию.
P.S. Я еще в марте делал цикл постов про нейронки с лайфхаками. За это время набрался прикладного опыта и есть чем их дополнить.
@js_is_easy
Будем обсуждать прикладное использование нейронок в программировании и не только.
Залетайте в это воскресенье, 14 мая, в 18:00 по МСК на трансляцию.
P.S. Я еще в марте делал цикл постов про нейронки с лайфхаками. За это время набрался прикладного опыта и есть чем их дополнить.
@js_is_easy
Telegram
iOS Такой 🍏
Всем привет! Возвращаемся к Вам после выходных с новой прямой трансляцией!
В это воскресенье у нас круглый стол на тему "Chat GPT и Нейронные сети". Поговорим про полезность нейронок, ответим на вопросы и попытаемся порассуждать что будет дальше. А главным…
В это воскресенье у нас круглый стол на тему "Chat GPT и Нейронные сети". Поговорим про полезность нейронок, ответим на вопросы и попытаемся порассуждать что будет дальше. А главным…
👍7❤3🔥2🤮1
Страх писать негативные отчеты
Пока технические советы на стадии разработки, хотел бы затронуть важный психологический аспект.
Многие программисты боятся отчетов и стесняются задавать вопросы, особенно, если речь идет о сообщении проблем. Я не был исключением. Во время написания очередного отчета я боялся показаться некомпетентным или задать глупый вопрос. Но в какой-то момент я понял, что это только мешает мне и коллегам, а также ухудшает отношения с заказчиками.
Страх задавать вопросы ведет к снижению производительности, так как приводит к отсутствию обратной связи, которая необходима для общего прогресса и решения задач. Также страдает и личная мотивация. Страх говорить о проблемах может снизить чувство удовлетворения от работы, ведь новые задачи продолжают поступать, а нерешенные – накапливаться.
С точки зрения взаимоотношений с клиентами, недостаток прозрачности может привести к разочарованию с их стороны. Рано или поздно проблемы все равно обнаружатся и будет казаться, что вы пытались что-то скрыть.
Опытные менеджеры, с которыми я работал, говорили примерно следующее: "Если есть проблема, расскажи о ней, как можно раньше". Да, таракан внутри нас считает, что за плохие новости будет наказание, на практике же, все совсем иначе. Чем раньше вы поделитесь возникшей проблемой, тем быстрее сможете начать работать над ее решением.
Если вы боитесь задавать вопросы или сообщать о проблемах, помните – вы не одиноки. Это обычное чувство, с которым сталкиваются многие программисты. Но преодоление этого страха – важный шаг к улучшению собственной производительности, репутации и качества проектов.
Думаю, тимлиды и ПМы согласятся с тем, что создание культуры, в которой люди не боятся высказываться – важная часть успешного управления проектами.
Помните, что вопросы – это не знак некомпетентности. На самом деле, это признак профессионализма. Задавая вопросы, вы показываете, что заботитесь о качестве вашего продукта и вовлечены в разработку.
@js_is_easy
Пока технические советы на стадии разработки, хотел бы затронуть важный психологический аспект.
Многие программисты боятся отчетов и стесняются задавать вопросы, особенно, если речь идет о сообщении проблем. Я не был исключением. Во время написания очередного отчета я боялся показаться некомпетентным или задать глупый вопрос. Но в какой-то момент я понял, что это только мешает мне и коллегам, а также ухудшает отношения с заказчиками.
Страх задавать вопросы ведет к снижению производительности, так как приводит к отсутствию обратной связи, которая необходима для общего прогресса и решения задач. Также страдает и личная мотивация. Страх говорить о проблемах может снизить чувство удовлетворения от работы, ведь новые задачи продолжают поступать, а нерешенные – накапливаться.
С точки зрения взаимоотношений с клиентами, недостаток прозрачности может привести к разочарованию с их стороны. Рано или поздно проблемы все равно обнаружатся и будет казаться, что вы пытались что-то скрыть.
Опытные менеджеры, с которыми я работал, говорили примерно следующее: "Если есть проблема, расскажи о ней, как можно раньше". Да, таракан внутри нас считает, что за плохие новости будет наказание, на практике же, все совсем иначе. Чем раньше вы поделитесь возникшей проблемой, тем быстрее сможете начать работать над ее решением.
Если вы боитесь задавать вопросы или сообщать о проблемах, помните – вы не одиноки. Это обычное чувство, с которым сталкиваются многие программисты. Но преодоление этого страха – важный шаг к улучшению собственной производительности, репутации и качества проектов.
Думаю, тимлиды и ПМы согласятся с тем, что создание культуры, в которой люди не боятся высказываться – важная часть успешного управления проектами.
Помните, что вопросы – это не знак некомпетентности. На самом деле, это признак профессионализма. Задавая вопросы, вы показываете, что заботитесь о качестве вашего продукта и вовлечены в разработку.
@js_is_easy
👍9🔥5❤2
Заметки о forwardRef
В устаревшей доке React подробно описано, использование
1. Обратная совместимость. Когда React перешел с классов на функции (FC), единственным способом переписать компонент с рефом с класса на FC был
2. Соглашение о наименовании. В приложении, без классовых компонентов, вы можете передать реф в любом пропе (кроме специальных: ref или key), например,
3. Инкапсуляция. По умолчанию React не позволяет компоненту обращаться к узлам DOM других компонентов. Это сделано намеренно, чтобы разработчики не могли использовать любые компоненты в императивном стиле, а только те, которые были специально разработаны для этого. Рефы – это императивная лазейка в декларативном React. Используйте их только в крайнем случае, например, когда нужно напрямую обратиться к DOM.
В новой документации React есть отличная статья про рефы и о третьем пункте в частности: https://react.dev/learn/manipulating-the-dom-with-refs
P.S. Я в этом посте делился кастомным хуком для объединения внешних и локальных рефов. Забирайте.
@js_is_easy
В устаревшей доке React подробно описано, использование
forwardRef
. Но нет объяснений, зачем использовать этот HOC, когда можно просто передать ref
в пропсах. На это есть несколько причин:1. Обратная совместимость. Когда React перешел с классов на функции (FC), единственным способом переписать компонент с рефом с класса на FC был
forwardRef
. Это связано с тем, что в классах рефы привязывались к экземпляру класса, а у функций экземпляров нет. [Подробнее]. Если бы ref был в общем списке пропов, то при деструктуризации пропов он бы проваливался сразу дальше, а в классовых компонентах его обрабатывали отдельно.2. Соглашение о наименовании. В приложении, без классовых компонентов, вы можете передать реф в любом пропе (кроме специальных: ref или key), например,
innerRef
, и при этом в дочернем компоненте не нужно использовать forwardRef
. С точки зрения разработки, это проще и удобнее, так как требуется меньше HOC'ов. Однако если вы разрабатываете библиотеку или работаете в команде, то для других разработчиков может быть не очевидно, чем ваш innerRef отличается от общепринятого ref. Если вы планируете предоставить доступ к DOM верхнего элемента, делайте это через ref
. Если требуется доступ к другим элементам или императивный подход, можно добавить свои пропы для рефов (подробнее в следующем пункте).3. Инкапсуляция. По умолчанию React не позволяет компоненту обращаться к узлам DOM других компонентов. Это сделано намеренно, чтобы разработчики не могли использовать любые компоненты в императивном стиле, а только те, которые были специально разработаны для этого. Рефы – это императивная лазейка в декларативном React. Используйте их только в крайнем случае, например, когда нужно напрямую обратиться к DOM.
В новой документации React есть отличная статья про рефы и о третьем пункте в частности: https://react.dev/learn/manipulating-the-dom-with-refs
P.S. Я в этом посте делился кастомным хуком для объединения внешних и локальных рефов. Забирайте.
@js_is_easy
👍8❤2🤔1
String Manipulation [JetBrains][VS Code] – плагин, который поможет ускорить разработку. У него достаточно богатая функциональность, но лично я использую только смену регистра.
Эта фича экономит время, поскольку избавляет от необходимости вручную перепечатывать строки из одного регистра в другой. И, естественно, исключает опечатки.
Очень удобен при переименовании переменных во время деструктуризации данных на фронте с бэка из snake_case в camelCase и наоборот, а также при рефакторинге.
Естественно, можно настроить шорткаты, кнопка настроек на втором окне внизу.
#plugins
@js_is_easy
Эта фича экономит время, поскольку избавляет от необходимости вручную перепечатывать строки из одного регистра в другой. И, естественно, исключает опечатки.
Очень удобен при переименовании переменных во время деструктуризации данных на фронте с бэка из snake_case в camelCase и наоборот, а также при рефакторинге.
Естественно, можно настроить шорткаты, кнопка настроек на втором окне внизу.
#plugins
@js_is_easy
👍10❤5🔥3
Внезапно для себя обнаружил, что webpack, по дефолту, во время сборки пакета, делает NODE_ENV всегда равным mode. То есть, если вы собрали библиотеку в production режиме, установили ее в проект, запустили этот проект в режиме разработки (NODE_ENV=development), то при обращении к
Для проектов и большинства либ, типа UI компонентов, это не играет роли, а вот если в пакете есть проверки на окружение для оптимизаций в проде или, наоборот, расширенное логирование для разработки, то стоит обратить внимание на такую настройку вебпака, как optimization.nodeEnv. По дефолту, она делает
Имейте это ввиду, если разрабатываете какой-нибудь дев тулз. Я потратил пол дня, прежде чем понял, почему моя либа для отладки не работает в проекте😢
@js_is_easy
process.env.NODE_ENV
в проекте, значение будет development, а в установленной библиотеке – production.Для проектов и большинства либ, типа UI компонентов, это не играет роли, а вот если в пакете есть проверки на окружение для оптимизаций в проде или, наоборот, расширенное логирование для разработки, то стоит обратить внимание на такую настройку вебпака, как optimization.nodeEnv. По дефолту, она делает
NODE_ENV
всегда равной режиму сборки. А если присвоить ей значение false, то NODE_ENV
будет тянуться из окружения проекта.Имейте это ввиду, если разрабатываете какой-нибудь дев тулз. Я потратил пол дня, прежде чем понял, почему моя либа для отладки не работает в проекте
@js_is_easy
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17🤯10❤3
Еще один интересный факт, связанный с вебпаком – это глобальная уникальность классов в CSS модулях. За их генерацию отвечает раздел modules в css-loader.
Допустим, есть два проекта с дефолтными настройками css-loader’а (localIdentName: "[path][name]__[local]--[hash:base64:5]
Я бы посоветовал добавлять в localIdentName название проекта или использовать localIdentHashSalt для избежания коллизий, если вы разрабатываете модули или UI библиотеки.
P.S. в create react app своя логика генерации классов, но эта проблема тоже присутствует.
@js_is_easy
Допустим, есть два проекта с дефолтными настройками css-loader’а (localIdentName: "[path][name]__[local]--[hash:base64:5]
).
В этих проектах есть два разных компонента, но с одинаковым путем: src/components/Footer/Footer.modules.scss
-> .container {…}
. Если собрать эти проекты, то в каждом билде будет класс: src-components-Footer-Footer-module__container--x3Zn_
. Эти классы уникальны в рамках одного проекта, но если соединить эти проекты через Module Federation или внешние зависимости, то получается неожиданный конфликт классов. Полагаю, что base64 использует в качестве сида путь до файла.Я бы посоветовал добавлять в localIdentName название проекта или использовать localIdentHashSalt для избежания коллизий, если вы разрабатываете модули или UI библиотеки.
P.S. в create react app своя логика генерации классов, но эта проблема тоже присутствует.
@js_is_easy
webpack
css-loader | webpack
webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.
👍8❤3🤔3🔥2
Хотел в прошлом посте раскрыть тему умирающего CRA, но решил что он достоен отдельного.
Последний раз я создавал и сопровождал проект через CRA около 3-х лет назад. С тех пор избегаю CRA. По нескольким причинам:
Кастомизация конфига. Есть два варианта и оба такие себе. Первый – делать eject и копаться в лапше конфигов. Второй – использовать craco или react-app-rewired и снова лезть в кишки, но уже на гитхабе, чтобы написать свои патчи.
Гора скрытых зависимостей. Под капотом около 50 зависимостей и все в
Больше не поддерживается. Если v4 еще худо-бедно обновляли, то на v5 забили почти сразу. Последний релиз больше года назад, свыше 1.5к issues, примерно треть из них за последний год. С каждой новой версией ноды растет риск несовместимости со свежими либами.
Любой мидл соберет нормальный конфиг вебпака с нуля. Почитайте несколько статей, это куда быстрее и приятнее, чем потом вникать в дебри CRA.
P.S. Последнее время нахваливают Vite (тут и тут). Сборщик быстрый и интересный, но в большой проект я бы его не взял – еще сырой. Если хочется что-то кроме webpack, то голый rollup.js будет постабильнее.
@js_is_easy
Последний раз я создавал и сопровождал проект через CRA около 3-х лет назад. С тех пор избегаю CRA. По нескольким причинам:
Кастомизация конфига. Есть два варианта и оба такие себе. Первый – делать eject и копаться в лапше конфигов. Второй – использовать craco или react-app-rewired и снова лезть в кишки, но уже на гитхабе, чтобы написать свои патчи.
Гора скрытых зависимостей. Под капотом около 50 зависимостей и все в
dependencies
разделе, некоторые из них периодически ломаются. Не нужен jest или tailwind? Не переживай, CRA все равно их установит.Больше не поддерживается. Если v4 еще худо-бедно обновляли, то на v5 забили почти сразу. Последний релиз больше года назад, свыше 1.5к issues, примерно треть из них за последний год. С каждой новой версией ноды растет риск несовместимости со свежими либами.
Любой мидл соберет нормальный конфиг вебпака с нуля. Почитайте несколько статей, это куда быстрее и приятнее, чем потом вникать в дебри CRA.
P.S. Последнее время нахваливают Vite (тут и тут). Сборщик быстрый и интересный, но в большой проект я бы его не взял – еще сырой. Если хочется что-то кроме webpack, то голый rollup.js будет постабильнее.
@js_is_easy
👍9❤2🔥2🤔1
Задача: Объединение отсортированных массивов
Даны два целочисленных массива
Объедините
Функция не должна ничего возвращать, вместо этого нужно мутировать массив
Задача со звездочкой: Сможете придумать алгоритм, который работает за время O(m + n)?
Пример 1:
Ввод: nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
Вывод: [1,2,2,3,5,6]
Объяснение: Массивы, которые мы объединяем – [1,2,3] и [2,5,6].
Результат объединения –[1,2,2,3,5,6].
Пример 2:
Ввод: nums1 = [1], m = 1, nums2 = [], n = 0
Вывод: [1]
Объяснение: Массивы, которые мы объединяем – [1] и [].
Результат объединения – [1].
Пример 3:
Ввод: nums1 = [0], m = 0, nums2 = [1], n = 1
Вывод: [1]
Объяснение: Массивы, которые мы объединяем – [] и [1].
Результат объединения – [1].
Обратите внимание, что, так как m = 0, в nums1 нет элементов. 0 здесь только для того, чтобы гарантировать, что результат слияния может поместиться в nums1.
Пишите свои версии в комментариях.
Ответ с объяснением 👈
#algorithms
@js_is_easy
Даны два целочисленных массива
nums1
и nums2
, отсортированных в возрастающем порядке, и два целых числа m
и n
, представляющие количество элементов в nums1
и nums2
, соответственно.Объедините
nums1
и nums2
в один массив, отсортированный в возрастающем порядке.Функция не должна ничего возвращать, вместо этого нужно мутировать массив
nums1
. Для этого, nums1
имеет длину m + n
, где первые m
элементов обозначают те, которые должны быть объединены, а последние n
элементов установлены в 0 и должны быть проигнорированы. nums2
имеет длину n.Задача со звездочкой: Сможете придумать алгоритм, который работает за время O(m + n)?
Пример 1:
Ввод: nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
Вывод: [1,2,2,3,5,6]
Объяснение: Массивы, которые мы объединяем – [1,2,3] и [2,5,6].
Результат объединения –[1,2,2,3,5,6].
Пример 2:
Ввод: nums1 = [1], m = 1, nums2 = [], n = 0
Вывод: [1]
Объяснение: Массивы, которые мы объединяем – [1] и [].
Результат объединения – [1].
Пример 3:
Ввод: nums1 = [0], m = 0, nums2 = [1], n = 1
Вывод: [1]
Объяснение: Массивы, которые мы объединяем – [] и [1].
Результат объединения – [1].
Обратите внимание, что, так как m = 0, в nums1 нет элементов. 0 здесь только для того, чтобы гарантировать, что результат слияния может поместиться в nums1.
Пишите свои версии в комментариях.
Ответ с объяснением 👈
#algorithms
@js_is_easy
👍9❤4🔥3
Типы ответов в axios
Думаю, многие используют axios для запросов. Однако стоит помнить, что по умолчанию
Для большинства случаев, это именно то, что нужно. Но, например, если нужно скачать готовый файл, такое преобразование может сыграть коварную шутку. Axios преобразует ответ в текст (поскольку JSON невалиден), и при попытке создать из преобразованного ответа Blob, получим битый файл. Проблема в том, что на вкладке Network (Сеть) и при выводе в консоль, визуально, ответ не будет отличаться: и там, и там будет выглядеть, как набор символов – разница лишь в том, что в Network ответ еще не преобразован в строку.
Фиксится довольно просто, нужно в config передать
P.S. Имейте ввиду, что есть еще и другие типы ответов:
Думаю, многие используют axios для запросов. Однако стоит помнить, что по умолчанию
responseType
в нем установлен как json
. Это означает, что все ответы с сервера будут обрабатываться как JSON-объекты (или текст, если json битый).Для большинства случаев, это именно то, что нужно. Но, например, если нужно скачать готовый файл, такое преобразование может сыграть коварную шутку. Axios преобразует ответ в текст (поскольку JSON невалиден), и при попытке создать из преобразованного ответа Blob, получим битый файл. Проблема в том, что на вкладке Network (Сеть) и при выводе в консоль, визуально, ответ не будет отличаться: и там, и там будет выглядеть, как набор символов – разница лишь в том, что в Network ответ еще не преобразован в строку.
Фиксится довольно просто, нужно в config передать
responseType:
blob
, тогда axios будет обрабатывать ответ соответствующим образом.P.S. Имейте ввиду, что есть еще и другие типы ответов:
arraybuffer, document, text, stream.
@js_is_easy👍12🔥6❤3🍾1
Работа с Singleton'ами в Webpack Module Federation
При использовании библиотек, которые создают singleton для своей работы, необходимо быть особенно внимательными во время разработки своих либ или микрофрнтов.
Например, популярная либа для переводов, i18next, создает глобальный объект для всего приложения. Поскольку приложения на Module Federation часто шарят зависимости, то все они используют один объект. Следовательно, при стандартной инициализации конфигов в обоих приложениях, они будут конфликтовать (пример на скрине).
В react-i18next есть пара способов решения проблемы. Для начала в обоих случаях нужно создать новый экземпляр i18next, а затем:
1. Можно создать кастомный хук useTranslation для каждого приложения с перезаписанным экземпляром
2. Или, что более универсально, использовать I18nextProvider с новым экземпляром.
@js_is_easy
При использовании библиотек, которые создают singleton для своей работы, необходимо быть особенно внимательными во время разработки своих либ или микрофрнтов.
Например, популярная либа для переводов, i18next, создает глобальный объект для всего приложения. Поскольку приложения на Module Federation часто шарят зависимости, то все они используют один объект. Следовательно, при стандартной инициализации конфигов в обоих приложениях, они будут конфликтовать (пример на скрине).
В react-i18next есть пара способов решения проблемы. Для начала в обоих случаях нужно создать новый экземпляр i18next, а затем:
1. Можно создать кастомный хук useTranslation для каждого приложения с перезаписанным экземпляром
2. Или, что более универсально, использовать I18nextProvider с новым экземпляром.
@js_is_easy
👍9🔥3❤2
Обработка ошибок загрузки изображений
У тега
Вот пример кода на React (хотя для обычного JS он будет выглядеть очень похожим):
@js_is_easy
У тега
<img />
есть коллбэк onError
, который срабатывает, если загрузка контента из src
не удалась. С его помощью можно избежать отображения поврежденных изображений и сделать сайт более приятным для пользователей.Вот пример кода на React (хотя для обычного JS он будет выглядеть очень похожим):
<img
src='https://site.com/my_img.png'
onError={({ currentTarget }) => {
currentTarget.onerror = null;
currentTarget.src="./default_img.png";
}}
/>
Обратите внимание на присвоение null
для onError.
Это необходимо чтобы избежать циклической загрузки, в случае, если дефолтная картинка тоже недоступна.@js_is_easy
👍20🔥6❤1
Доступ к LinkedIn
Сегодня VPN широко используются для различных целей. Большинство VPN сервисов перенаправляют весь трафик, однако, существуют и такие, которые нацелены на работу с определенными ресурсами.
Например, мне нравится разгребать LinkedIn, слушая подкасты или музыку на фоне. Чтобы не замедлять весь трафик через VPN, я использую это расширение для Chrome. Пока расширение активно, LinkedIn всегда доступен, а остальной интернет трафик проходит как обычно. Отключаю я его только если нужно врубить полноценный VPN, т.к. они конфликтуют.
@js_is_easy
Сегодня VPN широко используются для различных целей. Большинство VPN сервисов перенаправляют весь трафик, однако, существуют и такие, которые нацелены на работу с определенными ресурсами.
Например, мне нравится разгребать LinkedIn, слушая подкасты или музыку на фоне. Чтобы не замедлять весь трафик через VPN, я использую это расширение для Chrome. Пока расширение активно, LinkedIn всегда доступен, а остальной интернет трафик проходит как обычно. Отключаю я его только если нужно врубить полноценный VPN, т.к. они конфликтуют.
@js_is_easy
Google
Интернет-магазин Chrome
Добавьте в браузер новые функции и персонализируйте его.
👍7❤2🔥1💩1
Цена React.iss.onemo
Некоторые разработчики до сих пор пренебрегают мемоизацией компонентов, относясь к ней с опаской. Их беспокоит потенциальное снижение производительности из-за мемоизации. Я сделал небольшой эксперимент, для демонстрации того, что цена React.iss.onemo ничтожно мала.
Что по результатам?
- memo компоненты с примитивными пропсами, при неизменных значениях работают в разы быстрее
- Если пропсы в memo меняются каждый рендер, то CPU перформанс снижается на пару процентов в сравнении с обычными в синтетическом тесте. В реальных компонентах разница будет почти незаметна.
Из результатов можно сделать вывод о том, что memo проигрывает обычным компонентам, только если пропсы 100% меняются каждый рендер. В основном, это пропсы с не примитивными значениями (children тоже считается).
Если в вашем проекте распространено использование мемоизирующих хуков, то оборачивать в memo можно почти каждый компонент. Если нет – стоит задумываться над мемоизацией компонентов, содержащих не примитивные пропсы.
Еще один, более комплексный тест: https://stackoverflow.com/a/73111523
@js_is_easy
Некоторые разработчики до сих пор пренебрегают мемоизацией компонентов, относясь к ней с опаской. Их беспокоит потенциальное снижение производительности из-за мемоизации. Я сделал небольшой эксперимент, для демонстрации того, что цена React.iss.onemo ничтожно мала.
Что по результатам?
- memo компоненты с примитивными пропсами, при неизменных значениях работают в разы быстрее
- Если пропсы в memo меняются каждый рендер, то CPU перформанс снижается на пару процентов в сравнении с обычными в синтетическом тесте. В реальных компонентах разница будет почти незаметна.
Из результатов можно сделать вывод о том, что memo проигрывает обычным компонентам, только если пропсы 100% меняются каждый рендер. В основном, это пропсы с не примитивными значениями (children тоже считается).
Если в вашем проекте распространено использование мемоизирующих хуков, то оборачивать в memo можно почти каждый компонент. Если нет – стоит задумываться над мемоизацией компонентов, содержащих не примитивные пропсы.
Еще один, более комплексный тест: https://stackoverflow.com/a/73111523
@js_is_easy
❤9👍5🔥3💩1
Максимальное число параллельных запросов
В вебе время запросов к серверу оказывает большое влияние на производительность приложения. Для ускорения загрузки приложения используются параллельные запросы (где возможно). Но у параллельных запросов, помимо пропускной способности сети, есть одно не очевидное ограничение: лимит одновременных запросов к одному домену. Например, в хроме их 6. В остальных браузерах ± так же.
К сожалению, серебряной пули здесь нет, но есть различные практики и обходные пути, например:
- Использовать CDN. Подойдет для ассетов, но не для JS кода
- Перейти с HTTP/1.1 на HTTP/2. Самый удобный вариант, но мало кто запаривается с переходом.
- Подходить к code splitting с умом, а не дробить приложение на миллион чанков
- Отдельный лоадер для виджетов, вместо глобального и т.д.
@js_is_easy
В вебе время запросов к серверу оказывает большое влияние на производительность приложения. Для ускорения загрузки приложения используются параллельные запросы (где возможно). Но у параллельных запросов, помимо пропускной способности сети, есть одно не очевидное ограничение: лимит одновременных запросов к одному домену. Например, в хроме их 6. В остальных браузерах ± так же.
К сожалению, серебряной пули здесь нет, но есть различные практики и обходные пути, например:
- Использовать CDN. Подойдет для ассетов, но не для JS кода
- Перейти с HTTP/1.1 на HTTP/2. Самый удобный вариант, но мало кто запаривается с переходом.
- Подходить к code splitting с умом, а не дробить приложение на миллион чанков
- Отдельный лоадер для виджетов, вместо глобального и т.д.
@js_is_easy
👍14🔥4❤1
В любой непонятной ситуации - думай
По дороге в отпуск наконец-то дочитал книгу Максима Дорофеева «Джедайские техники». Ее мне давно советовали опытные лиды и менеджеры и я долго до нее добирался, а зря.
Из книги я почерпнул много практик и лайфхаков, и структурировал свои знания:
- стал тщательно контролировать «поток входящих» (отписался почти от всех email рассылок и оставил толко самые важные пуши)
- начал тщательнее продумывать названия задач
- упростил и реорганизовал хранение информации и многое другое.
Я еще в процессе внедрения некоторых практик, но уже сейчас стал замечать, как задачи стали делаться, а «забытой» информации стало меньше.
Я бы советовал книгу тем, кто хочет прокачать свою продуктивность или высвободить личное время. Джуны и мидлы найдут много полезных лайфхаков простыми словами в первых трех главах, остальная часть книги больше для руководящих позиций.
@js_is_easy
По дороге в отпуск наконец-то дочитал книгу Максима Дорофеева «Джедайские техники». Ее мне давно советовали опытные лиды и менеджеры и я долго до нее добирался, а зря.
Из книги я почерпнул много практик и лайфхаков, и структурировал свои знания:
- стал тщательно контролировать «поток входящих» (отписался почти от всех email рассылок и оставил толко самые важные пуши)
- начал тщательнее продумывать названия задач
- упростил и реорганизовал хранение информации и многое другое.
Я еще в процессе внедрения некоторых практик, но уже сейчас стал замечать, как задачи стали делаться, а «забытой» информации стало меньше.
Я бы советовал книгу тем, кто хочет прокачать свою продуктивность или высвободить личное время. Джуны и мидлы найдут много полезных лайфхаков простыми словами в первых трех главах, остальная часть книги больше для руководящих позиций.
@js_is_easy
Литрес
Джедайские техники. Как воспитать свою обезьяну, опустошить инбокс и сберечь мыслетопливо — Максим Дорофеев | Литрес
Почему, даже зная, как надо правильно работать, человек на практике делает все так, как привык… то есть плохо? Максим Дорофеев простым и доступным языком объясняет, почему так происходит. Прочитав ег…
❤8👍4🔥1🤔1💩1
Задача: Количество лазерных лучей в банке
Задачи с данными, которые можно визуализировать, а не просто абстрактные массивы решать интереснее. Это одна из них.
В банке активировали защитную систему. Дан двумерный массив
Между двумя устройствами проходит один лазерный луч, если выполняются оба условия:
- Два устройства находятся на двух разных строках:
- Для каждой строки
Каждый луч независим, то есть один луч не мешает другим и не соединяется с ними.
Верните общее количество лазерных лучей в банке.
Пример:
Ввод: ["011001","000000","010100","001000"]
Вывод: 8
Объяснение: Между каждой из следующих пар устройств проходит луч. Всего получается 8 лучей:
* bank[0][1] -- bank[2][1]
* bank[0][1] -- bank[2][3]
* bank[0][2] -- bank[2][1]
* bank[0][2] -- bank[2][3]
* bank[0][5] -- bank[2][1]
* bank[0][5] -- bank[2][3]
* bank[2][1] -- bank[3][2]
* bank[2][3] -- bank[3][2]
Обратите внимание, что между устройствами на 0-й и 3-й строках нет лучей, потому что на 2-й строке есть устройства безопасности, что нарушает второе условие.
Больше примеров и ответ с разбором: https://telegra.ph/Kolichestvo-lazernyh-luchej-v-banke-07-12
#algorithms
@js_is_easy
Задачи с данными, которые можно визуализировать, а не просто абстрактные массивы решать интереснее. Это одна из них.
В банке активировали защитную систему. Дан двумерный массив
bank
, представляющий план банка, где 0 означает пустую ячейку, а 1 – ячейку с защитным устройством.Между двумя устройствами проходит один лазерный луч, если выполняются оба условия:
- Два устройства находятся на двух разных строках:
r1
и r2
, где r1
< r2
.- Для каждой строки
i
, где r1
< i
< r2
, в i
-й строке нет устройств безопасности (т.е. луч всегда идет к устройствам на ближайшей строке).Каждый луч независим, то есть один луч не мешает другим и не соединяется с ними.
Верните общее количество лазерных лучей в банке.
Пример:
Ввод: ["011001","000000","010100","001000"]
Вывод: 8
Объяснение: Между каждой из следующих пар устройств проходит луч. Всего получается 8 лучей:
* bank[0][1] -- bank[2][1]
* bank[0][1] -- bank[2][3]
* bank[0][2] -- bank[2][1]
* bank[0][2] -- bank[2][3]
* bank[0][5] -- bank[2][1]
* bank[0][5] -- bank[2][3]
* bank[2][1] -- bank[3][2]
* bank[2][3] -- bank[3][2]
Обратите внимание, что между устройствами на 0-й и 3-й строках нет лучей, потому что на 2-й строке есть устройства безопасности, что нарушает второе условие.
Больше примеров и ответ с разбором: https://telegra.ph/Kolichestvo-lazernyh-luchej-v-banke-07-12
#algorithms
@js_is_easy
👍11❤2🔥2💩1
Заголовки в CORS запросах
Если вручную открыть вкладку “Сети” в браузере, то вы увидите все хэдеры запроса, а вот дотянуться из JS получится не до всех. Это ограничение существует из соображений безопасности [хорошая статья про корсы].
По умолчанию, для CORS запросов из браузера доступны следующие хэдеры:
- Cache-Control
- Content-Language
- Content-Type
- Expires
- Last-Modified
- Pragma
До других из JS вы просто так не дотянетесь.
Если вам нужен какой-то другой – попросите бэкендеров или девопсов добавить следующий хэдер на сервере
@js_is_easy
Если вручную открыть вкладку “Сети” в браузере, то вы увидите все хэдеры запроса, а вот дотянуться из JS получится не до всех. Это ограничение существует из соображений безопасности [хорошая статья про корсы].
По умолчанию, для CORS запросов из браузера доступны следующие хэдеры:
- Cache-Control
- Content-Language
- Content-Type
- Expires
- Last-Modified
- Pragma
До других из JS вы просто так не дотянетесь.
Если вам нужен какой-то другой – попросите бэкендеров или девопсов добавить следующий хэдер на сервере
Access-Control-Expose-Headers: Header-Name-1, Header-Name-2
P.S. помню, как сам когда-то судорожно и безуспешно заменял axios на fetch, и игрался с настройками в надежде достать нужный хэдер))@js_is_easy
👍24❤3🔥1