Кодовая база – Telegram
Кодовая база
1.26K subscribers
16 photos
1 video
31 links
База во фронтенд разработке.

Написать в личку: https://news.1rj.ru/str/devmargooo
Download Telegram
⚡️ Что такое замыкание и как оно приводит к утечкам памяти

В прошлый раз мы с вами говорили о лексическом окружении и причинах его создания, а сегодня поговорим о замыканиях. Термином “замыкание” в javanoscript обозначает функцию и ее лексическое окружение. Как вы помните, лексическое окружение в javanoscript содержит в себе ссылку на внешнее лексическое окружение - таким образом, все внешние лексические окружения для функции будут доступны ей через цепочку ссылок.

Что происходит с лексическим окружением функции после того, как она завершила свою работу? Довольно часто оно больше не нужно и уничтожается, однако бывает и иначе. Рассмотрим пример:

function makeCounter() {
let count = 0;
const increment = () => count++;
return increment;
}
let counter = makeCounter();
counter();
counter();


Функция makeCounter завершила свою работу, однако лексическое окружение, которое она создала - с идентификатором count в нем - осталось в памяти. Почему так? Потому что лексическое окружение функции makeCounter - внешнее для лексического окружения функции increment, которая в нем создается. Когда мы вернули из makeCounter функцию increment, прицепом к ней мы вернули все ее лексическое окружение. Поскольку на это лексическое окружение ссылается increment (ниже counter - это две переменных указывают на одну область памяти), то лексическое окружение вместе с переменной count надежно зависло в памяти до тех пор, пока counter остается ссылочно доступен.

В данном случае makeCounter у нас “зависло” совсем маленькое лексическое окружение с переменной count - однако бывают и гораздо более серьезные утечки памяти, связанные с замыканиями. Такая ситуация происходит, если “зависшее” лексическое окружение занимает много места в памяти и/или ссылается на другие “тяжелые” лексические окружения. Вот здесь я писала об одной из таких утечек в Promise.race, а в следующий раз поговорим с вами о том, как “зависшее” лексическое окружение приводит к ситуациям, которые мы называем stale props и stale state.

#замыкание #javanoscript
117👍3
Stale props и stale state

📌 Stale state — это ситуация, когда внутри замыкания используется устаревшее значение состояния. Stale props - то же самое, но для пропсов. Рассмотрим на примере, как это происходит.

export const Example = () => {
const [count, setCount] = useState(0);

useEffect(() => {
setTimeout(() => {
console.log(count);
}, 1000);
}, [])

return (
<button
onClick={() => setCount((c) => c + 1)}
>
{count}
</button> // кликнем несколько раз
)
}


Мы имеем React компонент Example, в котором имеется:
1. Состояние counter. 2. Эффект, который единожды сработает после монтирования и который выводит наше состояние в лог. Что будет, если за секунду мы уже успеем кликнуть по кнопке несколько раз и counter изменится? Выведется исходное состояние - то, которое было на момент срабатывания эффекта и установки таймера. Вы можете увидеть это на скриншоте выше. Давайте посмотрим подробнее, как так происходит.

В анонимной функции-колбеке, которую планирует таймер, никакого идентификатора counter не существует. Откуда javanoscript возьмет его при вызове? Он возьмет его из родительского лексического окружения, то есть из лексического окружения функции Example, которая одновременно является реакт компонентом. Клик на кнопке приведет к изменению состояния, а это, в свою очередь, вызовет ререндер - то есть новый вызов функции Example. Каждый новый вызов создаст свой объект лексического окружения. Однако нашей анонимной функции с логом до этого нет дела - она надежно запомнила, из какого лексического окружения ей нужно брать counter: из того объекта лексического окружения, которое было создано на момент вызова useEffect. Таким образом, когда наш таймер сработал и вывелся лог, мы увидели там устаревшее состояние.

#react
🔥72🤡1
🪄Как применять S из SOLID

Про принцип единственной ответственности написаны тонны статей, но как, чёрт возьми, применять его в реальной разработке? Для того, чтобы успешно применить этот и другие принципы, необходимо осознать одну вещь: наш код не существует сам по себе в сферическом вакууме, это модель реального мира. Связи между компонентами/классами/функциями в нашем коде должны быть такими же, как в реальном мире.

