isqualog • front-end • productivity
580 subscribers
27 photos
5 videos
70 links
Привет, я Алекс, разработчик с фокусом на фронтенд. Тут про фронтенд, работу и жизнь. Пишу, когда есть чем поделиться.

Лонгриды тут → https://isqua.ru/
Download Telegram
Channel name was changed to «isqualog • front-end • productivity»
Как управлять карьерой: Continuous Self Review

В бигтехе раз в полгода-год проходит performance review: оценивают результаты каждого сотрудника, раздают бонусы и повышения. У каждого есть грейд (L5 в Google, E4 в Meta и т.п.), от него зависит зарплата. Вот видео с объяснением процесса, спасибо Антону Сапронову за наводку.

Ревью начинается с того, что вы готовите self assessment — отчёт о своих достижениях за полгода. Важно какую пользу нанёс, а не объём работы типа «закрыл 200 задачек».

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

Ошибка — писать self-assessment в последний момент. Пытаешься вспомнить, чем занимался это время, перечитываешь закрытые таски. Так можно обнаружить, что полгода занимался фигнёй.

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

Это помогает фокусироваться на результате и не тратить время на текучку. Если пару спринтов и писать-то нечего — вы копаете не туда. Как в сёрфинге: куда смотришь, туда и едешь.

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

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

Тут я хотел написать, что бывают периоды, когда карьера не в приоритете: чините кукуху, переезжаете, растите детей. Но тут даже важнее понимать, на чём держать фокус, чтобы не тратить время и силы на ненужную работу.
18👍2
Чё там по state managers

Пошёл глянуть насколько ещё актуально в статьях про управление состоянием использовать примеры на redux (у меня он на текущем проекте). Пока что актуально. Несколько инсайтов с графика:

1. Судя по тренду, скоро Zustand обгонит Redux по загрузкам.

2. Jotai всё никак не обгонит mobx (если считать сумму mobx-react и mobx-react-lite)

3. Recoil, effector и reatom — какие-то нишевые и угасающие тренды. За год число их загрузок не выросло. А на фоне роста лидеров получается, что их доля значительно упала.

Скелетор вернется позже с еще одним неприятным фактом
1👍5😱1
Так, узнал, короче, что у телеграм каналов должна быть визитка. Ща будет визитка!
😁61😱1
Привет! Я Алекс, Senior Software Engineer. В 2014-м пришёл в Яндекс джуном, дорос до тимлида и откатился в разработчики. В 2024-м переехал в Европу, сейчас работаю в стартапах. Стек: React, TypeScript, Node.js.

Официально я фронтендер, но что я только ни делал: крутил nodejs в проде под нагрузкой, мигрировал сервисы из одного облака в другое, отвечал за CI/CD в монорепе на 100+ проектов, писал тулзы и парсеры, оптимизировал перфоманс и переписывал легаси.

Много менторил — и младших коллег на работе, и студентов в HTML Academy. Этот канал когда-то сделал для них, чтобы делиться опытом и полезными материалами. Вот некоторые из них:

🚀 Карьера и работа в команде
Как управлять карьерой: Continuous Self Review
Как внедрять изменения: уровни сопротивления
Работа это не писать код, а решать задачи
Роли в команде: тесты пишет фронтендер или тестер?
Как сделать работу интересной
Как работать с информацией
Как не продалбываться
Синдром ученика: не тормозите на старте
Встречи в одно и то же время


⚛️ Фронтенд
Масштабируемая файловая структура проекта
Убираем лишние эффекты из компонента
Алиасы для импортов: какие выбрать
Как задеплоить react-приложения на Github Pages (en)
Как в Гугле дизайнят API
Организуем моки бекенда для тестов и сторибука
Рефакторим вложенные ифаки
Фундамент CSS — для собеседований и не только
Pixel Perfect
БЭМ с точки зрения процессов
Контрольные точки для media-выражений


