cherkashin.dev
2.11K subscribers
251 photos
15 videos
277 links
Александр Черкашин. Бойскаут, Борец с перфекционизмом.

Для связи 👉 @cherkalexander

Фулстек разработчик в decisions.com. Работаю со стеком TypeScript, React, C#

Пишу о программировании и не только.


Блог: https://cherkashin.dev
Download Telegram
Пару месяцев назад я упоминал codeium — бесплатную альтернативу копайлоту. На новогодних праздниках наконец-то попробовал его на своём пет-проекте, и довольно часто он действительно ускоряет разработку. На скриншотах можно увидеть как codeium:

- Выводит значение enum’а
- Помогает писать тернарники
- Генерирует код по запросу в чате
- Может сгенерировать JSDoc или объяснить код

В текущих реалиях нужно включать VPN, чтобы работать с ChatGPT из России, здесь же есть встроенный чат, который работает без VPN 👍.

#ai
👍83
🗓 Cron теперь Notion Calendar

Некоторое время назад Notion купил Cron, и вот недавно состоялся релиз, теперь Cron - это Notion календарь, в котором доступна интеграция, как с гугл календарём, так и с базами в Notion.

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

https://calendar.notion.so

#notion
❤‍🔥3
🧹 Тестирование — подчищаем за собой

Так исторически сложилось, что у нас на проекте нет юнит тестов, только интеграционные и e2e.

Иногда в тестах приходится подчищать за собой — удалять созданные во время выполнения теста объекты в базе, чтобы не влиять на результат других тестов. Это конечно, лишь ухудшает читабельность кода.

Мы прошли некоторую эволюцию подходов для создания и удаления объектов:

1. Мы использовали try/finally , где все созданные объекты удаляются внутри блока finally. Выглядит сомнительно, когда нужно городить подобную конструкцию во многих тестах.
2. Перешли к использованию функций с колбэками. Утилитная функция создаёт и удаляет объект, а мы передаём лишь колбэк, в котором описываем логику теста и нужные нам проверки.
3. Внедрили IDisposable классы, которые мы называем Creator’ами. Они делают то же самое, что и функции с колбэками, но не добавляют ненужную вложенность, что улучшает читаемость кода. Они чем-то напоминают PageObjectModel в e2e тестах.

Использование паттерна с классами IDisposable также подходит для активации определенной настройки только в рамках одного теста и отключения её по завершении теста.

Такой подход не ограничивается только лишь C# — в TypeScript 5.2. уже появилась поддержка using и, возможно, скоро она появится и в JavaScript.

#csharp #javascript #typescript #tests
👍5
​​Напоминания в Notion

Сегодня немного о том, как я облажался, но не сильно. Обычно я оплачиваю подписку иви сразу за год — так дешевле, всего 2000р (≈170 руб / месяц). Но как только подписка заканчивается — списывается оплата за 1 месяц — 399р, что гораздо больше чем 170р.

Что можно сделать, чтобы не забыть оплатить подписку (отключить авто продление!)?

Если вы, как и я, ведёте свои задачи и проекты в Notion, то у вас скорее всего есть таблица, где отображаются задачи, которые вы должны выполнить сегодня. В таком случае вы можете:

1. Создать задачу в Notion
2. Указать дату выполнения, немного раньше завершения подписки
3. В указанную дату задача появится в вашем списке на сегодня

Например, моя подписка заканчивается 8 января 2025 года, поэтому я поставлю дату 27 декабря 2024 года, чтобы позаботиться об это заранее.

Я уже описывал этот способ в статье Система личного планирования в Notion. Эпизод 2 — Управление проектами.

#notion
👍4
​​Прошлой весной, я наконец-то зарегистрировался на GetMentor, и теперь время от времени мне поступают различные вопросы. Некоторые из них решил публиковать здесь на канале.

В
опрос: если для параметра указать тип React.DragEvent<HTMLDivElement> ,то в коде e.target.style.background = 'white’ TypeScript ругается, что в поле target отсутствует свойство style, почему так?

Ответ:

Тут всё дело в том target — элемент, на котором произошло событие (оно могло всплыть к текущему элементу от дочернего). Из-за этого заранее тип target’а не известен, поэтому его нужно привести к нужному типу. Например, вот так:


(e.target as HTMLElement).style.background = 'white';