Например, вам нужно сделать формы авторизации и регистрации. На макете они выглядят одинаково, и вы задумываетесь: сделать один универсальный компонент или два отдельных. Для того, чтобы ответить на этот вопрос, вспомните, как проходят эти процессы в реальной жизни. Например, в моем фитнес клубе они существенно отличаются: для регистрации в клубе я заполняла договор с паспортными данными, а для ежедневной регистрации в клубе мне достаточно приложить браслет к турникету. Совершенно разные действия, разные цели, разные сценарии. То же самое и в вебе: регистрация и авторизация - это два разных бизнес-процесса. Даже если сегодня их формы выглядят одинаково, эти компоненты живут своей независимой жизнью: например, на форме авторизации в какой-то момент может появиться галочка “мне уже есть 18”, а на форме регистрации - нет. Или поменяются поля, логика валидации, поведение при ошибках.

Другой пример: вы реализуете карточки товаров, и в разных разделах они имеют разные цвета. Использовать один компонент или делать разные? Давайте подумаем, как бы мы действовали бы в реальном мире. Представьте, что вы печатаете ценники на принтере. Шаблон один и тот же - вы просто вставляете бумагу нужного цвета: белую, жёлтую, синюю. Цвет меняется, но структура остаётся прежней.Если вы решите изменить размер ценника, например, сделать его больше - это уже изменение шаблона, которое повлияет на все ценники сразу. Точно так же в вебе: если мы хотим поменять структуру или размер карточек, то, как правило, мы хотим сделать это у всех карточек сразу. Таким образом, карточка - это один компонент с настраиваемым цветом.

#solid #srp
👍22🔥2🤡1
🏎Что такое race conditions в React хуках?

Хуки эффектов, в которых есть запросы с последующей установкой ответа в state могут приводить к race conditions. Race conditions возникает, когда хук выполняется слишком часто, и поскольку очередность ответов от сервера не гарантирована, то более ранние запросы могут завершиться после более поздних и тогда в state будут записаны неверные данные.

Например, вот такой код может привести к проблеме:

useEffect(() => {
fetch(`/api/data?query=${query}`)
.then((res) => res.json())
.then((data) => setData(data));
}, [query]);


Этот эффект будет выполняться при каждом изменении query. Таким образом, при вводе query отправится несколько вопросов, но порядок ответа от сервера и тем самым вызов setState не гарантирован.

Вот здесь я собрала песочницу для демонстрации проблемы.

В этом примере мы видим строку поиска товаров. Я добавила искусственную задержку: чем короче строка поиска, тем дольше выполняется запрос. Попробуйте ввести в поиск слово “dog”. Вы увидите, что сначала отображается один результат (”dog food”), а затем больше и больше результатов.

Почему? Потому что при вводе слова “dog” мы отправляем подряд целых три запроса: запрос с поиском значения “d”, запрос с поиском значения “do” и наконец запрос с поиском значения “dog”. Я реализовала искусственную задержку - чем больше букв в поисковой строке, тем быстрее выполнится запрос. Поэтому ответы нам будут приходить в обратном порядке: сначала ответ для “dog”, потом для “do” и наконец для “d”. Хук setData сработает в порядке возвращения ответов от сервера: сначала установятся значения для “dog”, потом для “do” и наконец для “d”. В этом примере задержка искусственная, но реальный сервер тоже не гарантирует порядок ответов и более ранний запрос может завершится после более позднего. В таком мы установим в state устаревшее состояние.

🪄Как предотвратить race conditions?

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

useEffect(() => {
const controller = new AbortController();

fetch(`/api/data?query=${query}`, { signal: controller.signal })
.then(res => res.json())
.then(data => setData(data))
.catch(err => {
if (err.name !== 'AbortError') {
console.error(err);
}
});

return () => controller.abort(); // отменяем прошлый запрос
}, [query]);

#react
Please open Telegram to view this post
VIEW IN TELEGRAM
21
👊 Битва useReducer vs useState: где хранить состояние компонента?

Вы наверняка встречали советы использовать useReducer вместо useState, когда состояние компонента становится "слишком большим и сложным". Но на самом деле дело не только в размере.

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

Представим форму с таким поведением:
- При отправке показывается лоадер.
- Сервер отвечает либо ошибкой, либо успешными данными.
- Ошибка или данные отображаются на странице.
- Повторная отправка формы сбрасывает старое состояние (ошибку и данные)