📱 Дизайн и UX
Типографика и вёрстка: как собирать крепкие страницы
Как сделать тёмную тему красиво
Напиши в жука: как получать фидбек от пользователей
Автофокус: экономим клики
Повышаем доступность дёшево
Кнопки с градиентной рамкой


🛠 Инструменты
Правим код быстрее — базовые фичи IDE
Подмена ответов API в Chrome DevTools
Два инструмента для работы с API
Генератор шума и мурчания


🧠 Задачки
Почувствуй себя хакером: взрывные головоломки
Пишем свой reduce
Упаковка массивов
Парсинг выражений и длинная арифметика
Кроссворды с regexp

Подскаст с Алёной делаем 👉 https://t.me/code_cleanup
Лонгриды публикую в блоге 👉 https://isqua.ru
🔥228😁1
isqualog • front-end • productivity pinned «Привет! Я Алекс, Senior Software Engineer. В 2014-м пришёл в Яндекс джуном, дорос до тимлида и откатился в разработчики. В 2024-м переехал в Европу, сейчас работаю в стартапах. Стек: React, TypeScript, Node.js. Официально я фронтендер, но что я только ни…»
Приходит ко мне однажды Алёна Батицкая, та самая, из Доки, и говорит «а что, слабо нам видео про рефакторинг выпускать?» и я такой «ну нинаю, ну надо пробовать»

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

А потом всё сожгли и выпустили пилотный выпуск на 7 минут про то, как оторвать useState в формах на React 19.

Поддержите нас пожалуйста лайками и репостами в твиттере и linkedin. И конечно смотрите наш выпуск!

https://youtu.be/JdMGSgh9uHA
310🔥10
Не поверите, на днях переубедил дизайнера

Делаем тёмную тему для сервиса. У нас дашборд с карточками, и фон конечно светло-серый, а карточки белые. И когда светлая тема выверена, хочется просто инвертировать палитру серых и бахнуть тёмную тему.

Что выходит, когда мы просто инвертируем цвета? Темно-серый фон и черные карточки. То есть в светлой теме карточки были парящими над фоном островами, а в тёмной теме они получаются... дырками.

Ну я и говорю дизайнеру: «давай повторим направление света в тёмной теме? То, что было светлее в дневном режиме, пусть и в ночном остаётся светлее». А он такой: «а давай». Ну мы и сделали.

Я не сам это выдумал: чекнул Gmail, там чётко видно, как повторили «направление света». И тёмный режим в айфоне, там тоже красиво.

Вот нарисовал вам карточки для наглядности! Хотите пошарить своему англоязычному дизайнеру? Скидывайте ссылку на linkedin.
👍23🤔1
В моей команде есть несколько ex-google инженеров. От них я узнал, что у Гугла есть публичные (!) гайдлайны по дизайну API. Называется «Google AIPs: API Improvement Proposals»

👉 https://google.aip.dev/

Вот несколько примеров документов:

AIP-193: Errors — формат ошибок, куда писать код ошибки, куда сообщение, локализацию, и как передать доп. информацию.

AIP-234: Batch methods: Update — батчевые ручки. Что должны отвечать синхронные и асинхронные апдейты и как сигнализировать, что только часть данных обновилась успешно. Отдельный поинт что батчевые ручки (и вообще кастомные операции) называются через двоеточие, типа
/users:batchUpdate

AIP-164: Soft delete — удаление и восстановление, в каких API-методах удалённые сущности могут и не могут появляться, и как же их всё-таки получить. И что делать, если восстановление долгое.

Там есть пропозалы и по клиентам для этих API. Короче, интересный справочник!
1🔥11👍61
Толщина рамок в уголках

10+ лет в индустрии, и вот снова неделю крашу кнопки. Файн-тюним дизайн-систему на проекте.

Знаете же эти модные кнопки и плашки с градиентными рамками? Обычно это два элемента: «задний» с градиентным фоном выглядывает из-за «ближнего» элемента с белым фоном (ну или какой там фончик).

