Forwarded from S0ER
Promise.race
Всем привет, на связи Марго @devmargooo и сегодня я расскажу вам про Promise.race.🏎 Promise.race принимает в качестве аргумента массив промисов и возвращает результат того промиса, который завершится первым. Значит ли это, что после завершения Promise.race можно просто забыть про те промисы, которые проиграли гонку? Оказывается, нет. В 2017 году была описана интересная утечка памяти в Promise.race https://github.com/nodejs/node/issues/17469#issuecomment-685216777. Эта утечка интересна не сама по себе (мне кажется, Promise.race не так часто используют), а тем, что она представляет собой очень показательный пример утечки памяти в js через замыкания. Рассмотрим следующие тезисы.
1. Промис сохраняет свой результат все время, которое он живет.
Некоторые разработчики считают, что если мы не используем результат, который вернул промис, то он освободит память сразу после того, как промис завершится. Это не так! Результат промиса сохраняется в его внутреннем свойстве result все время, пока живет (= ссылочно доступен) сам промис.
2. Также, если промис зарезолвился, это еще не значит, что данные внутри его функции-исполнителя (функция, которую передали в конструктор промиса) больше не удерживаются в памяти. Нет, они могут удерживаться в памяти, например, если внутри исполнителя был setTimeout.
3. Рассмотрим следующий код и попробуем память, когда из памяти будет удален “super string”.
В данном случае neverResolve завис в памяти, а с ним и весь родительский промис p. Результат промиса resolveString сохранился как внутренее свойство result объекта p. Если “super string” - это тяжелые данные, то мы получим существенную утечку памяти. По всей видимости, механизм утечки памяти в Promise.race аналогичен вышеизложенному.
Всем привет, на связи Марго @devmargooo и сегодня я расскажу вам про Promise.race.🏎 Promise.race принимает в качестве аргумента массив промисов и возвращает результат того промиса, который завершится первым. Значит ли это, что после завершения Promise.race можно просто забыть про те промисы, которые проиграли гонку? Оказывается, нет. В 2017 году была описана интересная утечка памяти в Promise.race https://github.com/nodejs/node/issues/17469#issuecomment-685216777. Эта утечка интересна не сама по себе (мне кажется, Promise.race не так часто используют), а тем, что она представляет собой очень показательный пример утечки памяти в js через замыкания. Рассмотрим следующие тезисы.
1. Промис сохраняет свой результат все время, которое он живет.
Некоторые разработчики считают, что если мы не используем результат, который вернул промис, то он освободит память сразу после того, как промис завершится. Это не так! Результат промиса сохраняется в его внутреннем свойстве result все время, пока живет (= ссылочно доступен) сам промис.
2. Также, если промис зарезолвился, это еще не значит, что данные внутри его функции-исполнителя (функция, которую передали в конструктор промиса) больше не удерживаются в памяти. Нет, они могут удерживаться в памяти, например, если внутри исполнителя был setTimeout.
3. Рассмотрим следующий код и попробуем память, когда из памяти будет удален “super string”.
const resolveString = new Promise((resolve) => resolve("super string"));
const neverResolve = new Promise(() => {});
const promises = [resolveString, neverResolve];
const p = new Promise((resolve, reject) => {
for (const promise of promises) {
Promise.resolve(promise).then(resolve, reject);
}
});
В данном случае neverResolve завис в памяти, а с ним и весь родительский промис p. Результат промиса resolveString сохранился как внутренее свойство result объекта p. Если “super string” - это тяжелые данные, то мы получим существенную утечку памяти. По всей видимости, механизм утечки памяти в Promise.race аналогичен вышеизложенному.
GitHub
`Promise.race` lead to memory leak · Issue #17469 · nodejs/node
Version: v9.2.0 and v8.9.1, probably other version also affected Platform: linux Subsystem: - I run this code inside docker with -m 100m --memory-swap 100m , and then the program crash after few se...
❤1👍1🤡1
Forwarded from S0ER
Разделение ответственности в UI компонентах
Привет, на связи @devmargooo и сегодня я хотела бы рассказать свои мысли насчет разделения ответственности в UI компонентах. В своей “Чистой архитектуре” Р. Мартин пишет, что принцип единственной ответственности (SRP) является следствием закона Конвея и определяет, что лучшей является такая структура программной системы, при котором каждый модуль может быть изменен только вследствие удовлетворения интересов одного единственного актора. На мой взгляд, при разработке библиотеки UI компонентов удобно использовать схожий принцип, который можно сформулировать следующим образом: каждая логическая зона UI может менять свое состояние вследствие изменения конфигурации одного и только одного компонента в коде. Под “логической зоной” я пониманию небольшой кусочек UI, который несет полезную нагрузку для пользователя и может находится в разных состояниях. Разберем на примере текстового инпута. В нем я выделяю следующие логические зоны: поле ввода (возможные состояния - пустое, непустое, задизабленное, с ошибкой), крестик возле инпута (возможные состояния - присутствует, отсутствует), иконка возле поля ввода, подпись под полем ввода. Библиотеки UI компонентов часто разрабатывают таким образом, что в них есть “самые базовые компоненты” (например, Input), и компоненты, которые построены на основе этих “самых базовых компонентов” (ErrorInput, LabelInput, IconInput etc) по принципу “матрешки”. Таким образом, нам нужно следить, чтобы в этой иерархии изменять состояние каждой логической зоны мог только компонент! Например, возможность рендера иконки рядом с полем ввода должен иметь только один компонент - или Input, или IconInput, и тд. Рассмотрим следующий пример реализации Input и ErrorInput на React:
При таком подходе возможна ситуация, когда в ErrorInput будут одновременно переданы пропсы
Привет, на связи @devmargooo и сегодня я хотела бы рассказать свои мысли насчет разделения ответственности в UI компонентах. В своей “Чистой архитектуре” Р. Мартин пишет, что принцип единственной ответственности (SRP) является следствием закона Конвея и определяет, что лучшей является такая структура программной системы, при котором каждый модуль может быть изменен только вследствие удовлетворения интересов одного единственного актора. На мой взгляд, при разработке библиотеки UI компонентов удобно использовать схожий принцип, который можно сформулировать следующим образом: каждая логическая зона UI может менять свое состояние вследствие изменения конфигурации одного и только одного компонента в коде. Под “логической зоной” я пониманию небольшой кусочек UI, который несет полезную нагрузку для пользователя и может находится в разных состояниях. Разберем на примере текстового инпута. В нем я выделяю следующие логические зоны: поле ввода (возможные состояния - пустое, непустое, задизабленное, с ошибкой), крестик возле инпута (возможные состояния - присутствует, отсутствует), иконка возле поля ввода, подпись под полем ввода. Библиотеки UI компонентов часто разрабатывают таким образом, что в них есть “самые базовые компоненты” (например, Input), и компоненты, которые построены на основе этих “самых базовых компонентов” (ErrorInput, LabelInput, IconInput etc) по принципу “матрешки”. Таким образом, нам нужно следить, чтобы в этой иерархии изменять состояние каждой логической зоны мог только компонент! Например, возможность рендера иконки рядом с полем ввода должен иметь только один компонент - или Input, или IconInput, и тд. Рассмотрим следующий пример реализации Input и ErrorInput на React:
interface InputProps {
value: string;
setValue: (newValue: string) => void;
icon?:string;
}
const Input = ({value, setValue, icon}:InputProps) => (
<div className="input">
{icon && <div className="icon">{icon}</div>}
<input type="text" value={value} onChange={(e) => setValue(e.target.value)}/>
</div>
)
interface ErrorInputProps extends InputProps {
is_error?: boolean;
}
const ErrorInput = (props:ErrorInputProps) => (
<div className="error_input">
{props.is_error && <div className="error_icon">X</div>}
<Input {...props}/>
</div>
)
При таком подходе возможна ситуация, когда в ErrorInput будут одновременно переданы пропсы
is_error
и icon
и в одной и той же логической зоне иконки будет отрендерено сразу две иконки, одна поверх другой. Следовательно,важно следить за тем, чтобы логическую зону иконки мог изменять только один компонент - в нашем случае это компонент Input. В своей практике я видела достаточно много багов, попавших на продакшн вследствие нарушения этого принципа.🤡1
Forwarded from S0ER
Как решать литкод
Всем привет, на связи снова @devmargooo и сегодня мы поговорим с вами о задачках с литкода. В то время, когда многие говорят о том, стоит ли вообще программисту тратить свое ценное время на решение задачек, преступно мало, на мой скромный взгляд, говорят о том, а как же их все-таки решить, эти задачки? В мануалах с ютуба все просто: блоггер читает условие и дальше решение зреет в его голове само собой, но на практике у многих людей почему-то так не происходит, сколько бы они не сидели перед ноутбуком и не вглядывались в свеженаписанный function declaration. Итак, мой способ - это идти к общему правилу от частного случая, он же метод индукции. Для этого нужно искусственно сократить мощность множества поступающих на вход данных, короче говоря, решить задачу для одного частного случая, причем максимально простого. В вашей функции на вход подаются число? Пускай это будет число 1. Строки? Возьмите строку из одного символа. Двоичные матрицы? Возьмите матрицу из одного элемента, максимально простого. И затем решите задачу для этого элемента. Как правило, такое решение не составляет труда, а написанный код не похож на свой финальный вариант. Далее возьмите еще один частный случай и решите задачу для него. Подумайте, можно ли объединить первые два случая в общее правило? Решите задачу для еще одного-двух случаев, и в этом момент вы уже начнете замечать закономерности, которые приведут вас к общему правилу. Дальше берите на вход все новые и новые виды входных данных, для которых написанное правило не работает, и решайте задачу для них, до тех пор, пока для всех возможных видов данных ваша задача не будет решена.
Всем привет, на связи снова @devmargooo и сегодня мы поговорим с вами о задачках с литкода. В то время, когда многие говорят о том, стоит ли вообще программисту тратить свое ценное время на решение задачек, преступно мало, на мой скромный взгляд, говорят о том, а как же их все-таки решить, эти задачки? В мануалах с ютуба все просто: блоггер читает условие и дальше решение зреет в его голове само собой, но на практике у многих людей почему-то так не происходит, сколько бы они не сидели перед ноутбуком и не вглядывались в свеженаписанный function declaration. Итак, мой способ - это идти к общему правилу от частного случая, он же метод индукции. Для этого нужно искусственно сократить мощность множества поступающих на вход данных, короче говоря, решить задачу для одного частного случая, причем максимально простого. В вашей функции на вход подаются число? Пускай это будет число 1. Строки? Возьмите строку из одного символа. Двоичные матрицы? Возьмите матрицу из одного элемента, максимально простого. И затем решите задачу для этого элемента. Как правило, такое решение не составляет труда, а написанный код не похож на свой финальный вариант. Далее возьмите еще один частный случай и решите задачу для него. Подумайте, можно ли объединить первые два случая в общее правило? Решите задачу для еще одного-двух случаев, и в этом момент вы уже начнете замечать закономерности, которые приведут вас к общему правилу. Дальше берите на вход все новые и новые виды входных данных, для которых написанное правило не работает, и решайте задачу для них, до тех пор, пока для всех возможных видов данных ваша задача не будет решена.
🔥5🤡1
Forwarded from S0ER
Брендированные типы в typescript
Привет, с вами снова @devmargooo и сегодня мы с вами поговорим о типизации в приложении на typescript. Структурная типизация в typescript, в отличие от номинативной, определяет совместимость типов, основываясь не на названии типа, а на его наборе полей. В этом структурная типизация похожа на утиную: если это выглядит как утка, плавает как утка и крякает как утка, то, вероятно, это утка. К сожалению, это может приводить к проблемам. Следующий код не приведет к ошибке компиляции, несмотря на то, что тип
Тип
Номинативные типы работают по-другому - они совместимы только при явном использовании. К сожалению, встроенной поддержки таких типов в typescript нет, но есть хак, который называют брендированием. Его суть заключается в том, что мы добавляем к типу уникальное свойство:
Теперь тип
Чтобы код заработал, нам придется явно указывать, что переменная имеет тип
Или добавить проверку в наш код, которая также будет выводить нужный нам тип:
Для удобства создания брендированных типов можно воспользоваться дежнериком:
Пример использования:
Привет, с вами снова @devmargooo и сегодня мы с вами поговорим о типизации в приложении на typescript. Структурная типизация в typescript, в отличие от номинативной, определяет совместимость типов, основываясь не на названии типа, а на его наборе полей. В этом структурная типизация похожа на утиную: если это выглядит как утка, плавает как утка и крякает как утка, то, вероятно, это утка. К сожалению, это может приводить к проблемам. Следующий код не приведет к ошибке компиляции, несмотря на то, что тип
some_string
указан как string
, а не Email
:type Email = string;
function auth(login:Email) {}
const some_string:string = "some_string";
auth(some_string); // ok
Тип
string
структурно идентичен типу Email
, поэтому ошибки нет. Номинативные типы работают по-другому - они совместимы только при явном использовании. К сожалению, встроенной поддержки таких типов в typescript нет, но есть хак, который называют брендированием. Его суть заключается в том, что мы добавляем к типу уникальное свойство:
type Email = string & { _: 'Email' };
Теперь тип
Email
будет структурно не совместим с типом string
. Мы получим ошибку компиляции:type Email = string & { _: 'Email' };
function auth(login:Email) {}
const some_string:string = "some_string";
auth(some_string); // Argument of type 'string' is not assignable to parameter of type 'Email'.
Чтобы код заработал, нам придется явно указывать, что переменная имеет тип
Email
:const some_string = "some_string" as Email;
Или добавить проверку в наш код, которая также будет выводить нужный нам тип:
function isEmail(value:string): value is Email {
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
return emailRegex.test(value);
}
Для удобства создания брендированных типов можно воспользоваться дежнериком:
type Brand<B extends string, T> = T & { readonly _: B }
Пример использования:
type Email = Brand<'Email', string>;
👍3🤡1
Forwarded from S0ER
Решение проблемы избыточных состояний через конечные автоматы
Часто замечаю в коде у фронтенд-разработчиков такой паттерн, как выражение одного логического состояния через несколько состояний в коде. Рассмотрим, например, такой код на React, который описывает состояние некоторой формы:
Здесь разработчик создает целых три разных независимых состояний в коде (состояние ошибки, состояние загрузки, состояние успеха), но логически весь этот код отвечает за состояние формы - то есть за одно и то же состояние. Это одна форма, которая может либо находиться в одном из четырех состояний:
1. в состоянии загрузки
2. в состоянии ошибки
3. в состоянии успеха
4. в состоянии готовности к редактированию.
Несложно посчитать, что код выше сгенерирует нам целых восемь различных состояний вместо четырех необходимых. Помимо запутанности и сложночитаемости, такой код плох тем, что мы генерируем недостижимые состояния, которые непонятно, как обрабатывать. Например, что делать, если у нас одновременно есть ошибка и переменная isSuccessful равна true? Скорее всего, программист выберет какое-то одно состояние как приоритетное, но так или иначе, такой код будет порождать запутанность и баги.
Выход из этой ситуации - это использование конечных автоматов. Конечный автомат - это математическая модель, описывающая конечный набор возможных состояний и определяющая, что автомат может находится только в одном из этих состояний в конкретный момент времени. Также автомат может переходить из одного состояния в другое. В коде на React конечный автомат можно довольно создать, используя редюсер, а возможные состояния удобно описываются через тип-сумму:
Созданные formReducer и initialState мы можем использовать в нашем компоненте через useReducer. Таким образом, мы получили удобное декларативное описание возможных состояний нашей системы, а также совокупность переходов из одного состояния в другое.
Часто замечаю в коде у фронтенд-разработчиков такой паттерн, как выражение одного логического состояния через несколько состояний в коде. Рассмотрим, например, такой код на React, который описывает состояние некоторой формы:
const [error, setError] = useState<string | undefined>(); // в форме есть ошибки
const [loading, setLoading] = useState<boolean>(false); // форма загружается на сервер
const [isSuccessful, setIsSuccessful] = useState<boolean>(false); // форма успешно отправлена
Здесь разработчик создает целых три разных независимых состояний в коде (состояние ошибки, состояние загрузки, состояние успеха), но логически весь этот код отвечает за состояние формы - то есть за одно и то же состояние. Это одна форма, которая может либо находиться в одном из четырех состояний:
1. в состоянии загрузки
2. в состоянии ошибки
3. в состоянии успеха
4. в состоянии готовности к редактированию.
Несложно посчитать, что код выше сгенерирует нам целых восемь различных состояний вместо четырех необходимых. Помимо запутанности и сложночитаемости, такой код плох тем, что мы генерируем недостижимые состояния, которые непонятно, как обрабатывать. Например, что делать, если у нас одновременно есть ошибка и переменная isSuccessful равна true? Скорее всего, программист выберет какое-то одно состояние как приоритетное, но так или иначе, такой код будет порождать запутанность и баги.
Выход из этой ситуации - это использование конечных автоматов. Конечный автомат - это математическая модель, описывающая конечный набор возможных состояний и определяющая, что автомат может находится только в одном из этих состояний в конкретный момент времени. Также автомат может переходить из одного состояния в другое. В коде на React конечный автомат можно довольно создать, используя редюсер, а возможные состояния удобно описываются через тип-сумму:
type FormState = {
state: 'loading';
} | {
state: 'error';
message: string;
} | {
state: 'ready';
} | {
state: 'successful';
}
type FormAction = {
type: 'set_loading'
} | {
type: 'set_error',
payload: {
error_message: string;
}
} | {
type: 'set_ready',
} | {
type: 'set_successful'
}
const initialState: FormState = { state: 'ready' };
const formReducer = (state: FormState, action: FormAction):FormState => {
// ...
}
Созданные formReducer и initialState мы можем использовать в нашем компоненте через useReducer. Таким образом, мы получили удобное декларативное описание возможных состояний нашей системы, а также совокупность переходов из одного состояния в другое.
👍4😭2🤡1
Последний пост в этом канале был несколько месяцев назад, и я поняла, что хочу оживить его. За это время я успела сменить команду и получить много разного интересного опыта, которым буду делиться с вами 🥰
Сегодня хочу коснуться такой темы, как стейт менеджеры. Я с огромным удовольствием посмотрела доклад Дмитрия Бабина “Вам не нужен state менеджер “. Дмитрий сделал действительно классный анализ существующих на данный момент стейт менеджеров (упустив, однако, effector и mobx), а также сравнил их с хранением состояния средствами react. Вставлю свои пять копеек.
Дмитрий подчеркивает такую проблему стейт менеджеров, как отсутствие экосистемы (на reatom нет библиотеки работы с формой и тд), объясняя это тем, что если мы заносим в проект стейт менеджер, то мы хотим писать на нем всю бизнес логику. Я всегда относилась к стейт менеджерам иначе - в первую очередь я использовала их для хранения данных, используемых глобально (как минимум в нескольких местах приложения), а не как место для написания бизнес логики. Мои требования к стейт менеджеру следующие:
- Стейт является структурой вида “ключ-значение”.
- Содержит геттер данных по ключу.
- Содержит сеттер данных, причем для каждого поля может быть только один сеттер. Этому требованию очень удобно удовлетворяет Redux: в нем принято писать один action creator, который возвращает action, и диспатчить этот action creator из разных мест приложения; но не удовлетворяет, например, effector, потому что он допускает установку данных как в push дизайне (вызов ивента), так и в pull дизайне (подписка стора на эффект). Почему это так важно, опишу позже.
- Удобные девтулзы.
Бизнес логику я распределяла и хранила в: 1. компонентах реакт (например, вызов запроса, если он вызывается только в одном месте), 2. в ts классах (отлично подходит для кода, не требующего механизмов реактивности), 3. в redux-thunk (в небольших приложениях) или 4. в эпиках rxjs (в больших приложениях). Таким образом, я изначально проектировала свой код так, чтобы стейт менеджеру отводилась роль хранилища, поэтому с проблемой, о которой говорит Дима, я за свой профессиональный опыт так и не столкнулась.
Для чего я вообще использую стейт менеджеры? Главная проблема, которую они для меня решают, возникает вовсе не в процессе написания кода, а в процессе поддержки и эксплуатации. Хранение глобальных данных во время написания кода - это вообще не проблема. Я могу легко написать код, который хранит данные где угодно - в реакт хуках, в контексте, да хоть в объекте window. Однако потом наше приложение постепенно обрастает пользователями и фичами, и рано или поздно мы неизбежно сталкиваемся с багом: в наших глобальных данных почему-то лежит не то, что мы ожидаем. Ждем foo, а лежит bar. И дальше наша - понять, почему так получилось, и устранить проблему. Для этого, во-первых, надо понять, какие данные записаны неверно. И вот тут-то пригождаются топовые девтулзы редакса: я просто открываю девтулзы и смотрю текущий слепок данных, в котором достаточно легко нахожу неверные данные. Дальше надо понять, откуда записались неверные данные. Для этого я ставлю в соответствующем action creator брейкпойнт дебаггера и в два счета нахожу в колстеке виновника.
Таким образом, два последних пункта, про которые я пишу - удобные девтулзы и один сеттер данных, в который можно поставить дебаггер - для меня принципиальны. Поэтому я уже много лет остаюсь верной редаксу: мне не нужны суперфичи в стейт менеджере, мне нужны удобные девтулзы для поддержки и дебага приложения. Ни один другой стейт менеджер, ровно как и нативные фичи реакта (контекст, хуки) такой удобный дебаг для меня не предоставляют.
Сегодня хочу коснуться такой темы, как стейт менеджеры. Я с огромным удовольствием посмотрела доклад Дмитрия Бабина “Вам не нужен state менеджер “. Дмитрий сделал действительно классный анализ существующих на данный момент стейт менеджеров (упустив, однако, effector и mobx), а также сравнил их с хранением состояния средствами react. Вставлю свои пять копеек.
Дмитрий подчеркивает такую проблему стейт менеджеров, как отсутствие экосистемы (на reatom нет библиотеки работы с формой и тд), объясняя это тем, что если мы заносим в проект стейт менеджер, то мы хотим писать на нем всю бизнес логику. Я всегда относилась к стейт менеджерам иначе - в первую очередь я использовала их для хранения данных, используемых глобально (как минимум в нескольких местах приложения), а не как место для написания бизнес логики. Мои требования к стейт менеджеру следующие:
- Стейт является структурой вида “ключ-значение”.
- Содержит геттер данных по ключу.
- Содержит сеттер данных, причем для каждого поля может быть только один сеттер. Этому требованию очень удобно удовлетворяет Redux: в нем принято писать один action creator, который возвращает action, и диспатчить этот action creator из разных мест приложения; но не удовлетворяет, например, effector, потому что он допускает установку данных как в push дизайне (вызов ивента), так и в pull дизайне (подписка стора на эффект). Почему это так важно, опишу позже.
- Удобные девтулзы.
Бизнес логику я распределяла и хранила в: 1. компонентах реакт (например, вызов запроса, если он вызывается только в одном месте), 2. в ts классах (отлично подходит для кода, не требующего механизмов реактивности), 3. в redux-thunk (в небольших приложениях) или 4. в эпиках rxjs (в больших приложениях). Таким образом, я изначально проектировала свой код так, чтобы стейт менеджеру отводилась роль хранилища, поэтому с проблемой, о которой говорит Дима, я за свой профессиональный опыт так и не столкнулась.
Для чего я вообще использую стейт менеджеры? Главная проблема, которую они для меня решают, возникает вовсе не в процессе написания кода, а в процессе поддержки и эксплуатации. Хранение глобальных данных во время написания кода - это вообще не проблема. Я могу легко написать код, который хранит данные где угодно - в реакт хуках, в контексте, да хоть в объекте window. Однако потом наше приложение постепенно обрастает пользователями и фичами, и рано или поздно мы неизбежно сталкиваемся с багом: в наших глобальных данных почему-то лежит не то, что мы ожидаем. Ждем foo, а лежит bar. И дальше наша - понять, почему так получилось, и устранить проблему. Для этого, во-первых, надо понять, какие данные записаны неверно. И вот тут-то пригождаются топовые девтулзы редакса: я просто открываю девтулзы и смотрю текущий слепок данных, в котором достаточно легко нахожу неверные данные. Дальше надо понять, откуда записались неверные данные. Для этого я ставлю в соответствующем action creator брейкпойнт дебаггера и в два счета нахожу в колстеке виновника.
Таким образом, два последних пункта, про которые я пишу - удобные девтулзы и один сеттер данных, в который можно поставить дебаггер - для меня принципиальны. Поэтому я уже много лет остаюсь верной редаксу: мне не нужны суперфичи в стейт менеджере, мне нужны удобные девтулзы для поддержки и дебага приложения. Ни один другой стейт менеджер, ровно как и нативные фичи реакта (контекст, хуки) такой удобный дебаг для меня не предоставляют.
YouTube
🎙️ Дмитрий Бабин - Вам не нужен state менеджер (react, redux, zustand, reatom, state management)
А что такое state менеджер, как писать бизнес логику в react, можно ли писать логику на react без библиотек, эти и многие другие вопросы мы с вами поднимем в рамках этого доклада. Попробуем использовать разные библиотеки и сравнить их по многим критериям…
🔥7👍2👎2🥰2🤡1
Небольшой лайфхак.
Допустим, у вас есть проект и есть библиотека компонентов, которую вы используете в проекте. Вы делаете новый компонент в библиотеке. Для того, чтобы проверить, как он интегрируется с проектом, не обязательно релизить новую версию библиотеки - достаточно просто сбилдить библиотеку и подменить сборку библиотеки в 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