Интуитивно многие используют следующий код для хранения состояния:

const [error, setError] = useState(false); 
const [data, setData] = useState("");
const [loading, setLoading] = useState(false);

const reset = () => {
setError("");
setData("");
};


const onSubmit = (e) => {
reset();
setLoading(true);
sendData(value).then((result) => {
if (result.type === "error") {
setError(result.message);
}
if (result.type === "success") {
setData(result.data);
}
setLoading(false);
});
};

Полный код примера можно посмотреть здесь

🌀 Но с таким кодом легко запутаться и привести систему в неконсистентное состояние: одновременно может быть loading: true, заполненное data и ненулевой error.

Вот так можно переписать это при помощи useReducer:

function reducer(state: FullState, action: Action): FullState {
switch (action.type) {
case "SET_LOADING":
return { loading: true, error: "", data: "" };
case "SET_SUCCESS":
return { loading: false, error: "", data: action.payload };
case "SET_ERROR":
return { loading: false, error: action.payload, data: "" };
}
}

Полный код примера смотреть здесь

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

#react
Please open Telegram to view this post
VIEW IN TELEGRAM
123🔥3❤‍🔥1👍1
Про оценку сроков

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

Однако непредвиденные проблемы возникают практически всегда. Внезапно выясняется, что часть системы, куда нужно интегрировать новую фичу, работает с багами, или наше решение не вписывается в существующую архитектуру. Разумеется, все эти моменты становятся известны уже в процессе решения задачи, но никак не на этапе планирования. Мы сталкиваемся со сложным выбором: провалить сроки или овертаймить.

Каждый из нас решает эту проблему по-своему. Один мой бывший коллега всякий раз очень долго извинялся, когда факапил сроки, и обещал обязательно все сделать сегодня. Но он снова не успевал, и снова извинялся. Другой мой бывший коллега оставался допоздна перед дедлайном, а как-то раз и вовсе заночевал на офисном диване.

В защиту программистов скажу, что проблема оценок существует не только в айти: любой сложный процесс практически невозможно спрогнозировать. Один мой менеджер как-то сказал: представь, что твой врач не может назвать, сколько времени уйдет на лечение, что ты будешь чувствовать? Это был очень плохой пример: как раз в это время я проходила стоматологическое лечение, которое заняло на год больше ожидаемого и оказалось в 2,5 раза дороже изначально планируемой суммы.

Разработка - это сборка конструктора из мелких деталей: никогда не знаешь, подойдёт ли новая деталь к уже собранной части. Это напоминает известную проблему остановки Тьюринга: для любых двух функций F и G мы никогда не можем определить, что их суперпозиция остановится (= заработает как надо). Алан Тьюринг доказал неразрешимость этой проблемы еще 90 лет назад, однако менеджеры по сей день продолжают пытать программистов на очередном дейли вопросом “так, сколько тебе еще делать эту задачу?”.

Однако можно сделать ровно противоположное: не угадывать срок, который уйдет на разработку, а зафиксировать время, которое вы готовы уделить на фичу. Например: “Мы готовы потратить на эту фичу 2–5 дней. Обязательно - чтобы работало вот это. Всё остальное сделаем по возможности”. Тогда вы не будете зависеть от точных оценок, и при любом раскладе сделаете главное.

Первый раз я применила этот способ еще в 2019 году. Я прикинула, что мне нужно около двух недель на задачу. Однако менеджер вернулась ко мне со словами - “бизнес не дал тебе две недели, бизнес дал тебе неделю”. “Хорошо, я могу сшить семь шапок из этой шкурки,” - подумала я. Я сделала каркас фичи за неделю, но не успела добавить несколько удобных штук в свое решение, плюс пропустила некоторые корнер кейсы. Менеджер осталась довольна. А затем попросила доработать решение и учесть корнер кейс. “Хорошо,” - сказала я, - “на это мне нужна еще неделя”. На том и порешили.

Если вы разработчик и от вас требуют конкретные сроки - попробуйте так и сказать: “Я точно успею сделать вот это, а остальное - постараюсь, если не вылезем за дедлайн”. Тогда вы точно сможете рассчитывать на то, что критическая функциональность будет готова в срок, а опциональной можно пренебречь.
23❤‍🔥8👍7
В тему оценки.

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