Вместо target можно использовать поле currentTarget, тип этого поля всегда известен, потому что currentTarget всегда ссылается на текущий элемент, к которому прикреплён обработчик событий. В этом случае можно избежать приведения типа.


e.currentTarget.style.background = 'white';


Хорошее демо о `target` и `currentTarget` есть в доке.

Ещё по теме

- Объект события Event
- Событийная модель

#question #frontend
👍11
Media is too big
VIEW IN TELEGRAM
🍎 Ещё раз об интеграции Notion и Apple Shortcuts

Пару лет назад я рассказывал, как можно использовать Apple Shortcuts, чтобы настроить быстрое добавление записей в инбокс. А в прошлом году поделился шаблоном, где для использования достаточно вставить токен notion и идентификатор базы. Но вчера я заметил, что теперь даже этого делать не нужно.

Наконец-то, Notion добавил готовые экшины для добавления записей в Inbox, всё настраивается за минуту. Жаль, что новый способ работает только на телефоне, приложение Notion для Mac не поддерживает эти действия.

#notion #automation
👍5🔥1
Явное управление ресурсами в TypeScript — using

Недавно,
когда я рассказывал, как мы пишем тесты, я уже упоминал, что в TypeScript’е появилось новое ключевое слово using. Оно позволяет нам сделать код чище и более линейным, избавившись от try/finally.

Но мы можем использовать using не только, когда открываем файл или подключение к базе данных, иначе его использование ограничилось бы исключительно сервером.

Мне нравится рассматривать using, как Undo/Redo только наоборот, сперва мы выполняем какое-то действие, а в конце отменяем его:
- создали объект, удалили
- показали спиннер и скрыли, когда получили данные

Причем отмена удобно происходит в самом конце функции, даже если мы используем async/await.

Вот простой пример, как можно использовать using, чтобы показывать/скрывать спиннер в React коде.



// обычный код на React
useEffect(() => {
(async () => {
try {
setIsLoading(true);
await Promise.resolve().then(() => console.log("promise.resolve"));
} finally {
setIsLoading(false);
}
})()
}, [])




// такой же код, с использованием using
useEffect(() => {
(async () => {
using manager = new LoadingManager(setIsLoading);
await Promise.resolve().then(() => console.log("promise.resolve"));
})();
}, []);

/**
* Класс, который управляет состоянием спиннера
*/
class LoadingManager {
constructor(private setIsLoading: (value: boolean) => any) {
this.setIsLoading(true);
console.log("constructor");
}

[Symbol.dispose]() {
this.setIsLoading(false);
console.log("disposer")
}
}

// В консоли будет выведено в следующем порядке
// constructor
// promise.resolve
// disposer


Код можно открыть в песочнице.

К сожалению, нельзя опустить переменную manager, но это лучше, чем лепить везде try / finally.

Ещё по теме:
- using Declarations and Explicit Resource Management
- Явное управление ресурсами: пробуем новую фичу JavaScript и TypeScript

#typescript #frontend
👍9
Сегодня увидел, что Хабр советует прочитать мою старую статью с советами о выгорании, поэтому я решил напомнить о ней. Как раз подходит, чтобы отвлечься от работы, расслабиться и почитать вечером в пятницу.

https://habr.com/ru/post/598517/

#fridayreading #burnout
👍11
🚀 React — Compound Components

Как-то я уже упоминал паттерн Compound Components (Составные компоненты) для React, теперь остановимся на нём немного подробнее.

ℹ️ Compound components — это подход позволяет объединить несколько компонентов в единую сущность, которая неявно имеет общее состояние. Эти компоненты тесно взаимодействуют друг с другом и работают как единое целое, представляя собой полноценный UI компонент.

🔍 Основные характеристики:
- Используется React контекст, чтобы управлять состоянием
- Должен быть главный компонент, в котором хранится состояние и объявляется React контекст
- Все дочерние компоненты используют состояние через React контекст

ℹ️ Он состоит из 2 простых подходов React:
1. Композиция компонентов
2. Паттерн “Провайдер” — использование контекста React

📝 Вначале рассмотрим подходы по отдельности

1️⃣ Что такое композиция?

Вместо вот этого

<Tile count={money} title="Стоимость" icon={<MoneyIcon/>}/>


Мы пишем вот так

<Tile>
<Title>{title}</Title>
<Number>{count}</Number>
<Icon>{icon}</Icon>
</Tile>


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

