Небольшой лайфхак.
Допустим, у вас есть проект и есть библиотека компонентов, которую вы используете в проекте. Вы делаете новый компонент в библиотеке. Для того, чтобы проверить, как он интегрируется с проектом, не обязательно релизить новую версию библиотеки - достаточно просто сбилдить библиотеку и подменить сборку библиотеки в node modules вашего проекта на только что собранную вами. Если ваш проект на next.js, то необходимо еще и удалить собранный next-ом билд проекта и пересобрать заново через next dev.
Допустим, у вас есть проект и есть библиотека компонентов, которую вы используете в проекте. Вы делаете новый компонент в библиотеке. Для того, чтобы проверить, как он интегрируется с проектом, не обязательно релизить новую версию библиотеки - достаточно просто сбилдить библиотеку и подменить сборку библиотеки в node modules вашего проекта на только что собранную вами. Если ваш проект на next.js, то необходимо еще и удалить собранный next-ом билд проекта и пересобрать заново через next dev.
🔥10🤡2
Возможно, я кого-то удивлю, но "клиентские компоненты" в next.js рендерятся на... сервере. А затем гидратируются на клиенте, и поэтому код таких компонентов прилетает в браузер.
В отличие от них, серверные компоненты не гидратируются на клиенте, а рендерятся только на сервере.
В отличие от них, серверные компоненты не гидратируются на клиенте, а рендерятся только на сервере.
👌5🤡5👍4
В чем основные преимущества серверных компонентов перед клиентскими в Next.js?
Серверные компоненты рендерятся только на сервере. Браузер не получает js код серверных компонентов, а получает только json-подобное описание необходимомого virtual dom, называемое rsc payload. За счет этого бандл становится меньше.
Второе серьезное преимущество - это поддержка streaming: сервер не дожидается, пока все дерево компонентов будет готово, а отправляет rsc payload по мере готовности, чтобы браузер мог отобразить то, что возможно, как можно скорее. На месте неготовых компонентов будут плейсхолдеры, и браузер заменит их на компоненты сразу, как получит их rsc payload с сервера.
Серверные компоненты рендерятся только на сервере. Браузер не получает js код серверных компонентов, а получает только json-подобное описание необходимомого virtual dom, называемое rsc payload. За счет этого бандл становится меньше.
Второе серьезное преимущество - это поддержка streaming: сервер не дожидается, пока все дерево компонентов будет готово, а отправляет rsc payload по мере готовности, чтобы браузер мог отобразить то, что возможно, как можно скорее. На месте неготовых компонентов будут плейсхолдеры, и браузер заменит их на компоненты сразу, как получит их rsc payload с сервера.
🔥15
Сегодня помогала фронтендеру в чате разобраться с проблемой.
Собственно, проблема: в верстке футер не достает до правого края, хотя указана ширина 100%. Такие проблемы обычно возникают, когда какой-то потомок выпал из контейнера. Например, у потомка указана ширина 100% и у родительского контейнера есть паддинги, из-за паддингов суммарно ширина становится больше 100% и вот уже потомок выпал из контейнера.
Рецепт дебага:
1. Нам нужно найти, какой элемент вывалился из контейнера. Идем в файл с html разметкой (или корневой компонент в вашем любимом фреймворке)
2. Комментируем ВСЕ. Проблема исчезнет, как и вся верстка с сайта.
3. Поочередно, по одной секции страницы, раскомментируем обратно
4. Та секция, на которой проблема снова появилась, и есть проблемная. В ней обычно легко найти вывалившийся элемент при помощи девтулзов браузера. Если нет, то рекурсивно повторяем историю с комментированием, но уже в рамках отдельной секции.
P.S. Лендинг со скриншота я создала за пару минут в https://v0.dev. Спасибо Сергею и его каналу https://t.iss.one/DragorWW_space за то, что регулярно освещает крутые нейронки для работы!
Собственно, проблема: в верстке футер не достает до правого края, хотя указана ширина 100%. Такие проблемы обычно возникают, когда какой-то потомок выпал из контейнера. Например, у потомка указана ширина 100% и у родительского контейнера есть паддинги, из-за паддингов суммарно ширина становится больше 100% и вот уже потомок выпал из контейнера.
Рецепт дебага:
1. Нам нужно найти, какой элемент вывалился из контейнера. Идем в файл с html разметкой (или корневой компонент в вашем любимом фреймворке)
2. Комментируем ВСЕ. Проблема исчезнет, как и вся верстка с сайта.
3. Поочередно, по одной секции страницы, раскомментируем обратно
4. Та секция, на которой проблема снова появилась, и есть проблемная. В ней обычно легко найти вывалившийся элемент при помощи девтулзов браузера. Если нет, то рекурсивно повторяем историю с комментированием, но уже в рамках отдельной секции.
P.S. Лендинг со скриншота я создала за пару минут в https://v0.dev. Спасибо Сергею и его каналу https://t.iss.one/DragorWW_space за то, что регулярно освещает крутые нейронки для работы!
👍7❤4
На днях спросили, какие темы в Javascript нужно знать для стажировки по этому направлению. Приведу полный список здесь:
- Переменные - let, const
- Условия - if else
- Циклы for, for of, for in, forEach, while
- Функции
- Типы данных (примитивы и объекты). Тип Symbol стажерам знать не обязательно :)
- Методы строк, методы массивов, методы объектов
- Промисы, async/await
- Ключевое слово this, bind, call, apply
- Таймеры: setTimeout, setInterval
Это основы Javascript, которые необходимы стажеру для того, чтобы начать практиковаться. Все остальное можно выучить уже позже😊
- Переменные - let, const
- Условия - if else
- Циклы for, for of, for in, forEach, while
- Функции
- Типы данных (примитивы и объекты). Тип Symbol стажерам знать не обязательно :)
- Методы строк, методы массивов, методы объектов
- Промисы, async/await
- Ключевое слово this, bind, call, apply
- Таймеры: setTimeout, setInterval
Это основы Javascript, которые необходимы стажеру для того, чтобы начать практиковаться. Все остальное можно выучить уже позже😊
1❤13
В одном из чатиков обещала рассказать, как я готовлю условные типы в typescript. Чаще всего они мне пригождаются, когда нужно один тип преобразовать в другой. Например, один раз мне нужно было написать функцию, которая получала объект с полями формы (имя, фамилия, город, возраст…) и вырезала оттуда все пустые строки. Таким образом, нужно было вывести тип-дженерик, который принимал бы исходный тип T и получал бы из него такой же тип, только с пустыми строками. Например, тип
Вот так вот я написала этот дженерик при помощи условных типов:
Дженерик проходится по всем полям в типе и проверяет, является ли это поле наследником от строки? Если да, то в новом типе это поле будет
type User = { name: string; age: number; sex: Sex }
нужно было преобразовать в { name?: string; age: number; sex: Sex }
. Вот так вот я написала этот дженерик при помощи условных типов:
export type OptionalString<T extends Record<string, any>> = {
[K in keyof T]: T[K] extends string ? string | undefined : T[K];
}
Дженерик проходится по всем полям в типе и проверяет, является ли это поле наследником от строки? Если да, то в новом типе это поле будет
string | undefined
, в противном случае - то же, что и было в исходном типе1❤10🤯7👍5🔥2
Media is too big
VIEW IN TELEGRAM
Вот такой вот сайт я сделала себе за день при помощи нейросети https://v0.dev/, при этом бОльшую часть времени работы я потратила на тексты и на настройку хостинга. Закинула пропмтом тему сайта и понравившуюся мне цветовую схему, и сервис сгенерировал мне готовый проект на next.js. Мне осталось только скачать его, заменить тексты на свои и захостить :)
Потыкать можно здесь: https://devmargooo.ru/
Потыкать можно здесь: https://devmargooo.ru/
🔥7🤯3
Как в next.js на серверной стороне определить, десктопную или мобильную версию сайта рисовать?
В популярных библиотеках для React существует много хуков, которые позволяют определить версию лейаута - мобильную или десктопную. Однако они все работают на браузерной стороне, а в next.js может потребоваться определить лейаут на серверной стороне, чтобы сразу отдать десктопную или мобильную верстку. Универсального рецепта у меня нет, но есть достаточно хороший:
1. Нам нужно получить заголовок user agent. В next это делается при помощи функции headers.
2. В мобильных браузерах обычно есть слова
В популярных библиотеках для React существует много хуков, которые позволяют определить версию лейаута - мобильную или десктопную. Однако они все работают на браузерной стороне, а в next.js может потребоваться определить лейаут на серверной стороне, чтобы сразу отдать десктопную или мобильную верстку. Универсального рецепта у меня нет, но есть достаточно хороший:
1. Нам нужно получить заголовок user agent. В next это делается при помощи функции headers.
import { headers } from 'next/headers';
export default async function Page() {
const userAgent = await headers().get('user-agent'));
….
}
2. В мобильных браузерах обычно есть слова
Mobile
, Android
, iPhone
, iPad
. Решение заключается в том, чтобы найти, есть ли какое-нибудь из этих слов и полученном user agent. Например, если в девтулах поставить мобильную версию и iphone 14, то вернет Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.
. Здесь есть сразу и Mobile, и iPhone.❤10
Неоплачиваемые стажировки: за/против
Мало какая тема в айти комьюнити вызывает столько бурления, как неоплачиваемые стажировки. Одна часть комьюнити гневно порицает тех, кто осмелился опубликовать вакансию с бесплатной стажировкой на своем проекте, другая часть считает, что это хороший шанс для новичков влиться в профессию. Давайте разберемся, как обстоят дела на самом деле.
Прежде всего нужно понять: проект проекту рознь. Это - самый главный фактор, который определяет, есть ли смысл вписываться в какой-либо проект на волонтерских началах. Для того, чтобы вы могли прокачать свои навыки на проекте, на этом проекте вы должны получать обратную связь от опытного разработчика, который подсветит вам ваши пробелы и ошибки. Например, блоггер S0ER периодически набирает ребят в проект Naris. Я сама участвовала в этом проекте, будучи уже далеко не джуном, и подчерпнула для себя много интересных разработческих фишек. Также многие крупные компании - например, Газпромбанк, Озон, ЦФТ, KTS - периодически набирают учеников на бесплатные курсы, в рамках которого вы также будете делать какой-либо учебный проект и получать обратную связь от менторов. Прокачка скиллов на таких проектах позволит вам не просто писать работоспособный код, но и сделать его гибким, поддерживаемым и масштабируемым.
Однако сейчас на рынке появилось много предложений бесплатных стажировок от мелких работодателей. Часто в таких вакансиях обещают нанять вас в штат после бесплатной стажировки. За редким исключением, такие проекты не способны вас ничему научить, потому что у них нет такой цели, на них не применяются best practices, часто формальное ревью. По сути, это просто бесплатная работа. Я советую вам избегать таких проектов и не надеяться, что после бесплатной стажировки вас обязательно возьмут в штат, потому что у работодателя есть прекрасная возможность этого не делать. На таком проекте вы просто потеряете время и мало чему научитесь.
Короче говоря: не стоит вестись на обещания «устроить в штат после бесплатной стажировки». Соглашайтесь только на те проекты, которые выгодны прямо здесь и сейчас. Выгода в бесплатных проектах заключается в возможности прокачать свои навыки и получить обратную связь от опытных коллег. Если проект не предлагает вам ни прокачки скиллов, ни денег, то не стоит тратить на него ни минуты своего времени.
Мало какая тема в айти комьюнити вызывает столько бурления, как неоплачиваемые стажировки. Одна часть комьюнити гневно порицает тех, кто осмелился опубликовать вакансию с бесплатной стажировкой на своем проекте, другая часть считает, что это хороший шанс для новичков влиться в профессию. Давайте разберемся, как обстоят дела на самом деле.
Прежде всего нужно понять: проект проекту рознь. Это - самый главный фактор, который определяет, есть ли смысл вписываться в какой-либо проект на волонтерских началах. Для того, чтобы вы могли прокачать свои навыки на проекте, на этом проекте вы должны получать обратную связь от опытного разработчика, который подсветит вам ваши пробелы и ошибки. Например, блоггер S0ER периодически набирает ребят в проект Naris. Я сама участвовала в этом проекте, будучи уже далеко не джуном, и подчерпнула для себя много интересных разработческих фишек. Также многие крупные компании - например, Газпромбанк, Озон, ЦФТ, KTS - периодически набирают учеников на бесплатные курсы, в рамках которого вы также будете делать какой-либо учебный проект и получать обратную связь от менторов. Прокачка скиллов на таких проектах позволит вам не просто писать работоспособный код, но и сделать его гибким, поддерживаемым и масштабируемым.
Однако сейчас на рынке появилось много предложений бесплатных стажировок от мелких работодателей. Часто в таких вакансиях обещают нанять вас в штат после бесплатной стажировки. За редким исключением, такие проекты не способны вас ничему научить, потому что у них нет такой цели, на них не применяются best practices, часто формальное ревью. По сути, это просто бесплатная работа. Я советую вам избегать таких проектов и не надеяться, что после бесплатной стажировки вас обязательно возьмут в штат, потому что у работодателя есть прекрасная возможность этого не делать. На таком проекте вы просто потеряете время и мало чему научитесь.
Короче говоря: не стоит вестись на обещания «устроить в штат после бесплатной стажировки». Соглашайтесь только на те проекты, которые выгодны прямо здесь и сейчас. Выгода в бесплатных проектах заключается в возможности прокачать свои навыки и получить обратную связь от опытных коллег. Если проект не предлагает вам ни прокачки скиллов, ни денег, то не стоит тратить на него ни минуты своего времени.
1👍13❤6🔥2
Как сделать скриншотные тесты в библиотеке компонентов?
Я не использую снепшотные тесты для тестирования ui компонентов, потому что такие тесты получаются слишком хрупкие и проверяют, по сути, порядок html тегов, а не ui результат. Зато мне кажется довольно удобным использовать скриншотные тесты. Скриншотные тесты делают снимок компонента, сохраняют его в файл и при прогоне проверяют, что скриншот не изменился. В своем ui kit я использую сторибук, и для скриншотных тестов я использую инструмент из коробки Test runner https://storybook.js.org/docs/writing-tests/test-runner. Под капотом он работает на Jest и Playwright. Test runner не дает такого гибкого конфигуриривания теста, как Playwright, но для тестирования ui компонентов мне пока хватает :) Ниже поделюсь рецептом, как я готовлю скриншотные тесты с использованием Test runner:
1️⃣ Во-первых, следует учесть, что под капотом скриншотные тесты поднимают безголовый браузер (обычно chromium), и рендеринг может работать по-разному в разных операционных системах. Поэтому я заворачиваю запуск тестов в докер, чтобы рендеринг был идентичен и на машине разработчика, и в CI/CD.
2️⃣ В качестве базового образа я использую playwright:1.49.0. Образ можно найти в докер хабе. Он уже содержит установленный playwright.
3️⃣ Во время сборки образа я копирую репозиторий с ui kit в докер контейнер и поднимаю storybook с флагом —no-open (ведь нам не нужно открывать его в браузере)
4️⃣ Добавляю в package.json команду, которая запустит тесты на поднятом контейнере. Я вынесла команду в отдельный bash файл и вот что там есть:
1.
2.
3.
5️⃣ Готово! Вы великолепны. Теперь прогон скриншотных тестов осуществляется в докер контейнере, что обеспечивает универсальность рендера компонентов и на машинах разработчика, и в ci/cd🎆
Я не использую снепшотные тесты для тестирования ui компонентов, потому что такие тесты получаются слишком хрупкие и проверяют, по сути, порядок html тегов, а не ui результат. Зато мне кажется довольно удобным использовать скриншотные тесты. Скриншотные тесты делают снимок компонента, сохраняют его в файл и при прогоне проверяют, что скриншот не изменился. В своем ui kit я использую сторибук, и для скриншотных тестов я использую инструмент из коробки Test runner https://storybook.js.org/docs/writing-tests/test-runner. Под капотом он работает на Jest и Playwright. Test runner не дает такого гибкого конфигуриривания теста, как Playwright, но для тестирования ui компонентов мне пока хватает :) Ниже поделюсь рецептом, как я готовлю скриншотные тесты с использованием Test runner:
1️⃣ Во-первых, следует учесть, что под капотом скриншотные тесты поднимают безголовый браузер (обычно chromium), и рендеринг может работать по-разному в разных операционных системах. Поэтому я заворачиваю запуск тестов в докер, чтобы рендеринг был идентичен и на машине разработчика, и в CI/CD.
2️⃣ В качестве базового образа я использую playwright:1.49.0. Образ можно найти в докер хабе. Он уже содержит установленный playwright.
3️⃣ Во время сборки образа я копирую репозиторий с ui kit в докер контейнер и поднимаю storybook с флагом —no-open (ведь нам не нужно открывать его в браузере)
4️⃣ Добавляю в package.json команду, которая запустит тесты на поднятом контейнере. Я вынесла команду в отдельный bash файл и вот что там есть:
1.
docker exec -it [container] node_modules/.bin/test-storybook
- запускаю Test runner из node_modules2.
find src -type d -name '__diff_output__' -exec rm -rf {} +
- удаляю старые файлы с диффами тестов перед каждым новым прогоном`3.
docker cp [container] :/opt/src .
- копирую репо из контейнера в рабочую директорию, это нужно для того, чтобы в рабочей директории появились файлы с диффами тестов`5️⃣ Готово! Вы великолепны. Теперь прогон скриншотных тестов осуществляется в докер контейнере, что обеспечивает универсальность рендера компонентов и на машинах разработчика, и в ci/cd
Please open Telegram to view this post
VIEW IN TELEGRAM
Storybook
Test runner | Storybook docs
Storybook is a frontend workshop for building UI components and pages in isolation. Thousands of teams use it for UI development, testing, and documentation. It's open source and free.
1🔥16👍5
В последнее время многие айтишники начали вести свои каналы. Конкуренция на рынке труда становится жестче, и личный бренд помогает нетворкингу, через который можно найти самые вкусные вакансии. Я читаю вообще все айтишные каналы, которые нахожу - это позволяет мне держать руку на пульсе и понимать ситуацию на рынке труда. Сегодня у меня для вас подборка айти каналов - возможно, что-то из этого понравится и вам 😊
Клуб IT-блоггеров - сообщество для тех, кто ведет свои телеграмм каналы на айти тематику. Общение с ребятами из клуба помогает мне писать посты лучше и интереснее 😊
Счастливый тимлид — канал для менеджеров и разработчиков о том как не сойти с ума в айтишке, как беречь кукуху и жить свою лучшую жизнь. Женя рассказывает классные истории и его очень интересно читать.
<Frontend вдохновляет/> - авторский канал Александра для тех, кто хочет получить заряд мотивации. Истории с работы, юмор, разбор примеров кода и советы новичкам (и не только им) - все здесь 🙂
{ Снежные строки } — канал о фронтенд разработке, где можно учиться вместе с автором. Здесь разбирают JavaScript, React и другие технологии, делятся опытом прохождения собеседований, тестируют новые подходы в разработке. Всё, чтобы развиваться в профессии и прокачивать навыки!
Коучинг для ИТ с Анной Бикеевой — канал коуча с 17-летним бэкграундом в ИТ, где автор рассказывает на своем опыте и опыте клиентов, как работа с мышлением помогает расти в карьере и громко заявлять о себе!
В АйТи из Уфы - канал о буднях во Frontend разработке без технических деталей.
Раушан рассказывает как перешёл из другой сферы, проходит собесы и собирается в web3 разработку.
Делится чем интересуется вне работы, чтобы держать кукуху на месте 🙃
IT Инсайты — канал лида разработки с 12-летним опытом в ИТ-сфере, где публикуются полезные мысли и советы для сотрудников ИТ и их руководителей. Канал будет интересен как начинающим, так и опытным специалистам 🤗
Клуб IT-блоггеров - сообщество для тех, кто ведет свои телеграмм каналы на айти тематику. Общение с ребятами из клуба помогает мне писать посты лучше и интереснее 😊
Счастливый тимлид — канал для менеджеров и разработчиков о том как не сойти с ума в айтишке, как беречь кукуху и жить свою лучшую жизнь. Женя рассказывает классные истории и его очень интересно читать.
<Frontend вдохновляет/> - авторский канал Александра для тех, кто хочет получить заряд мотивации. Истории с работы, юмор, разбор примеров кода и советы новичкам (и не только им) - все здесь 🙂
{ Снежные строки } — канал о фронтенд разработке, где можно учиться вместе с автором. Здесь разбирают JavaScript, React и другие технологии, делятся опытом прохождения собеседований, тестируют новые подходы в разработке. Всё, чтобы развиваться в профессии и прокачивать навыки!
Коучинг для ИТ с Анной Бикеевой — канал коуча с 17-летним бэкграундом в ИТ, где автор рассказывает на своем опыте и опыте клиентов, как работа с мышлением помогает расти в карьере и громко заявлять о себе!
В АйТи из Уфы - канал о буднях во Frontend разработке без технических деталей.
Раушан рассказывает как перешёл из другой сферы, проходит собесы и собирается в web3 разработку.
Делится чем интересуется вне работы, чтобы держать кукуху на месте 🙃
IT Инсайты — канал лида разработки с 12-летним опытом в ИТ-сфере, где публикуются полезные мысли и советы для сотрудников ИТ и их руководителей. Канал будет интересен как начинающим, так и опытным специалистам 🤗
Telegram
Tribute
This bot helps content creators receive financial support from their followers directly in the app.
1👍4👀2❤1🔥1
Как новичку дебажить? Часть 1.
Я довольно много занимаюсь менторингом джунов и заметила такую вещь: практически все джуны не умеет дебажить. На курсах учат писать код и делать фичи, а не дебажить уже имеющийся код и лечить баги. Потом, когда такой джун выходит на свою первую работу, чаще всего в качестве первых задач он получает багофикс и смотри на негокак баран на новые ворота в полной растерянности, не понимая, что с ним делать. К счастью для джунов, они могут подписаться на мой канал, где я постепенно буду раскрывать эту тему😊
Первое, что критически необходимо понять: любая программа (да, и ваш проект тоже) представляет из себя совокупность данных, которые каким-то образом изменяются на протяжении своей “жизни” в программе. Представьте себе: вот есть данные, они хранятся в какой-то переменной, а дальше они проделывают какой-то путь по вашей программе: передаются из функции в функцию, из хранилища в компонент, из компонента запросом бекенд, а с бекенда - в стор (такой путь данных по сути есть call stack, но пока не будем об этом). Я у себя в голове визуализирую путь данных как движущийся поток из одного места в другое.
Второе, что критически необходимо понять, если вы фронтендер: современный фронтенд по большей части использует реактивные фреймворки, такие как React, Vue, Angular (в этом посте мы не будем душнить про то, что React - библиотека, а не фреймворк, оки?☺️). Реактивные - означает, что сначала меняются данные, а затем фреймворк реактивно обновляет свой ui (обратный процесс тоже возможен, пока не будем об этом). Если вы пишете на jquery, то для вас это не работает, вам нужно обновлять ваш ui ручками.
Таким образом мы можем понять, почему возник ваш баг: данные где-то на своем пути были неверно преобразованы, поэтому вы видите что-то неправильное в вашем ui. Я хочу вам предложить следующий способ дебага: вам нужно проследить весь путь данных от момента их зарождения до момента попадания в конкретный элемент ui, и найти звено, где было выполнено неверное преобразование.
Например: вы столкнулись с проблемой, что данные из профиля пользователя неверно отображаются. Вам нужно найти место, где они хранятся (например, стор приложения), вывести их в console.log, затем посмотреть, через какую цепочку функций и компонентов они попадают в ваш ui элемент, вывести их в лог так же в этих звеньях, и, наконец, вывести их в лог в самом ui компоненте. Необязательно ставить лог прям в каждом звене, на весь путь достаточно 2-3 логов, а дальше можно ставить дополнительные логи по мере того, как будет проясняться, в каком куске программы данные передаются неверно. В следующих посте я покажу на примере, как это можно сделать.
Вышеописанный способ - не единственный способ дебажить и даже не самый эффективный, но, как показала моя преподавательская практика, он наиболее эффективен для обучения дебагу с нуля. Если вы совсем не умеете дебажить, попробуйте этот способ. Далее я буду рассказывать и другие способы дебага.
#дебаг
Я довольно много занимаюсь менторингом джунов и заметила такую вещь: практически все джуны не умеет дебажить. На курсах учат писать код и делать фичи, а не дебажить уже имеющийся код и лечить баги. Потом, когда такой джун выходит на свою первую работу, чаще всего в качестве первых задач он получает багофикс и смотри на него
Первое, что критически необходимо понять: любая программа (да, и ваш проект тоже) представляет из себя совокупность данных, которые каким-то образом изменяются на протяжении своей “жизни” в программе. Представьте себе: вот есть данные, они хранятся в какой-то переменной, а дальше они проделывают какой-то путь по вашей программе: передаются из функции в функцию, из хранилища в компонент, из компонента запросом бекенд, а с бекенда - в стор (такой путь данных по сути есть call stack, но пока не будем об этом). Я у себя в голове визуализирую путь данных как движущийся поток из одного места в другое.
Второе, что критически необходимо понять, если вы фронтендер: современный фронтенд по большей части использует реактивные фреймворки, такие как React, Vue, Angular (в этом посте мы не будем душнить про то, что React - библиотека, а не фреймворк, оки?☺️). Реактивные - означает, что сначала меняются данные, а затем фреймворк реактивно обновляет свой ui (обратный процесс тоже возможен, пока не будем об этом). Если вы пишете на jquery, то для вас это не работает, вам нужно обновлять ваш ui ручками.
Таким образом мы можем понять, почему возник ваш баг: данные где-то на своем пути были неверно преобразованы, поэтому вы видите что-то неправильное в вашем ui. Я хочу вам предложить следующий способ дебага: вам нужно проследить весь путь данных от момента их зарождения до момента попадания в конкретный элемент ui, и найти звено, где было выполнено неверное преобразование.
Например: вы столкнулись с проблемой, что данные из профиля пользователя неверно отображаются. Вам нужно найти место, где они хранятся (например, стор приложения), вывести их в console.log, затем посмотреть, через какую цепочку функций и компонентов они попадают в ваш ui элемент, вывести их в лог так же в этих звеньях, и, наконец, вывести их в лог в самом ui компоненте. Необязательно ставить лог прям в каждом звене, на весь путь достаточно 2-3 логов, а дальше можно ставить дополнительные логи по мере того, как будет проясняться, в каком куске программы данные передаются неверно. В следующих посте я покажу на примере, как это можно сделать.
Вышеописанный способ - не единственный способ дебажить и даже не самый эффективный, но, как показала моя преподавательская практика, он наиболее эффективен для обучения дебагу с нуля. Если вы совсем не умеете дебажить, попробуйте этот способ. Далее я буду рассказывать и другие способы дебага.
#дебаг
1👍12🔥7💯5
Как новичку дебажить? Часть 2.
В прошлой части я обещала показать на примере, как может выглядеть дебаг конкретной проблемы. Рассмотрим следующую ситуацию: на вас в жире ставят баг, где написано, что при переключении тоггла светлая/темная тема тема не меняется. Вы запускаете приложение, тыкаете на тоггл темы и видите - и в самом деле не меняется. В такой ситуации алгоритм действий дебага будет следующий:
1️⃣ Помните, в прошлой части мы говорили о том, что приложение - это данные, которые меняются по ходу жизни приложения? Тема - это тоже данные. Наша первоочередная задача - найти, где они хранятся. Хранятся они в какой-то переменной в коде. Эта переменная может читать данные из local storage, из параметров урла, она может выглядеть как поле в redux или значение в useState, но она точно существует. Наша задача ее найти. Как? Для этого надо найти в коде тоггл, посмотреть его обработчик onchange и посмотреть, куда этот обработчик пытается писать данные. Так вы найдете место, где хранится значение темы.
2️⃣ Допустим, на предыдущем шаге вы выяснили, что тема хранится, например, в контексте. Теперь наша задача - проследить весь путь этих данных от провайдера контекста до конкретных компонентов. Возьмите для примера один какой-нибудь компонент. Пусть это будет какая-нибудь панель. Затем посмотрите, откуда она получает данные о теме. Она может получать данные из провайдера напрямую, из пропсов, возможны разные варианты.
3️⃣ Допустим, наша панель получает данные из пропсов. Получается, данные передает родитель. Теперь надо найти, откуда получает данные родитель. Нам нужно распутать всю цепочку, как данные из места, найденного в п.1, попали в наш компонент. (Примечание: со временем вам не нужно будет разбирать всю цепочку, достаточно будет нескольких звеньев, но поначалу такой полный разбор эффективен для обучения)
4️⃣ Вы выяснили путь, по которому данные попадают из контекста в панель. Теперь наша задача - определить, на каком шаге данные искажаются неверно. Для этого ставим console.log в панели и в том месте, где один из родителей получает данные из контекста, и в панели тоже.
5️⃣ Вы снова воспроизводите баг и видите: ваш родитель получает верную тему из контекста и передает ее вниз по дереву компонентов, но сам компонент панели получает от своего родителя старую тему! Добавляем console.log в промежуточных компонентов по цепочке передачи данных.
6️⃣ Вы обнаружили, что последний компонент, который получил данные верно, был компонент, скажем, Wrapper, а дальше уже данные передаются неверно. Отлично, мы нашли проблемное место - это компонент Wrapper!
7️⃣ Теперь нужно посмотреть, как именно Wrapper передает данные вниз. Скорее всего, на этом этапе вы уже сможете вручную заметить ошибку в коде - например, компонент может мемоизировать данные и передавать мемоизированные данные. Достаточно будет заново вычислять мемоизированное значение при смене темы и баг будет пофикшен🎉
#дебаг
В прошлой части я обещала показать на примере, как может выглядеть дебаг конкретной проблемы. Рассмотрим следующую ситуацию: на вас в жире ставят баг, где написано, что при переключении тоггла светлая/темная тема тема не меняется. Вы запускаете приложение, тыкаете на тоггл темы и видите - и в самом деле не меняется. В такой ситуации алгоритм действий дебага будет следующий:
1️⃣ Помните, в прошлой части мы говорили о том, что приложение - это данные, которые меняются по ходу жизни приложения? Тема - это тоже данные. Наша первоочередная задача - найти, где они хранятся. Хранятся они в какой-то переменной в коде. Эта переменная может читать данные из local storage, из параметров урла, она может выглядеть как поле в redux или значение в useState, но она точно существует. Наша задача ее найти. Как? Для этого надо найти в коде тоггл, посмотреть его обработчик onchange и посмотреть, куда этот обработчик пытается писать данные. Так вы найдете место, где хранится значение темы.
2️⃣ Допустим, на предыдущем шаге вы выяснили, что тема хранится, например, в контексте. Теперь наша задача - проследить весь путь этих данных от провайдера контекста до конкретных компонентов. Возьмите для примера один какой-нибудь компонент. Пусть это будет какая-нибудь панель. Затем посмотрите, откуда она получает данные о теме. Она может получать данные из провайдера напрямую, из пропсов, возможны разные варианты.
3️⃣ Допустим, наша панель получает данные из пропсов. Получается, данные передает родитель. Теперь надо найти, откуда получает данные родитель. Нам нужно распутать всю цепочку, как данные из места, найденного в п.1, попали в наш компонент. (Примечание: со временем вам не нужно будет разбирать всю цепочку, достаточно будет нескольких звеньев, но поначалу такой полный разбор эффективен для обучения)
4️⃣ Вы выяснили путь, по которому данные попадают из контекста в панель. Теперь наша задача - определить, на каком шаге данные искажаются неверно. Для этого ставим console.log в панели и в том месте, где один из родителей получает данные из контекста, и в панели тоже.
5️⃣ Вы снова воспроизводите баг и видите: ваш родитель получает верную тему из контекста и передает ее вниз по дереву компонентов, но сам компонент панели получает от своего родителя старую тему! Добавляем console.log в промежуточных компонентов по цепочке передачи данных.
6️⃣ Вы обнаружили, что последний компонент, который получил данные верно, был компонент, скажем, Wrapper, а дальше уже данные передаются неверно. Отлично, мы нашли проблемное место - это компонент Wrapper!
7️⃣ Теперь нужно посмотреть, как именно Wrapper передает данные вниз. Скорее всего, на этом этапе вы уже сможете вручную заметить ошибку в коде - например, компонент может мемоизировать данные и передавать мемоизированные данные. Достаточно будет заново вычислять мемоизированное значение при смене темы и баг будет пофикшен🎉
#дебаг
Telegram
Фронтенд кухня🥘
Как новичку дебажить? Часть 1.
Я довольно много занимаюсь менторингом джунов и заметила такую вещь: практически все джуны не умеет дебажить. На курсах учат писать код и делать фичи, а не дебажить уже имеющийся код и лечить баги. Потом, когда такой джун выходит…
Я довольно много занимаюсь менторингом джунов и заметила такую вещь: практически все джуны не умеет дебажить. На курсах учат писать код и делать фичи, а не дебажить уже имеющийся код и лечить баги. Потом, когда такой джун выходит…
🔥11❤1
Продолжаем тему дебага при помощи логов. Как вы думаете, что мы увидим в консоли?
const obj = {};
console.log('1', obj);
console.log('2', obj.a);
obj.a = 'aaa';
Что выведет код?
Anonymous Quiz
63%
1: {} 2: undefined
7%
1: {a: 'aaa'} 2: a
17%
1: {a: 'aaa'} 2: undefined
13%
a: {} 2: Reference Error
🤯7🔥1
Предыдущий пример логирования дает очень интересный результат. В браузере вы увидите объект, в котором при раскрытии будет поле "a", записанное уже после лога. Так происходит потому, что в javascript объект - это ссылка, и при раскрытии объекта по ссылке в некоторых браузерах - например, в хроме - вы можете увидеть уже измененное состояние объекта. Таким образом, слепое доверие консоли браузера при логировании ссылочных типов может стоить вам нескольких часов бесплодного дебага. Это особенно актуально, если вы используете описанный мной в предыдущих постах способ "проследить, как меняются данные на своем пути от источника к моменту вывода".
Так как же надежно логировать объекты? Я логирую объекты, преобразуя их в строку при помощи JSON.stringify:
Такой код преобразует объект в примитивную строку и отформатирует 4 пробелами. Используя данный способ, вы гарантированно выведете актуальное на момент лога состояние объекта.
P.S. В комментариях справедливо заметили, что в примере из опроса в лог выведется пустой объект, а уже на момент раскрытия в него допишется свойство. Признаю свою вину за неверную формулировку в вопросе. Единственной целью этого опроса было показать, как вы можете ошибиться при логировании объектов в javascript, и, надеюсь, мне удалось достичь этой цели 😊
#дебаг
Так как же надежно логировать объекты? Я логирую объекты, преобразуя их в строку при помощи JSON.stringify:
JSON.stringify(obj, null, 4)
Такой код преобразует объект в примитивную строку и отформатирует 4 пробелами. Используя данный способ, вы гарантированно выведете актуальное на момент лога состояние объекта.
P.S. В комментариях справедливо заметили, что в примере из опроса в лог выведется пустой объект, а уже на момент раскрытия в него допишется свойство. Признаю свою вину за неверную формулировку в вопросе. Единственной целью этого опроса было показать, как вы можете ошибиться при логировании объектов в javascript, и, надеюсь, мне удалось достичь этой цели 😊
#дебаг
👍20
Forwarded from Радикальная идея
Почему программисты ненавидят работать с чужим кодом?
Вот представь, что тебе доверили достроить за другим прорабом лабораторию на острове. Ты приходишь на объект, а там кроме недостроенного здания: огромный вентилятор (размером со здание), большой воздушный шар и комната набитая швабрами. Почесав голову, ты разбираешь этот хлам и доделываешь лабораторию. Сдаешь объект ученным, но через 5 минут они выбегают с криком: "УТЕЧКА ЯДОВИТОГО ГАЗА!!!".
— Как так–то, б..ть! Должно же работать! — в отчаянии кричишь ты и звонишь прошлому прорабу:
— Вася, у нас ядовитый газ потёк! В чем проблема?
— Не знаю, должно было все работать. Что–то в проекте менял?
— Немного, швабры вынес...
— Швабры потолок держали!
— Что??? Что, б...ть, извините???
— Говорю, швабры потолок держали. Над ними цистерны с газом были. Очень тяжелые, пришлось в комнату снизу швабры напихать.
— Ты хотя бы записку на двери повесил бы, что швабры для держания потолка! У нас тут ядовитый газ течет! Что нам делать?
— Включай вентилятор. Он сдует газ с острова.
— Я его, б...ть, демонтировал сразу же!
— Зачем?
— Зачем ты построил 120 тонный вентилятор? Ты не мог положить ящик бл...ских ПРОТИВОГАЗОВ?
— Ящик противогазов искать нужно, а вентилятор у меня с прошлого заказа оставался.
— Вася, я убрал твой вентилятор! Мы тут задыхаемся!
— Херли вы тогда там делаете? Садитесь на воздушный шар и у..бывайте!
—-
Баян, но каждый раз смеюсь
Вот представь, что тебе доверили достроить за другим прорабом лабораторию на острове. Ты приходишь на объект, а там кроме недостроенного здания: огромный вентилятор (размером со здание), большой воздушный шар и комната набитая швабрами. Почесав голову, ты разбираешь этот хлам и доделываешь лабораторию. Сдаешь объект ученным, но через 5 минут они выбегают с криком: "УТЕЧКА ЯДОВИТОГО ГАЗА!!!".
— Как так–то, б..ть! Должно же работать! — в отчаянии кричишь ты и звонишь прошлому прорабу:
— Вася, у нас ядовитый газ потёк! В чем проблема?
— Не знаю, должно было все работать. Что–то в проекте менял?
— Немного, швабры вынес...
— Швабры потолок держали!
— Что??? Что, б...ть, извините???
— Говорю, швабры потолок держали. Над ними цистерны с газом были. Очень тяжелые, пришлось в комнату снизу швабры напихать.
— Ты хотя бы записку на двери повесил бы, что швабры для держания потолка! У нас тут ядовитый газ течет! Что нам делать?
— Включай вентилятор. Он сдует газ с острова.
— Я его, б...ть, демонтировал сразу же!
— Зачем?
— Зачем ты построил 120 тонный вентилятор? Ты не мог положить ящик бл...ских ПРОТИВОГАЗОВ?
— Ящик противогазов искать нужно, а вентилятор у меня с прошлого заказа оставался.
— Вася, я убрал твой вентилятор! Мы тут задыхаемся!
— Херли вы тогда там делаете? Садитесь на воздушный шар и у..бывайте!
—-
Баян, но каждый раз смеюсь
😁18🔥1
Денис написал отличный пост про проектирование... чего угодно. Будь то класс, реакт компонент или же обычная функция. Всегда в первую очередь думайте о том, какую возможность вашего кода вы хотите открыть его потребителям, а какую - скрыть и не дать возможность использовать извне
❤2
Forwarded from zede code
The pit of Failure (or Success)
Часто при проектировании API кроме того что нам важно думать не только о фичах и возможностях которые он дает, но и какой импакт этот API несет при использовании. И тут есть 2 противоположных концепта: Falling Into The Pit of Success/Failure или при переводе Упасть В Яму Успеха/Неудачи.
Какие же ключевые принципы разработки за этим скрываются? Если сократить и упростить, то выйдет: Делай так чтобы правильно было использовать легко, а неправильно сложно. Те наша задача мотивировать людей и поощрять правильное использование API и делать так, чтобы некорректное использование всем видом кричало, что тут дела обстоят не так (fall into the pit of success). Обратный пример, когда API словно подталкивает использовать себя грязно, а использовать корректно больше похоже на тернистый путь или полосу испытаний (Я думаю каждый сталкивался с таким ощущением)
Давайте возьмем пару примеров из API и рассмотрим их:
React:
И тут нам интересно API
И вот сегодня я увидел обратный пример из мира Svelte:
Это сегодняшний анонс долгожданной фичи, чтобы вычислимые значения могли быть временно изменены. Крутая же фича? В целом да, ее запрашивали и ждали, а без нее приходилось использовать костыли. И вроде как надо радоваться? Нам же дали возможность и маловероятно, что оно что-то сломает... Но вот тут как раз всплывает тема того к чему мы подталкиваем дизайном нашего API.
В реактивной системе необходимость делать writable вычислимые поля достаточно редка. Кроме того нам дали возможность делать только прямую запись, а не условный сеттер который бы позволил сделать two way connection, нет, это не тот случай! Те мы можем просто лезть в кэш вычислимого свойства и подменять его до изменения значения. Ну надо же людям эту фичу, в чем проблема? А в том, что в 99% случаев эта фича не нужна, а вот все 100% $derived полей стали вместо read-only теперь writable. И никакой вас TypeScript не спасет от записи в него случайно (например, при рефакторинге) и вы больше видя перед собой $derived не можете быть уверены записывают что-то в него или нет, эта информация лежит где-то в другом месте компонента и пока вы не прочтете код компонента полностью вы больше не можете быть в этом уверены.
Таким образом эта возможность не подталкивает к правильному использованию сигналов, делает так что допускать случайные ошибки стало проще и при этом осталось относительно скудным по возможностям (как и написал это не дает возможность делать two way connection). С другой стороны мы покрыли возможность 1% от случаев. Вот это пример, когда мы видим собой
Как этого можно было избежать?
Использовать отдельный нейминг
Или использовать отдельный параметр
Или на худой конец если мы хотим оставить магию в нашем мире, то создать явное API
Это все еще лучше, чем выкинуть забор и дать неявное по смыслу API.
Не думайте что это "написать плохо на чем угодно можно" /"вопрос прямых рук". НЕТ! Вы, как автор API, должны формировать у людей прямые руки, а кривые выпрямлять. Пожалуйста, прикидывайте в голове эти сценарии: "мотивирую ли я делать что-то плохое" и "поощряю ли я правильное использование". Спасибо...
Часто при проектировании API кроме того что нам важно думать не только о фичах и возможностях которые он дает, но и какой импакт этот API несет при использовании. И тут есть 2 противоположных концепта: Falling Into The Pit of Success/Failure или при переводе Упасть В Яму Успеха/Неудачи.
Какие же ключевые принципы разработки за этим скрываются? Если сократить и упростить, то выйдет: Делай так чтобы правильно было использовать легко, а неправильно сложно. Те наша задача мотивировать людей и поощрять правильное использование API и делать так, чтобы некорректное использование всем видом кричало, что тут дела обстоят не так (fall into the pit of success). Обратный пример, когда API словно подталкивает использовать себя грязно, а использовать корректно больше похоже на тернистый путь или полосу испытаний (Я думаю каждый сталкивался с таким ощущением)
Давайте возьмем пару примеров из API и рассмотрим их:
React:
<div dangerouslySetInnerHTML={{ __html: "Hello" }} />
И тут нам интересно API
dangerouslySetInnerHTML
, видите что оно делает? Да, оно всем своим видом кричит, что вы делаете что-то опасное и нехорошее, а громоздкость с { __html: "Hello" }
дополняет картинку. В добавок вам еще будет сложнее точно сходу вспомнить правильное написание и вы пойдете в документацию, где вам еще раз дадут понять: "скорее всего ты делаешь что-то не то". Это прекрасный пример того, как с помощью API вам не дают применить нечто потенциально опасное.И вот сегодня я увидел обратный пример из мира Svelte:
let double = $derived(count*2);
double = 3.14;
Это сегодняшний анонс долгожданной фичи, чтобы вычислимые значения могли быть временно изменены. Крутая же фича? В целом да, ее запрашивали и ждали, а без нее приходилось использовать костыли. И вроде как надо радоваться? Нам же дали возможность и маловероятно, что оно что-то сломает... Но вот тут как раз всплывает тема того к чему мы подталкиваем дизайном нашего API.
В реактивной системе необходимость делать writable вычислимые поля достаточно редка. Кроме того нам дали возможность делать только прямую запись, а не условный сеттер который бы позволил сделать two way connection, нет, это не тот случай! Те мы можем просто лезть в кэш вычислимого свойства и подменять его до изменения значения. Ну надо же людям эту фичу, в чем проблема? А в том, что в 99% случаев эта фича не нужна, а вот все 100% $derived полей стали вместо read-only теперь writable. И никакой вас TypeScript не спасет от записи в него случайно (например, при рефакторинге) и вы больше видя перед собой $derived не можете быть уверены записывают что-то в него или нет, эта информация лежит где-то в другом месте компонента и пока вы не прочтете код компонента полностью вы больше не можете быть в этом уверены.
Таким образом эта возможность не подталкивает к правильному использованию сигналов, делает так что допускать случайные ошибки стало проще и при этом осталось относительно скудным по возможностям (как и написал это не дает возможность делать two way connection). С другой стороны мы покрыли возможность 1% от случаев. Вот это пример, когда мы видим собой
pit of failure
, да нас не мотивируют прямым образом использовать этот функционал неправильно, но "заборчик" рядом с ямой куда-то унесли.Как этого можно было избежать?
Использовать отдельный нейминг
let double = $writableDerived(count*2);
double = 3.14;
Или использовать отдельный параметр
let double = $derived(count*2, { writable: true }); // или любая другая явная модификация
double = 3.14;
Или на худой конец если мы хотим оставить магию в нашем мире, то создать явное API
let double = $derived(count*2);
$modifyDerivedCache(double, 3.14); // мы сделали неудобное, но однозначное API
Это все еще лучше, чем выкинуть забор и дать неявное по смыслу API.
Не думайте что это "написать плохо на чем угодно можно" /"вопрос прямых рук". НЕТ! Вы, как автор API, должны формировать у людей прямые руки, а кривые выпрямлять. Пожалуйста, прикидывайте в голове эти сценарии: "мотивирую ли я делать что-то плохое" и "поощряю ли я правильное использование". Спасибо...
👍7❤3