И ведь мне это нужно как-то оценить 😊
🤯7👍4😨2👌1
Говорила то же самое, когда это еще не было мейнстримом 😊
Брутфорсить собесы - это очень плохая идея.
💯2👍1🤮1
Сейчас я расскажу неприятный, но важный факт 👮

Не ходи на собеседования, если не готов к ним.

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

Поэтому не стоит выходить на рынок:
С сырым резюме (получишь меньше денег).
Без базового знания алгоритмов.
Без понимания предметной области, в которую идёшь.
Без осознания того, что ты хочешь делать на работе.
Без базовых софтов (очень много отлетают на собесе с командой).

Как подготовиться?
Пробные собеседования (моки). Смотреть, как другие плавают по реке - круто, а самому поплавать — совсем другое дело.
Резюме. В нашем сообществе есть отдельный чат с разборами резюме, можно спросить совета и исправить ошибки. Ну и получить ответ сколько денег просить, многие до сих пор не знают настоящие вилки. Или спроси у знакомого из другой компании!

Всё это необходимый минимум. В нынешней ситуации приходить неподготовленным - неуважение к себе и работодателю. Ты не только потратишь время, но и получишь «фриз» на полгода в этой компании. А ведь этот оффер мог бы помочь в переговорах с компанией "мечты" где ты мог бы поторговаться.
Please open Telegram to view this post
VIEW IN TELEGRAM
💯138😁5👎1
✍️ Конструктор сопроводительных писем

Во времена “сломанного найма” многие задаются вопросом, стоят ли сопроводительные письма потраченного на них времени. Я считаю, что сопроводительные полезны, однако занимают много времени. Я придумала способ, как делать сопроводительные быстро и качественно.

1️⃣ Поймите, на чем вы специализируетесь

Многие пишут резюме в духе “работу работал”. Одна из главных проблем нанимающих менеджеров - это программисты, которые пишут код, не приходя в сознание и не имея понятия, что и для чего они делают (потом еще часто выясняется, что они таки сделали не то, что от них требовалось). Если у вас есть опыт работы 2-3 года, то вы наверняка на чем-то специализируетесь. Возможно, вы все это время работали в аутсорсе и умеете быстро делать шаблонные проекты. Или же вы много работали с интерактивными картами. Или у вас хорошо получаются сложные css анимации. Дайте ответ на вопрос, какие задачи вами можно закрыть и чем вы можете быть полезны бизнесу. Этот ответ должен быть подтвержден вашим резюме.

2️⃣ Сформулируйте ваши сильные стороны в виде тезисов

Я использую для этого “Заметки” в макбуке. Эти тезисы станут составными блоками вашего конструктора сопроводительных писем. Допустим, последние три года вы работали в аутсорсе и разрабатывали на React и Next.js. Тогда ваши тезисы могут выглядеть так:

- “У меня есть опыт работы в аутсорсе, я умею закрывать проекты точно в срок”
- “У меня три года опыта коммерческой разработки на React”
- “У меня три года опыта коммерческой разработки на React и Next.js”
- “Я уже занимался разработкой интернет-магазина ShopName - реализовал X, Y, Z”
- “Последние два года я использую FSD”
- “У меня есть опыт работы с Redux и Mobx”
- “Я умею делать анимации на React Motion”
- “Я умею применять паттерны проектирования и принципы SOLID, KISS, DRY”

Обратите внимание, что опыт работы на Reaсt и опыт работы на React+Next.js вынесен в разные тезисы: это связано с тем, что на одни вакансии нужен только React, а на другие - React и Next.js.

3️⃣ Откликайтесь только на релевантные вакансии

Некоторые блоггеры советуют откликаться на все подряд. Я с этим не согласна: в кризис у вас почти нет шансов “вхолодную” пройти на нерелевантную вакансию.

Говорят, что эйчары тратят 30 секунд на чтение одного резюме. Вы можете сделать то же самое, но с вакансиями. Не поленитесь потратить 30 секунд на чтение вакансии и понять, подходит ли вам вакансия по навыкам и опыту. Откликайтесь только на подходящие.