Если делать одинаковый border-radius у внутреннего и внешнего элемента, то уголки как бы утолщаются, выглядит не аккуратно. Верхний блочок на скрине, видите?

То ли дело, если уменьшить радиус внутреннего элемента на толщину рамки! Второй блочок на скрине выглядит прилично.

Поясняю в числах:

1. У блока с градиентом радиус 20px, толщина рамки 5px. Тогда у «белого» элемента радиус должен быть 15px.

2. У блока с градиентом радиус 10px, толщина рамки 2px. Тогда у «белого» радиус должен быть 8px.

Код и пример: https://codepen.io/isqua/pen/vEGomyr?editors=1100

Узнали? Согласны? 😁
1👍16😁6🔥3
isqualog • front-end • productivity
Photo
Мифы про отличия Zustand и Redux

Работаю сейчас с zustand, который уже обогнал redux по загрузкам. Вот что говорят адепты zustand, сравнивая его с redux:

Миф 1: В Zustand можно создавать множество сторов вместо одного!

По факту и правда можно, но в доке Zustand советуют «single store». А если мол ваше приложение большое, можете разделить стор на слайсы.

В redux тоже single store, который можно разделить на слайсы. И в отличие от zustand, есть встроенное решение для динамической подгрузки слайсов, что позволяет делать код-сплиттинг и загружать только нужные слайсы.

Миф 2: В Zustand меньше бойлерплейта!

По факту и правда меньше, пока у тебя стор размером с "counter, increment, decrement". Как только тебе надо обновить поле где-то глубоко в дереве:

updateNestedParam: (value: string) => {
set((state) => ({
deep: {
...state.deep,
nested: {
...state.deep.nested,
obj: { ...state.deep.nested.obj, param: value }
}
}
}))
}


В то время как в redux уже давно можно просто:

updateNestedParam: (state: MyState, value: string) => {
state.deep.nested.obj.param = value
}


Чтобы решить эту проблему документация zustand советует нам immer. На этой библиотеке как раз работает redux, просто она уже встроена. А с zustand нужно писать всё вручную. Есть ещё опция прикрутить immer middleware, чтобы получилось ну-вот-уже-почти-как-в-redux, только вместо одной функции надо две писать:

updateNestedParam: (value: string) => {
set(state => {
state.deep.nested.obj.param = value
})
}


Миф 3: Ура, не нужно использовать Provider!

И правда не нужно. А это точно преимущество? Чтобы написать тесты на компонент, использующий redux, нужен враппер с preloadedState. В Zustand советуют мокать (!) методы самого zustand, чтобы добавить в каждый стор метод очистки, и вызывать это в afterEach — а что если мне в тесте нужен не initialState, а какой-то уже наполненный. Опять всё руками? ЛИБО, внимание, использовать Context API, чтобы предоставить компонентам конкретный инстанс стора. В чём разница с Redux Provider?

Миф 4: Zustand лучше перфоманс!

И показывают бенчмарки на батчевую запись в стор, где в redux используется immer, а в zustand его не добавляют, и пишут тот самый бойлерплейт из мифа №2. Мы точно сравниваем полноценные решения на реальном юз-кейсе? Или подгоняем задачу под ответ?

Я повидал разные проекты. Вопрос производительности библиотек встаёт на масштабах главной страницы Яндекса, где сам код приложения уже оптимизирован донельзя. Проекты поменьше, даже если там сложные графики с 5-летними данными с дневной гранулярностью (зачем), или формы с 200 селектами (зачем), тормозят не из-за стейт-менеджера, а из-за того, как написано само приложение.

Миф 4.1: В Zustand селекторы более гранулярные, именно это влияет на перфоманс!

В zustand можно так:

useMyStore(state => state.very.deep.object.prop)


Но в redux можно точно также:

useSelector(state => state.very.deep.object.prop)