- В одном месте, показывать карточку без иконки
- В другом, показывать карточку, где цифра то посередине, то слева, то справа, то на луне
- В третьем, нам нужно добавить иконку, чтобы при наведении показывалось описание

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

2️⃣ Паттерн “Провайде
р”

Здесь идёт речь об обычном использовании контекста реакта, чтобы передавать какие-то данные на любую глубину дерева компонентов, минуя дочерние компоненты.

🔄 Если объединить два этих подхода, то сможем реализовать паттерн Compound Components. Как пример, можно использовать компонент табов из библиотеки material-ui.

function MyTabs() {
return (
<TabContext value={value}>
<TabList onChange={handleChange}>
<Tab label="Item One" value="1" />
<Tab label="Item Two" value="2" />
<Tab label="Item Three" value="3" />
</TabList>Ï
<TabPanel value="1">Item One</TabPanel>
<TabPanel value="2">Item Two</TabPanel>
<TabPanel value="3">Item Three</TabPanel>
</TabContext>
);
}


1. TabContext — главный компонент, в котором хранится состояние и объявляется React контекст
2. Tab и TabPanel получают текущее значение активного таба неявно через React контекст. Явно значение не передаётся в каждый компонент.
3. onChange объявлен только на компоненте TabList, компоненты Tab неявно получают его из контекста.

Ещё по теме:

- Александр Дунай (Альфа-Банк) — Улучшаем качество кода React-приложения с помощью Compound Components
- JavaScript Patterns — Provider Patter
- JavaScript Pattern — Compound Pattern

#react #frontend #architecture #patterns
👍10
🔮 Абстракция

Когда говорят про ООП, часто забывают о двух вещах:

- Это не только инкапсуляция, наследование и полиморфизм, но ещё и абстракция
- Инкапсуляция, наследование и полиморфизм не прибиты гвоздями к ООП, особенно инкапсуляция и полиморфизм. Но об этом не сегодня.

Сегодня советую к просмотру видео: Абстракция, уровни абстракции.

ℹ️ Основные моменты:

- Абстракция — отвлечение от несущественных сторон, свойств, связей объекта с целью выделения их существенных, закономерных признаков. Иными словами, мы выделяем существенные свойства для нашей конкретной задачи, и не обращаем на несущественные.
- Абстрация = Интерфейс + Инкапсуляция
- Интерфейс — выделяет существенное
- Инкапсуляция — скрывает несущественное
- Абстрагирование нужно для управления сложностью кода, чтобы всё было надёжно, эффективно, расширяемо и поддерживаемо.

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

- Если нам важно вычислять его площадь и периметр, то мы говорим, что квадрат — это геометрическая фигура (абстрагируемся). Иначе говоря квадрат реализует интерфейс IGeometricShape.
- Если нам важно, чтобы квадрат мог быть сохранён в файл, то мы говорим, что квадрат — сериализуемый, например, в JSON объект, который затем можно записать в файл. Иначе говоря квадрат реализует интерфейс ISerializable.
- Аналогично, если нам важно уметь рисовать квадрат на экране, он должен реализовывать интерфейс IDrawable.
- Ну и где-то у нас есть методы, которые работают с абстракциями IGeometricShape, ISerializable и IDrawable. Таким образом методы абстрагированы от конкретных реализаций, что увеличивает переиспользуемость кода.

Ну и немного от себя, абстракция — фундаментальное понятие.
- Без абстракции не будет полиморфизма
- Без полиморфизма не будет Dependency Injection (Внедрение зависимостей)

#fridayreading #essential #oop
👍9🔥2
Яндекс.Музыка уже давно поменяла логотип, поэтому пришло время обновить его и в расширении для VS Code.

P.S. За иконки спасибо автору Мастерской Программиста 👍
👍9👎1
​​Уровни абстракции

Уровни абстракции — одна из самых важных и одновременно самых сложных концепций, понимание которой ведёт к написанию качественного кода.

Методы и функции — один из самых простых примеров, на основе которых можно рассмотреть концепцию уровней абстракции.

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

Как понять, что метод написан на разных уровнях абстракции