В 99% процентах случаев по тексту вакансии можно хотя бы примерно понять, чего от вас хотят. Даже если вакансия составлена так, словно ее писал бредогенератор, то в ней, как минимум, указана сфера деятельности компании (а если нет, то ее можно погуглить😉) и стек. Если повезет, то в вакансии будет подробный портрет идеального кандидата.

4️⃣ Конструируем сопроводительное из блоков

Соотносим ваши сильные стороны с требованиями в вакансии и простым копипастом получаем релевантное сопроводительное. Например, в вакансии ищут разработчика в интернет-магазин и ожидают навыки Next.js, FSD и базовое понимание архитектурных принципов. Получаем:

“Добрый день! Заинтересовала вакансия frontend разработчика.

У меня три года опыта коммерческой разработки на React и Next.js. Я уже занимался разработкой интернет-магазина ShopName - реализовал X, Y, Z. Последние два года я использую FSD, умею применять паттерны проектирования и принципы SOLID, KISS, DRY.

Готов ответить на любые ваши вопросы”.


На ручной сбор одного такого письма из блоков уходит приблизительно 5-8 секунд. При этом письмо получается минимум на 90% релевантным.

5️⃣ Бонус

Можно загрузить тезисы в ИИ и в тот же чат скидывать описание вакансии: ИИ неплохо пишет сопроводительные по составленным тезисам 😉

#резюме #сопроводительное
Please open Telegram to view this post
VIEW IN TELEGRAM
116🔥6👍5👎1
Как быть программистом (особенно фронтендером) и не сойти с ума 🤯

Разработка, особенно фронтенд разработка - невероятно динамичная область. Не успел выучить старый фреймворк, уже появился новый, а к нему пять библиотек в придачу. Все это учить - сойдешь с ума. Забить - останешься без работы на дистанции пяти лет. Что делать?

Ответ простой: не учите технологии, учите идеи, которые за ними стоят. Например, современные фронтенд фреймворки (React, Vue, Angular) используют идеи реактивной архитектуры и шаблоны MVC, MVVM. Стейт менеджеры используют идеи flux, FSD использует идеи DDD. Поймите ключевые идеи - и вы сможете молниеносно изучать новые фреймворки и библиотеки, достаточно увидеть, какие идеи они реализуют.

Приведу пример из своей жизни: в 2019 году я свитчнулась с Vue на React, выучив основы за несколько часов, сидя в аэропорту. Это возможно за счет того, что они используют одни и те же базовые идеи. Последние две недели я и вовсе пишу код на go. Я прошла короткий бесплатный курс по языку на Хекслет и поняла, что основные идеи я уже видела раньше в других языка, поэтому смена языка не доставила мне особых хлопот.

Для того, чтобы легко переключаться между фреймворками и языками, нужно знать всего несколько вещей:

1️⃣ Конструкции структурного программирования: условия, циклы, подпрограммы.

2️⃣ Структуры данных: числа, строки, булеаны, стеки, очереди, массивы, хеш-таблицы, кортежи, списки, деревья. В большинстве языков программирования они ведут себя схожим образом и имеют схожие методы.

3️⃣ Основы ООП: абстракция, инкапсуляция, наследование, полиморфизм. Эти идеи неявно используются в современных фронтенд фреймворках.

4️⃣ Паттерны проектирования: фабрика, строитель, шаблонный метод, фасад, итератор, стратегия, синглтон, обсервер. Эти идеи используются во многих современных библиотеках.

5️⃣ Архитектурные шаблоны уровня приложения: MV*, реактивные, луковые, гексагональные архитектуры, event sourcing и CQRS.
Please open Telegram to view this post
VIEW IN TELEGRAM
4❤‍🔥32👍2110🔥3👎1👏1
Часто слышу, что задания на собеседованиях не имеют ничего общего с реальной работой. Это не совсем так. Да, в продакшн коде вам наверняка не потребуется проверять, является ли строка палиндромом, но такие задачи проверяют куда более фундаментальные навыки.

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

〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️
Основная цель собеседования - понять, умеет ли человек программировать.
〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️

Этот навык включает в себя набор разных умений:

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


〰️ Например, алгоритмические задачи по типу задач с leetcode отлично показывают:

