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

Написать в личку: https://news.1rj.ru/str/devmargooo
Download Telegram
Как быть программистом (особенно фронтендером) и не сойти с ума 🤯

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

Ответ простой: не учите технологии, учите идеи, которые за ними стоят. Например, современные фронтенд фреймворки (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
Дискуссия про применимость алгоритмических задач с собеседований в реальной работе получила новый виток. Сегодня в комментариях подкинули вот такую задачу с собеседования:

*️⃣*️⃣*️⃣
Вы хотите набрать строку s, состоящую из строчных латинских букв, в вашем любимом текстовом редакторе Notepad#.
Notepad# поддерживает два типа операций:
дописать любую букву в конец строки;
скопировать непрерывную подстроку уже напечатанной строки и вставить эту подстроку в конец строки.
Можно ли набрать строку s за число операций, меньшее длины строки?
canBeTypedFaster("tbank") => false
canBeTypedFaster("mama") => true

*️⃣*️⃣*️⃣

Задача несложная, мне потребовалось примерно двадцать секунд на подумать и еще пару минут на закодить. Вот что у меня получилось:

function canBeTypedFaster(str) {
const set = new Set();
for (let i = 0; i < str.length - 1; i++) {
const substring = str.substring(i, i + 2);
if (set.has(substring)) {
return true;
}
set.add(substring);
}
return false;
}


Как я рассуждала: для того, чтобы воспользоваться опцией копипаста, нужно, чтобы в целевой строке повторялась хотя бы одна группа из двух символов. Тогда эту группу можно будет скопировать и вставить. Можно и больше, но двух символов хватит. Следовательно, задача сводится к тому, чтобы понять, есть ли в строке повторяющиеся группы из двух элементов. Дальше все просто: я прохожусь по строке и запоминаю все группы из двух подряд идущих символов, а также проверяю, встречалась ли мне такая группа раньше. Если встречалась, то значит, эту группу можно скопировать и для такой строки ответ будет true. В противном случае ответ будет false.

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

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


Именно навык рассуждать логически и проверяют на собеседованиях подобные задачи. Для того, чтобы решать такие задачи, необязательно задротить литкод (хотя это хорошая идея), достаточно научиться рассуждать логически. У меня на литкоде дайбох если штук 10 решенных задач есть, однако на собеседованиях я решаю 90% задач. Литкод - это не цель и не поэма, которую нужно выучить наизусть, это всего лишь тренажер для отработки навыков логического мышления.

#алгоритмы
Please open Telegram to view this post
VIEW IN TELEGRAM
110👍6👎5❤‍🔥3🤮1🍌1
Скормила эту задачу чату гпт. Вот что он мне выдал:
*⃣*⃣*⃣
Думал на протяжении 16s

Короткий ответ: да — ровно тогда, когда в строке s существует фрагмент длины ≥ 2, который в какой-то момент встречается снова так, что его второе вхождение начинается в позиции, когда префикс до этой позиции уже напечатан. Формально: существует i (1 ≤ i ≤ n-1) и L ≥ 2 такие, что i + L ≤ n и s.substring(i, i+L) встречается в s.substring(0, i). В этом случае можно одну или несколько таких копий использовать и получить число операций < n.

Ниже — простая и надёжная реализация на JavaScript:
// Возвращает true, если строку s можно набрать за число операций < s.length
function canBeTypedFaster(s) {
const n = s.length;
if (n <= 1) return false; // невозможно сократить
// для каждой позиции i — попробовать найти любую длину L>=2,
// такую что s[i:i+L] содержится в префиксе s[0:i]
for (let i = 1; i < n; i++) {
// максимальная длина, которую можем попытаться скопировать отсюда
const maxL = n - i;
// интересуют только L >= 2
for (let L = 2; L <= maxL; L++) {
const chunk = s.substring(i, i + L);
if (s.substring(0, i).indexOf(chunk) !== -1) {
return true;
}
}
}
return false;
}

// Примеры
console.log(canBeTypedFaster("tbank")); // false
console.log(canBeTypedFaster("mama")); // true


Сложность приведённого кода в худшем случае O(n³) в naive JS (из-за indexOf внутри двойного цикла), но на строках обычной длины это проходит быстро. Если нужна оптимизация для больших строк — можно применять суффиксный массив/дерево, Z-функцию или KMP/rolling hash, чтобы сократить до O(n²) или O(n).
*⃣*⃣*⃣

По-моему, какая-то лажа. Чат гпт решил искать не только группы из двух элементов, но и более длинные, хотя достаточно групп из двух элементов - они входят в более длинные. Еще и сложность кубическая.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤‍🔥8👎2🖕21🤮1
Друг скинул еще одну задачу с собеседования: https://leetcode.com/problems/isomorphic-strings/. На ее решение у меня ушло около 7 минут. Решение:

var isIsomorphic = function(s, t) {
const dictS = {};
const dictT = {};
for (let i = 0; i < s.length; i++) {
const sChar = s[i];
const tChar = t[i];
if (!check(sChar, tChar, dictS) || !check(tChar, sChar, dictT)) {
return false;
}

}
return true;
};

function check(origin, replacer, map) {
if (map[origin]) {
return map[origin] === replacer
}
map[origin] = replacer;
return true;
}

Меня огорчило, что я не попала в 10% самых быстрых решений (beats 89.81%). Закинула чат гпт и он решил гораздо хуже (beats 32.05%).
Вот так этим вечером внезапно выяснилось, что чат гпт решает алгозадачи так себе - по крайней мере, те две, которые мы разбирали сегодня в канале, он решил хуже меня.

Для меня это еще один повод использовать алгозадачи на собесах 😎
👎23🔥14👍6🤮31🖕1
Мне интересно, дизлайк на предыдущий пост поставил человек, который попал в 10% самых быстрых решений? 🤔
👎21💩6🐳3🦄3🤣1🖕1
🍇 Немного о сортах типизации

Раз уж я заговорила про typenoscript, считаю своим долгом погрузить вас в эту тему.

Как вы знаете, typenoscript - это компилируемый язык со статической типизацией. В статически типизируемых языках в переменную можно присвоить только значение сопоставимого типа:

const x: number = 42; // ок, в number можно присвоить number
const y: number = ‘abc’; // ошибка, в number нельзя присвоить строку


Однако не все знают, что языки программирования имеют разный взгляд на то, какой же тип является “сопоставимым”. Бывают языки с номинативной и структурной типизацией.

Номинативная типизация

Языки с номинативной типизацией используют имя типа для того, чтобы считать, что тип является сопоставимым. Так типизация работает в Java: если мы объявляем значение и указываем тип, то присвоить в это значение мы можем только этот же самый тип либо потомок (логически, потомок тоже является тем же самым типом, просто с некоторыми уточнениями).

class Order { public String id; }

// PriorityOrder технически тоже является Order-ом, просто с дополнительными свойствами
class PriorityOrder extends Order { }

public class Main {
public static void main(String[] args) {
// ок, присваиваем в Order значение типа Order
Order o1 = new Order();
// PriorityOrder тоже можно присвоить в переменную типа Order, так это наследник
Order o2 = new PriorityOrder();
}
}


Если у нас есть другой класс, который совпадает по структуре, но не является наследником, присвоить его нельзя:

class CustomerRequest { public String id; }

public class Main {
public static void main(String[] args) {
// Ошибка: нельзя присвоить в Order значение типа CustomerRequest, они никак не связаны через наследование
Order o3 = new CustomerRequest();
}
}


🚀 Структурная типизация

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

type Order = { id: string };
type CustomerRequest = { id: string };

Function handleOrder(order: Order) {…};

сonst customerRequest: CustomerRequest = { id: ‘abc’ };

// ок, потому что структура двух типов совпадает
handleOrder(customerRequest);

Typenoscript-у не важно, что тип по-другому называется - ему главное, что нужные поля имеются. Это может подкинуть вам такой неприятный сюрприз:

type Phone = string;
type Email = string;

function sendSms(phone: Phone) {...}
const email: Email = 'test@mail.ru';

sendSms(email); // oк, потому что структура одна и та же, оба типа - строки


В typenoscript можно эмулировать номинативную типизацию при помощи костыля хака, о котором я писала здесь. В остальных случаях придется к ней привыкнуть и полюбить ❤️

#typenoscript
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12💩8🤮6👍43👎2😁1🖕1
🐆Как научиться решать алгоритмические задачи, если вы совсем не умеете

Если вы придерживаетесь мнения, что алгоритмические задачи не нужно решать, это пост не для вас — на канале много других интересных постов😊 На этой неделе несколько человек написали мне с этим вопросом в личку, поэтому пишу пост для всех.

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

Нужно начать с самых простых задач из тех, что вы можете решить самостоятельно и без подсказок. Большинство ребят способны решать простые задачи, такие как поиск максимума в массиве или обмен двух переменных значениями. В этом репозитории вы найдете еще простые задачи, с которыми можно поработать. Цель заключается в том, чтобы во время тренировки мысленно визуализировать алгоритм и представлять, как ведут себя разные структуры данных, что с ними можно делать и чего нельзя, какие операции выполняются похожим образом, а какие — совсем разным. Нужно решить много простых задач, после этого можно переходить к более сложным задачам (уровень easy на литкоде).

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

#алгоритмы
Please open Telegram to view this post
VIEW IN TELEGRAM
23🤮8👍7💯5👎3💩3❤‍🔥2🔥2🥰2🖕1
💥 Как React рендерит UI. Часть 1

Если вам когда-либо было сложно разобраться в порядке вызова эффектов в компоненте или вы просто хотите подготовиться к собеседованию, то это серия постов для вас.

📎 Рендеринг UI в React состоит из двух фаз: render и commit.

📌 Render фаза

Во время render фазы React вызывает функции компонентов. Ваши компоненты — это же обычные javanoscript функции, верно? Вот React эти функции и вызывает с переданными аргументами. В результате получается новый VDOM. После этого React React сравнивает старый VDOM с новым (этот процесс называется reconciliation) и определяет, какие изменения нужно внести (какие узлы добавить, какие узлы удалить и т.д.)

📌 Commit фаза

React вносит изменения в реальный DOM при помощи js методов вроде appendChild, removeChild и т.п. Но это не приводит к их немедленному отображению на экране — js однопоточный и этот поток занят выполнением js кода 🙂. После внесения изменения в DOM выполняются layout эффекты (useLayoutEffect). Они уже могут использовать реальный DOM (например, для вычисления размеров элементов) и вносить в него правки. Только после этого браузер отрисовывает новый UI на экране, после чего выполняются эффекты useEffect.

Рассмотрим пример и разберемся по шагам, что здесь происходит:

function App() {
useLayoutEffect(() => console.log('useLayoutEffect'));
useEffect(() => console.log('useEffect'));
console.log('render');
return <div>hello world</div>;
}


В этом примере:

*️⃣Render фаза

1️⃣Вызывается функция App. Вычисляется VDOM и изменения, которые нужно закоммитить в реальный DOM. Мы увидим лог “render”, потому что функция App была вызвана.

*️⃣Commit фаза

2️⃣ React обновляет реальный DOM
3️⃣ Выполняется useLayoutEffect. Мы увидим лог “useLayoutEffect”
4️⃣ Изменения отобразятся на экране, и пользователь увидит Hello world.
5️⃣ Выполнится useEffect, и мы увидим лог “useEffect”

В следующих постах посмотрим, как изменится этот флоу, если эффекты вносят изменения в DOM или состояние.

#react
Please open Telegram to view this post
VIEW IN TELEGRAM
128🔥10🤮6💩3👎2💘2
💥 Как React рендерит UI. Часть 2

В прошлой серии мы поговорили с вами о том, что рендеринг в React состоит из двух фаз — render и commit. В render фазе вычисляются новые VDOM и Fiber tree, в commit фазе сначала обновляется DOM, затем выполняются useLayoutEffect, после чего следует отрисовка и, наконец, выполняются useEffect.
Сегодня мы рассмотрим useLayoutEffect подробнее.

Многие из вас знают, что в useLayoutEffect можно подшаманить UI перед отрисовкой и тогда верстка не будет прыгать. Например, в следующем кейсе пользователь сразу увидит красивый нежно-розовый прямоугольник без скучного серого перед ним:

// index.css

.rect { width: 300px; height: 200px; background: grey; }

// App.tsx

export default function App() {
const rect = useRef<HTMLDivElement | null>(null);
useLayoutEffect(() => {
if (!rect.current) return;
rect.current.style.backgroundColor = "pink";
}, []);

return <div className="rect" ref={rect}></div>;
}


Это происходит за счет того, что useLayoutEffect выполняется перед отрисовкой. Браузер построил DOM с серым прямоугольником, затем выполнил js код с useLayoutEffect, в котором содержится смена цвета. После этого браузер внес изменения в DOM и затем наконец отрисовал интерфейс.

А что произойдет, если мы в useLayoutEffect будем менять состояние? Помним, что обновление состояния происходит асинхронно — новое значение появится только в следующем рендере. Как думаете: в примере ниже пользователь сначала увидит серый прямоугольник или сразу розовый?

function sleep() {
const start = Date.now();
while (Date.now() - start < 2000) {}
}

export default function App() {
const [color, setColor] = useState("gray");

useLayoutEffect(() => {
sleep(); // спим 2 секунды
setColor("pink");
console.log(color); // серый - обновление произойдет перед следующим рендером
}, []);

return (
<div
style={{
width: "300px",
height: "200px",
background: color,
}}
></div>
);
}


Ответ на этот вопрос я напишу позже, а пока вы можете делиться вашими догадками в комментариях :)

#react
🔥1511🤮6👍3👎2💩2
Какой прямоугольник пользователь увидит сначала в задаче выше?
Anonymous Poll
53%
серый
47%
❤️розовый
🔥6🤮65👍3👎3💩3
💥 Как React рендерит UI. Часть 3

Мнения разделились. Правы оказались те, кто выбрал романтичный розовый цвет 💗 (пруф). Но подождите… ведь переменная состояния обновляется только в следующем рендере, верно?

Так и есть. При вызове setState внутри useLayoutEffect React прерывает текущую commit фазу и сразу запускает новую render фазу. Таким образом, после первого рендера пользователь ничего не увидит — до стадии отрисовки React не дошел. А вот после второго увидит розовый прямоугольник 🌸

В следующей серии поговорим о том, что будет, если в дело вступит useEffect💫

#react
Please open Telegram to view this post
VIEW IN TELEGRAM
19👍10🔥7👎4🤯4🤮2🤡1