В чём разница? Получили ли мы что-то новое в Zustand, или авторы просто строят очередной Redux?
8🔥7🤔4😱2👎1
Forwarded from code_cleanup
Неужели мы выпустили видео? Конечно выпустили!

Ну и шляпу там нам AI нагенерил, сортировка пузырьком. Рефакторим по TDD, максимально упрощая логику. Объясняем, в чём прикол разных локалей при сортировке.

Улучшили качество видео. Пока мы ещё не супер-блоггеры, но стремимся!

Энджой, лайк, подписка

https://youtu.be/rTbZ38qX_6Q
110👍2🔥1
Структура файлов на проекте, импорты, barrel файлы. Пост ниже ↓
Layers vs Vertical Slices

Кирилл Мокевнин (Hexlet) набросил, как файлы класть — по типу или по домену?

Для меня меня на фронтенде это вопрос давно решенный: если сервис больше чем 2 странички, то, конечно, по фичам. Иначе, чтобы поправить какую-то мелочь, надо по 5 папкам лазить.

📗 Главный принцип: low coupling, high cohesion

Недавно был на проекте: 90к строк кода, 4 фронтендера. Код разложен по слоям: consts, utils, hooks, api, components, pages. Так там утилит было на ~20к строк (четверть кодовой базы!), в них лежала почти вся логика приложения. В константах лежало 202 файла. Тип пропсов компонента из src/components/statistics/CohortsTable.tsx лежал в src/types/statistics/CohortsTable.d.ts. Постоянные проблемы с циклическими зависимостями. Ребята генерили новый код, похожий на старый — трудно было найти нужное.

Когда в ру-язычной фронтенд-тусовке говорят про vertical slices, вспоминают FSD. Имхо, челы перегибают палку. Зачем деление на widgets/features/entities? Это тащит нас обратно — в low cohesion, high coupling. Поэтому туда не ходим, keep it simple, stupid.

И вот мы пару недель обсуждали, какие есть проблемы, почему больно это поддерживать, почему даже мелкие задачки занимают столько времени. В итоге проблема «хз че где» вышла на первое место по скору ICE (Impact × Confidence × Ease).

Мы выработали структуру и правила. Самое сложное было — выделить доменные сущности, об этом никто раньше не думал. Ещё за неделю раскидали 80% файлов, жить сразу стало легче. Подробнее писал в блоге компании (опубликовали в мой последний день там лол)

В src осталось три папки:
app — рутовый компонент, провайдеры
features — самая соль по доменам
shared — общие компоненты

В каждой фиче (опционально): pages, ui, store, api, utils, const, types. При этом если какие-то константы, типы или хелперы нужны только для одного компонента, они идут в папку этого компонента. На уровень фичи поднимается только то, что нужно для нескольких модулей в ней.

Один коллега боялся, что пути/будут/вот/такие/длинные/ужас/кошмар. Но .../ui/Component это последний левел глубины. Внутри компонента всё плоско. Если меньше 10-15 файлов в папке, доп. уровни не нужны:

src/features/apps/ui/AppsTable/
AppsTable.tsx
AppsTable.module.css
DesktopRow.tsx
MobileRow.tsx
CellWrapper.tsx
useColumns.tsx
formatter.ts


Дальше учимся давать имена сущностям из вонючего ящика utils и выделять их из файлов по тыще строк. Типовые куски:

adapters/mappers — из ответов API в структуру, удобную для фронтенда и обратно — обычно в src/features/<feature>/api
validators — валидаторы/схемы для формочек — к соотв. компоненту
formatters — как мы даты форматируем и т.п. — к компоненту

Выкидываем barrel-файлы (index.ts с реэкспортами) из папок, которые не являются модулями:

src/features/apps/ui/AppsTable — модуль (компонент), кладём index.ts, реэкспортируем «публичный интерфейс» — скорее всего, это сам <AppsTable /> и его пропсы. А всякую внутреннюю шелуху типа форматтеров или useColumns не реэкспортим
src/shared/routing — модуль, кладём index.ts, реэкспортируем всякие константы маршутов, функции для их построения и тп
src/features/apps/ui/не модуль, а просто папочка организационная