- Когда мы смешиваем уровни абстракции, то функция обрастает большим количеством второстепенных подробностей — деталями с более низкого уровня абстракции
- Если читать код функции, вы найдёте одновременно действия, которые будут отвечать на вопросы “что?” и “как?”:
- “что?” — более высокий уровень абстракции, тут функция описывает, что мы делаем.
- “как?” — тут будет описано, “как” мы что-то делаем, а чтобы понять что именно, нужно будет напрячь извилины и подумать. И если мы заменим это “как” на функцию, имя которой будет отвечать на вопрос “что”, то всё станет на свои места и будет на одном уровне абстракции.

⚠️ Не окрепшим умам главное понять, что метод написанный на “одном уровне абстракции” это то, к чему нужно стремиться, но главное не переусердствовать, ведь не всегда так просто провести грань между уровнями абстракции.

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

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

Пример от Дядюшки Боба найдёте в комментариях, из него должно стать понятней, что имелось ввиду при описании “что?” и “как?”

#architecture #cleancode #abstraction
🔥3👍1
Forwarded from mefody.dev
Подсветка кода на странице при помощи Custom Highlight API

Если вы встраивали показ кода на страницы своих сервисов, то скорее всего приходилось прикручивать и подсветку этого кода, чтобы были красивые цвета у разных наборов токенов, как в любимом IDE. Для этого есть много готовых библиотек, так что сложности особой нет. Но все эти библиотеки сейчас создают большое количество span с набором классов для стилизации.

Брамус показывает, как можно применять современный Custom Highlight API, чтобы не создавать span для стилизации в принципе. Это такая апишка, которая уже работает в Chrome 105 и Safari 17.2. И она позволяет при помощи JavaScript разбивать текстовые узлы на набор параметризированных токенов. Как это делать в JS, лучше смотреть в самой статье. Но зато в CSS всё становится сильно приятнее:


::highlight(important) {
color: red;
font-weight: bold;
}

::highlight(attr) {
color: violet;
}


Имена хайлайтов как раз задаются в JS.

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

https://www.bram.us/2024/02/18/custom-highlight-api-for-syntax-highlighting/
👍3🔥1
Forwarded from Hello, IT’s Mihello
Подборка для изучения CSS в игровой форме:

1. Flexbox groggy
2. Grid garden
3. Flexbox defense
4. Flexbox zombies 🧟‍♀️
5. Knights of the Flexbox Table
6. Flex Box adventure
7. CSS Diner
8. Grid attack

Бонус:
CSS Battle
100 days of CSS
CSS Challenges
5🔥1
☁️ Облако слов

Ради интереса решил построить облако слов на основе комментариев в пул реквестах.

Нашёл пару подходящих библиотек:

- react-tagcloud — нет типов для тайпскрипта, и облако само по себе выглядит не очень красиво
- react-wordcloud — типы есть, облако выглядит неплохо, использовать легко

<ReactWordcloud
size={[1000, 500]}
words={data}
maxWords={350}
options={{ fontSizes: [10, 120] }}
callbacks={{
onWordClick: (e) => {
onClick(e.text);
},
}}
/>


#library #react
👍2🔥1
This media is not supported in your browser
VIEW IN TELEGRAM
🆙 Кнопки в базах данных Notion

Когда-то давно я писал, как автоматически заполнять Completed Date поле в Notion.

С тех пор много воды утекло, и кажется об использовании Github Actions для этих целей можно забыть.

В Notion уже давно есть кнопки, наконец-то они появились и в базах данных.

Ещё пример

#notion #automation
👍2🔥1
Наконец-то попаду на "Я 💛 Фронтенд" в оффлайне. Трансляция тоже будет.

https://events.yandex.ru/events/ya-love-frontend-2024

#conference
🔥7👍3
👨‍💻 Phind

В комментариях к прошлому посту о Codeium мне порекомендовали попробовать Phind.

До расширения для VS Code руки ещё не дошли, а вот онлайн версией пользуюсь достаточно регулярно. Очень удобно учитывая, что он бесплатный, генерирует неплохие ответы и не нужно постоянно включать VPN, если вы находитесь в России.

Вначале не мог запомнить название, но потом понял, что phind — это find через ph и всё стало на свои места.

У Phind есть 2 режима:

1️⃣ Чат — стандартный чат, аналогичный ChatGPT

2️⃣ Поиск — phind сгенерирует ответ и покажет ссылки на использованные источники в интернете.

Также позволяет запустить сгенерированный код в Replit.

#ai
👍10🔥2