🔴 Знаете ли вы структуры данных и их методы - без этого не получится никакого программирования
🔴 Умеете ли внимательно читать и, главное, понимать условие задачи
🔴 Способны ли составить план решения
🔴 Можете ли «прокрутить» код в голове и предсказать результат на разных входных данных

〰️ Теоретические вопросы (те самые набившие оскомину “100 вопросов по Javanoscript”) проверяют базовое понимание архитектуры приложений. Представьте, что вам прилетел баг - после установки фильтров в query параметры страница перезагружается.

С чего начать? Вам помогут базовые знания:
🔴 Архитектура веб-приложений (помните вопрос “что происходит, когда пользовать переходит на сайт google.com” ? Это оно самое)
🔴 SPA архитектура
🔴 Методы Javanoscript для работы с адресной строкой (window.history, window.location)

Да, вы можете сказать, что в этом случае вы не взаимодействуете с объектом window напрямую, вы используете react router, но он имеет те же принципы работы, что и нативное апи. Разные технологии часто строятся на одних и тех же идеях, просто используют их по-разному - поэтому важно понимать эти фундаментальные идеи. Подробнее об этом писала здесь.

Поэтому учите базу - она поможет вам в любой ситуации: и пройти собеседование, и в новом поекте быстро разобраться, и свитчнуться на новый фреймворк или даже язык ❤️