👉 Писал про barrel-файлы у себя в блоге.

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

Зачем мы 2 недели обсуждали, если я сразу «знал, как надо»? Чтобы:
• провалидировать, что это решит проблемы именно текущего проекта, и именно самые больные
• адаптировать подход к проекту и команде, срезать углы, что-то улучшить
• ребята вовлеклись и участвовали в принятии решения, люди гораздо лучше делают то, что решили сами, чем что-то навязанное

Кстати, AI-агентам в такой структуре проще ориентироваться.

А вы в каком лагере?
🔥 features first: src/features/<feature>/ui
🤔 layers first: src/ui/<feature>/blabla
⭐️ уже иду рефакторить
🔥112
Forwarded from code_cleanup
Привет, а вот и новое видео!

В прошлой серии мы залезли в одну функцию сортировки и улучшали её. В этот раз смотрим шире — почему так больно работать с компонентом и откуда берутся данные.

А конкретно:
— выносим бизнес-логику из React компонента
— разбираемся с концепцией derived state
— используем селекторы в Zustand
— пишем тесты 💚 на стор без React и DOM
— и даже ловим классическую ошибку с getSnapshot в Next.js

Постарались сделать формат более живым, много обсуждений, сомнений и реальных решений по ходу.

Получился почти час 😅 наливайте чайку и залетайте к нам

https://youtu.be/oKbi-K2kj4Q
🔥52
Жизнь научила меня не смешивать разные изменения в одном PR

Фичи, багфиксы, рефакторинг — у этих изменений разный контекст и разный уровень риска. Бывает, сядешь за новую фичу, и видишь, отрефакторить бы немного, тогда фича отлично ляжет. Ну рефачишь, по дороге еще какой-то баг обнаружил в соседней фиче, его поправил, заливаешь пулрик на 1к строк с этим всем. В чём проблема?

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

Вот вас кое-как оревьюили, тестеры протестировали, выкатили на прод. Бум! Какая-то проблема проскочила все защиты и надо срочно откатывать. Тоже не проблема — мы же умные, роллбечим релиз.

Но в мастере-то код сломан. И следующий релиз будет сломан. Тут головняк пропорционален частоте ваших релизов. Надо мастер тоже чинить. Быстрее всего — ревертнуть. Но как? Допустим, проблема в той новой фиче, и откатить нужно именно её. Но вы в том же PR ещё багу починили, отревертите тот PR — бага вернётся. А ещё рефакторинг сделали (разный уровень риска). А ваши коллеги может уже понаписали там что-то поверх, будете ревертить — конфликтов не оберётесь. Короче, удачи.

А если бы вы в трёх отдельных PR сделали то же самое, ревертнули бы только фичу. Опенсорс тоже говорит об этом, вспомните React 18.3. Они там прямо говорят, что к предыдущей версии они добавили лишь ворнинги для подготовки к react 19. Чтобы обеспечить 3-шаговое обновление:

Шаг 1: Обновляетесь до 18.3 — если вы были на 18.2, то код совместим
Шаг 2: Чините все ворнинги и deprecations — короче активно шатаете кодовую базу
... тут вы даже можете пожить с этим какое-то время и убедиться что всё ок ...
Шаг 3: Обновляетесь до 19.0 — это должно пройти практически бесшовно, если вы на шаге 2 всё починили
сгорел прод? ну откатываете версию, а код не надо трогать

То же самое при внедрении новых правил линтеров:
1. Сначала приводите код в соответствие правилу
2. Потом врубаете его на всех

Это перекликается с идеей Branch by abstraction из TBD. Там большие изменения не могут долго жить в отдельной ветке. Их дробят на маленькие безопасные шаги, которые можно быстро влить и быстро откатить.

О чём надо себя спросить перед открытием PR: как я буду в случае чего это ревертить?
🔥54