#база
Please open Telegram to view this post
VIEW IN TELEGRAM
16👍13🤡6❤‍🔥3
Небольшое объявление для тех, кто планировал прийти ко мне на менторство или консультации - из-за сильной загруженности как минимум до конца октября такой возможности не будет :(
Это не относится к тем, с кем уже работаю или с кем есть договоренности.

Upd. Если вам нужна моя помощь и дело не терпит до конца октября, на данный момент смогу уделить вашему кейсу 10-15 минут и ответить на ваш вопрос в личке. Пишите в личку. Это бесплатно😊
1😭95👍4👎1
Кодовая база pinned «Небольшое объявление для тех, кто планировал прийти ко мне на менторство или консультации - из-за сильной загруженности как минимум до конца октября такой возможности не будет :( Это не относится к тем, с кем уже работаю или с кем есть договоренности. Upd.…»
Прошлый пост вызвал жаркую дискуссию о том, нужны ли алгоритмы.

Для меня знание алгоритмов - как личный автомобиль: без него можно прожить, но с ним гораздо удобнее. Самое главное, что дает их изучение - это умение думать. Казалось бы, зачем в повседневной работе помнить DFS или бинарный поиск? Не лучше ли сразу учиться на реальных задачах?

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

Так получается потому, что реальных задач невероятно много. А вот фундаментальных задач, частными случаями которых являются реальные, на порядки меньше. Понимая фундаментальные задачи, можно с их помощью решить частные случаи. А вот наоборот, увы, не работает (ну а если у вас работает, значит, вы уже шарите в алгоритмах😎).
👍15🔥94🤡2
This media is not supported in your browser
VIEW IN TELEGRAM
Бинарный поиск

Сегодня поговорим о бинарном поиске.

Бинарный поиск нужен для того, чтобы быстро что-то найти. Для того, чтобы можно было легко что-то найти, нужен порядок (прямо как в шкафу). Проще говоря, данные, где вы ищите, должны быть отсортированы по какому-нибудь признаку.

Алгоритм бинарного поиска заключается в том, что мы делим кучу данных на две равные кучки данных поменьше и затем пытаемся понять, какая из двух кучек нам подходит. После того, как мы это поняли, мы продолжаем поиск в нужной кучке. Вот и весь Великий и Ужасный Алгоритм, которым пугают джунов, как бабайкой. С вас три тыщи.

В классическом варианте вы наверняка увидите массив чисел, в котором ищется число x, равное, ну скажем для примера, 17. Мы делим кучку на две части пополам, и смотрим, чему равна середина. Если середина больше 17, то нам нужно искать в левой кучке (там, где числа поменьше). Если середина меньше 17, то наша кучка - правая. Искать таким образом числа в массиве вам, скорее всего, не потребуется никогда, но вот сама идея - “разделяй и властвуй сравнивай” - очень полезная.

В повседневной работе идея делить кучу на две поменьше пригождается в самых разных ситуациях. Например, конструкция if else тоже позволяет поделить данные на две кучки по какому-нибудь признаку. А еще та идея полезна для дебага. Допустим, вы внесли много изменений в код и в какой-то момент все сломалось (прямо как у меня сегодня). Как быстро найти проблемный файл? Очень просто: убираем половину ченжей (например, в stash) и проверяем, как это отразилось на баге. Если баг все еще воспроизводится, то делим эту кучку еще на две. Эту же идею использует для дебага git bisect.

Можно пойти дальше в своих размышлениях и додумать до идеи делить кучу не на две, а на три. Такие задачи иногда дают младшеклассникам на олимпиадах по математике. Мне впервые попалась такая в подготовительных материалах, когда мне было 8 лет, и решение дошло до меня только на следующий день.

Удачных вам разделений и сравнений!
#алгосы
110👍7🥱4🔥3
📌Абстракция

Абстракция - это упрощение объекта до его ключевых характеристик. Благодаря абстракции мы можем пользоваться объектом, не вдаваясь в детали его реализации. Несмотря на кажущуюся сложность этого определения, абстракция нужна, чтобы облегчить нам жизнь. Абстракция заставляет объекты и функции соблюдать контракт (т.е. интерфейс), благодаря чему мы можем пользоваться ими, не разбираясь, как они этот контракт реализуют.

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

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

Чтобы создать хорошую абстракцию, необходимо:
🔘Продумать ее зону ответственности. Не следует навалить на одну абстракцию слишком много, а то она выгорит.
🔘Определить круг ее сообщников, которые могут ей помогать.
🔘Инкапсулировать от посторонних вмешательств, которые могут помешать ее работе.

И да, сходство работает и в обратную сторону: пока программист делает то, что от него ожидается, мало кто интересуется, как именно он это делает 🙂

#ооп
Please open Telegram to view this post
VIEW IN TELEGRAM
10👍7🥱7🔥2
🎯Рекурсия

Если вы понимаете, что такое рекурсия и когда её применять — можете пропускать этот пост 🙂

〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️

Рекурсия во фронтенде встречается чаще, чем кажется. Например:

🔘 вычисление коэффициентов для анимаций;
🔘 обход и рендеринг древовидных структур (комментарии с тредами, дерево директорий и файлов);
🔘 парсинг вложенных данных (например, JSON-схемы);
🔘 написание утилит (например, парсинг токенов Figma для автоматической генерации переменных дизайн системы).

Не всем программистам очевидно, когда именно стоит применять рекурсию. И здесь нам приходит на помощь понимание, что такое абстракция, о котором я писала в предыдущем посте. Абстракция даёт нам контракт, которым мы можем пользоваться, при этом нам не нужно знать ни детали реализации, ни даже быть уверенным в том, что эта реализация уже готова. То есть: при написании любой функции мы можем использовать ее саму, потому что ее контракт гарантирован.

📌 При написании функции подумайте, будет ли вам полезен результат этой же функции, но с другими аргументами? Если да, то в этой задаче можно использовать рекурсию.

〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️

🔘Пример 1. Факториал.

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

const  factorial = (x) => x *  factorial(x - 1)

Затем нужно учесть корнер кейсы. Мы вычитаем 1 из x и очевидно, что лучше не делать это до минус бесконечности. Нужно выбрать какое-то конкретное число, на котором мы остановимся. Логично выбрать число 0, потому что это наименьшее число, для которого определена функция факториала. Получаем финальное решение:

const  factorial = (x) => x ?  x *  factorial(x - 1) : 1



🟣Пример 2. Обход дерево.

Задача: есть дерево, где каждая нода содержит id и массив children. Нужно собрать все id.

Заметим, что задача сильно упрощается, если нам не нужно думать про id дочерних элементов. Предположим, что уже существует функция getChildrenIds, которая возвращает id дочерних элементов. Останется добавить id текущей ноды. Получаем решение:


const getIds(node) => […getChildrenIds(), node.id] 


Теперь реализуем getChildrenIds. Она должна вернуть все id дочерних элементов. Но у нас уже есть функция getIds, которая вернет id элементов поддерева. Если вызвать ее для каждого потомка, то она вернет все id всех поддеревьев. Итого:

const getIds = (node) => {
let result = [node.id];
node.children.forEach((child) => result = result.concat(getIds(child)))
return result;
}


Желаю вам удачного выхода из рекурсивного цикла! 🔄 Еще про рекурсию можно почитать в этом посте.

#алгосы
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8🥱5
Forwarded from fedos dot com
👆 Фредерик П. Брукс. «Мифический человеко-месяц: очерки о разработке программного обеспечения». Эссе «Нет серебряной пули».

👆 Десятилетиями поставщики инструментария и ученые мужи обещают, что создание средств, которые позволят отказаться от программирования, не за горами. Первым и, кажется, самым забавным случаем присвоения этого ярлыка, был язык Fortran. Fortran задумывался как средство, которое даст ученым и инженерам возможность просто набирать формулы и, таким образом, обойтись без помощи программистов.



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

Причина в том, что программирование — принципиально сложный процесс даже при наличии хорошего инструментария. Дело не в инструментах — программистам приходится бороться с несовершенством реального мира; нам нужно досконально продумывать последовательности, зависимости и исключения, иметь дело с конечными пользователями, которые никак не могут ничего решить. Нам всегда придется бороться с плохо определенными интерфейсами с другими программными и аппаратными средствам и всегда принимать во внимание инструкции, бизнес-правила и другие источники сложных проблем, возникающие вне мира программирования.

Нам всегда будут нужны люди, способные заполнить брешь между задачей реального мира, которую нужно решить, и компьютером, предназначенным для решения этой задачи. Эти люди будут называться программистами независимо от того, манипулируют они машинными регистрами на ассемблере или диалоговыми окнами в Microsoft Visual Basic. Пока у нас есть компьютеры, нам будут нужны люди, которые говорят компьютерам, чтó делать, и эта деятельность будет называться программированием.

Когда вы слышите заявления о том, что «новый инструментарий устранит необходимость компьютерного программирования», бегите! Или хотя бы посмейтесь про себя над этим наивным оптимизмом.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7💯31👎1🤔1
Решила проверить, как обстоят дела с поиском работы для фронтендеров на hh. Создала максимально дефолтное резюме максимально дефолтного миддла на React, указала 3 года опыта работы в ноу нейм компания. Сделала 30 откликов (на большее не хватило времени).

Результаты:

▫️Отказов: 10 (один автоматический спустя минуту, в бигтех)
▫️Предложений от hr перейти общаться в телеграмм: 2
▫️Тестовое: 1
▫️Звонок (на hh появились звонки?...): 1

Что лично я считаю неплохим результатом.
Please open Telegram to view this post
VIEW IN TELEGRAM
1🤗14💩8👍61🤡1
🚀 Как делать задачи быстрее

Самый простой способ ускорить работу, если вы фронтенд-разработчик - это использовать жоский typenoscript. То есть не ограничиваться стандартными типами string/number/boolean и объектами из них, а реально ограничить тип только возможными значениями.

Например, email - это не любой string, а только составленный по определенному правилу, содержащий символы @ и .. Пин-код, - это тоже не любой string, а строка ровно из 4 цифр.

📌 Чем жестче ваш typenoscript, тем быстрее вы будете работать.

На первый взгляд это звучит парадоксально: почему скорость работы увеличится, если жесткая типизация добавит работы? А вот почему:

1️⃣ Меньше ручных проверок

Большинство из нас пишет код так: написал, сохранил, перезагрузил браузер, проверил, поправил. Больше всего времени тратится на пересборку приложения, перезагрузку браузера и прохождение юзер флоу. Когда типы заданы строго, достаточно убедиться, что код скомпилировался. Проверить всю работу новой фичи можно один раз в самом конце, перед ревью.
(Это, конечно, работает, когда вы пишете логику, а не верстаете.)

2️⃣ Меньше багов и возвратов из тестирования

Основная задача typenoscript как инструмента - снизить количество ошибок в рантайме, перенеся их в compile-time. Чем жестче ваша типизация, тем меньше багов будет в результате 🔜 меньше доработок и возвратов фичи из тестирования


3️⃣ Типы выполняют роль документации и делают код более читаемым.

Для тех, кто хочет попрактиковаться в написании типов, есть классный репозиторий https://github.com/type-challenges/type-challenges - в нем собраны задачи от самого легкого до продвинутого уровня.
Please open Telegram to view this post
VIEW IN TELEGRAM
118🔥9👍4👎3❤‍🔥2🌚21💯1🤝1