Ivanchikov ITClub


Channel's geo and language: Belarus, Russian
Category: Technologies


Добро пожаловать в сообщество для людей которым интересен язык программирования JS, но здесь не только об этом.
Связь:
tg - t.me/IlyaIvanchikov
linkedin - www.linkedin.com/in/ilyaivanchikov

Related channels

Channel's geo and language
Belarus, Russian
Statistics
Posts filter


🌍 Привет, мир! 👋

⏳ Минутка полезной информации

❓ А вы знали, что AI может помочь вам писать на английском правильно!

Когда вы общаетесь, к примеру с ChatGPT на английском, можно написать специальное правило, следуя которому модель будет автоматически исправлять ваш запрос, укажет на ошибки и неточности, подробно объяснит, почему это неверно, а затем ответит на ваш вопрос. Для этого необходимо добавить правило в настройки вашей учетной записи.

✏️ Пример правила:
If a query is written in English, ChatGPT must:
1. Automatically correct errors – ChatGPT corrects grammatical, lexical, and stylistic mistakes in the query without changing its meaning.
2. Briefly explains which errors were corrected and why.
3. Respond to the prompt – Provides a response based on the corrected query.

📝 Как корректировка выглядит на практике:

Ответ разбивается на несколько частей:

1️⃣ Ваш исходный вопрос:

"How correct read file async in nodejs?"

2️⃣ Автоматическое исправление от ChatGPT:

Your sentence has some grammatical errors. The corrected version should be:

"How to correctly read a file asynchronously in Node.js?"

3️⃣ Объяснение исправлений:

❌ "How correct read" → "How to correctly read"
"How correct read" is not grammatically correct. The correct structure is "How to correctly read."

❌ "file async" → "file asynchronously"
"async" is often used in code but not in a natural sentence. "Asynchronously" is the correct adverb.

4️⃣ Ответ на исправленный вопрос:

In Node.js, you can read a file asynchronously using the built-in fs module:

const fs = require('fs').promises;

async function readFile() {
try {
const data = await fs.readFile('./file.txt', 'utf-8');
console.log(data);
} catch (error) {
console.error('Error:', error);
}
}

‼️ Используя похожее правило, вы не только получите четкий и правильный ответ, но и улучшите свой английский!

😊 Пользуйтесь на здоровье!

#AI #CODINGTIPS


🌍 Привет мир! 👋🏻

Часто требуется передавать обновления клиентам мгновенно, как только они появляются. Обычно для этого используют подходы вроде Polling или WebSockets, но не все знают о простом и эффективном решении — Server-Sent Events (SSE).

Что такое SSE

Это подход при котором происходит однонаправленная передача данных от сервера к клиенту, через HTTP-соединение.

👍🏻 Преимущества SSE

Автоматическое переподключение: Браузер автоматически восстанавливает соединение с сервером в случае его разрыва, что делает приложение устойчивым и лёгким в поддержке.
Небольшие затраты ресурсов: SSE потребляет меньше ресурсов по сравнению с WebSockets, так как это простой, односторонний протокол.
Кросс-браузерность: Современные браузеры, такие как Chrome, Firefox и Safari, имеют встроенную поддержку SSE.

⚙️ Как работает SSE?

➖ Клиент делает обычный HTTP-запрос к серверу.
➖ Сервер поддерживает это соединение открытым и отправляет данные в формате text/event-stream.
➖ Клиент слушает сервер и обрабатывает поступающие данные.

🛠 Технические детали имплементации

Сервер отвечает с типом контента text/event-stream, а сами данные отправляются в следующем формате:

📌 data: Может содержать несколько строк, каждая заканчивается переводом строки (\n). Каждое сообщение, отправленное с сервера, должно начинаться с data:, за которым следует контент, и заканчиваться двумя переводами строк (\n\n). Это не просто какое-то соглашение — это требование протокола SSE.
📌 event (опционально): тип события.
📌 id (опционально): уникальный идентификатор, используется для того чтобы клиент мог отслеживать и восстанавливать соединения.

✏️ Небольшой пример (Back-end side) (кстати полную версию рабочего приложения можно посмотреть здесь)

app.get('/events', (req, res) => {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');

res.write(`data: Connected to server\n\n`);

let messageId = 0;

const intervalId = setInterval(() => {
messageId += 1;
res.write(`id: ${messageId}\n`);
res.write(`event: time-update\n`);
res.write(`data: ${new Date().toLocaleTimeString()}\n\n`);
}, 1000);

req.on('close', () => {
console.log('Client disconnected');
clearInterval(intervalId);
res.end();
});
});


1️⃣ Открывается SSE endpoint (/events): Сервер устанавливает заголовки для SSE-соединения:
➖ Content-Type: text/event-stream — определяет тип контента.
➖ Cache-Control: no-cache — отключается кеширование.
➖ Connection: keep-alive — указывается, что соединение нужно оставить открытым.

2️⃣ Первоначальное сообщение: Сервер сразу отправляет клиенту простое сообщение о подключении:

Connected to server


3️⃣ Регулярная отправка сообщений: Каждую секунду отправляется новое событие:
➖ Уникальный идентификатор (id) для каждого события.
➖ Тип события — event: time-update.
➖ Данные (data) — текущее серверное время.

4️⃣ Закрытие соединения: Если клиент отключается (req.on('close')), сервер останавливает отправку сообщений, очищая таймер.

В результате: клиент получает регулярные обновления времени без необходимости самостоятельно отправлять запросы серверу.

Вся часть клиента (Front-end side) крутится вокруг EventSource, пример реализации.

‼️ Особенности:

👉🏻 Сервер может предоставлять любое количество SSE-каналов на разных URL-адресах.
👉🏻 Один поток SSE может передавать разные типы событий (уведомления, сообщения, обновления данных и тд.).
👉🏻 Если соединение ⛓️‍💥 обрывается, браузер автоматически отправляет серверу последний полученный идентификатор события (Last-Event-ID). Это позволяет серверу отправить клиенту пропущенные события после переподключения.
👉🏻 Сервер может завершить соединение: вызвав res.end()
👉🏻 Только браузер может восстановить соединение, создав новый объект EventSource.

💬 Делитесь своим мнением в комментариях👇! Если вам понравилась статья, не забудьте поставить лайк! 👍

#ARCHITECTURE


🌍 Привет, мир! 👋

Минутка полезной информации

🚀 Shortcuts, которые я использую каждый день

Работая 👩‍💻 с кодом, я постоянно использую клавиатурные сокращения.
Вот несколько моих любимых поисковых 🔎 шорткатов в VS Code, которые реально ускоряют работу:

1️⃣ Поиск чего-либо в текущем файле:
Ctrl + F, ввожу часть названия – и готово!

2️⃣ Поиск чего-либо во всём проекте:
В таком случае Ctrl + Shift + F спасает – ищу сразу по всему проекту.

3️⃣ Переход к (метод, функция, класс) в текущем файле:
Когда необходимо быстро прыгнуть к определённому методу или классу в файле, Ctrl + Shift + O и ввод части названия. Особенно удобно в больших файлах.

4️⃣ Переход к (метод, функция, класс) во всём проекте:
Проекты бывают весьма и весьма большие, расположение всего не запомнишь, на помощь приходит Ctrl + T, зажимаете клавиши и далее ввод части названия – моментально находится необходимое место.

‼️ Эти шорткаты экономят мне кучу 🕙 времени. Попробуйте, если ещё не используете! А какие горячие клавиши вы используете чаще всего❓ Делитесь в комментариях! 👇

🎈 Пользуйтесь на здоровье!

😊 Желаю вам продуктивного дня! 💪

#CODINGTIPS #IDE


🌍 Привет мир! 👋🏻

На днях узнал о существовании интересной фичи в TypeScript, которая была введена в TypeScript 5.0, const в параметрах типов.

🚀 Мотивация

До TypeScript 5.0 по классике, если передавался массив или объект в качестве аргумента функции, то в результате он становился обобщенным (упрощался до более общего типа).

📝 Например:

function getFirst(arr: T[]): T {
return arr[0];
}

const result = getFirst(["hello", "world"]); // string


‼️ Но иногда для дальнейшего взаимодействия с данными на выходе функции, необходимо сохранить конкретные литеральные значения.

📝 Например:

const result = getFirst(["hello", "world"]); // "hello" | "world"


Ранее для достижения необходимого результата приходилось использовать as const или satisfies.

Как использовать const type parameters

Очень важно понимать, что на вход функции необходимо передавать только точные типы, что это означает?

👎🏻 Плохо

const helloWorld = ["hello", "world"]; // string[]
const result = getFirst(helloWorld);


В данном случае, typescript уже распознал тип как string[], и поэтому даже если используется const type parameters в функкции, то ts не сможет из обобщенного типа string[] сделать вам точный ["hello", "world"]

👍🏻 Хорошо

const result = getFirst(["hello", "world"]); // "hello" | "world"
// или
const helloWorld = ["hello", "world"] as const;
const result = getFirst(helloWorld);


Рабочий пример с использованием const type parameters и сохранением точных типов:

function createConfig<
const T extends Record>(config: T): T {
return config;
}

const serverConfig = createConfig({
dev: { mode: "development", port: 3000 },
prod: { mode: "production", port: 8000 },
});


В данном случае в результате мы получаем тип:

const serverConfig: {
readonly dev: {
readonly mode: "development";
readonly port: 3000;
};
readonly prod: {
readonly mode: "production";
readonly port: 8000;
};
}


Без использования const type

const serverConfig: {
dev: {
mode: string;
port: number;
};
prod: {
mode: string;
port: number;
};
}


🧐 Думаю можно не объяснять, польза очевидна.

Как итог можно избегать использование as const везде, где нужно сохранять точное значение.

Когда полезно использовать

📌 При необходимости улучшить точность, когда работаете с литеральными массивами или объектами, так как TypeScript по умолчанию склонен обобщать (widen) массивы и объекты, приводя их к менее точным (более общим) типам.
📌 При создании гибких, но точных API, конфигурации объектов или маппинга.

💬 Делитесь своим мнением в комментариях👇! Если вам понравилась статья, не забудьте поставить лайк! 👍

#TYPESCRIPT


🌍 Привет мир! 👋🏻

Продолжаем двигаться в сторону понимания AI, уже поговорили про Vector DB, следующее что на слуху когда речь заходит про AI - это Retrieval-Augmented Generation (RAG).

Какую проблему решает RAG

В больших языковых моделях (БЯМ) ответы генерируются на основе предварительно изученных шаблонов и информации на этапе обучения.

✏️ Пример:

Вопрос: На сколько актуальна база у модели ChatGPT 4o ?

Ответ: Моя база знаний обучена на данных до июня 2024 года.

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

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

⁉️ Как работает RAG

1️⃣ Пользователь вводит свой вопрос или промпт.
2️⃣ Запрос уходит в Retriever,
который ищет релевантные документы или части информации, с помощью которых в последующем сформируется полноценный ответ от БЯМ. На выходе из ретривера мы получем context.
3️⃣ Сформированный context и user query передается в БЯМ, за счет контекста мы получаем более точный и детализированный ответ, так как response формируется не только за счет уже имеющихся знаний, но и дополняется (Augmented) конкретными подробностями из извлеченного context.

📝 Типы Retrievers

Retriever – это компонент в RAG, который занимается поиском 🔎 и извлечением 📤 релевантной информации.


📎 Sparse Retriever - поиск по ключевым словам.

➖ Основан на методах сопоставления терминов, таких как TF-IDF или BM25.

Как работает
1. Квери пользователя остаётся в текстовом виде.
2. Поиск идёт по индексированным текстам в базе данных (например, Elasticsearch).
3. Находятся документы 📑 с наибольшим совпадением ключевых слов.

✏️ Пример:

Запрос: "Как работает микроволновка?"

Происходит поиск документов, которые содержат слова "микроволновка", "работает", и возвращает их по степени релевантности.


📎 Dense Retriever - поиск по векторным представлениям.

➖ Использует векторные представления текста.

Как работает
1. Квери пользователя превращается в вектор.
2. Вектор сравнивается с векторами документов в базе данных (например, Chroma, Weaviate...).
3. Возвращаются документы с наибольшей схожестью.

✏️ Пример:

Запрос: "Как работает микроволновка?"

1️⃣ Запрос превращается в вектор (например, [-0.12, 0.58, ...]).
2️⃣ Поиск идёт среди документов, у которых похожие векторные представления.
3️⃣ Находится документ "Инструкция микроволновки...", даже если там нет точного совпадения слов.


📎 Hybrid Retriever - гибридный поиск

➖ Комбинирует Sparse Retriever и Dense Retriever.
➖ Используется для улучшения качества поиска.

🚀 Типы контекста который формирует Retriever?

👉🏻 Структурированный -
организованный набор данных, например JSON.
👉🏻 Неструктурированный - обычный текст из статей, документов, чатов.
👉🏻 Векторный - представляет информацию в виде векторов.

Где применяется RAG

RAG применяют везде, где нужно точное и актуальное извлечение данных + генерация осмысленных ответов (медицина, юриспруденция, финансы и др.) .

👎🏻 Недостатки RAG

1️⃣ Зависимость от качества поиска - если поиск извлекает нерелевантные или устаревшие данные, ответ модели будет неточным, модель может придумывать (галлюцинировать) ответы.
2️⃣ Снижается скорость - RAG требует выполнения поиска + генерации, что делает его медленнее, чем обычные LLM-ответы.
3️⃣ Ограниченный контекст - у LLM есть лимит на длину контекста, поэтому длинные документы могут усекаться или обрабатываться не полностью.

💬 Делитесь своим мнением в комментариях👇! Если вам понравилась статья, не забудьте поставить лайк! 👍

#AI


🌍 Привет, мир! 👋

⏳ Минутка рассуждений

Сегодня становится все больше и больше способов написать код и приложить минимум усилий 💪🏻 для этого. Я ловлю себя на мысли, что тем самым мы оказываем себе медвежью услугу. Да, код пишется кратно быстрее☄️, задачи закрываются, бизнес доволен.

Но, а что происходит с вами⁉️ Копируя решения из какого-либо бота, вы чаще всего даже не до конца понимаете как так получилось, ну ладно, громко сказано. Опытные разработчики читают код и все понимают, и как будто бы все красиво.

А как же пассивная прогрессия вашей экспертизы❓ Вы уже не сидите часами 🕑 читая мануалы или читая полотна из ответов на stack overflow.
И происходит следующее: местами вы как будто бы перепрыгиваете из любого класса средней школы сразу на выпускной 🕺🏻(благодаря тому, что ответы на экзаменационные вопросы вам предоставил чат бот).

Будет это хорошо❓ Очевидно нет, шаг влево или вправо и вы уже не знаете ответа и снова идете на поклон к чат боту, с какой-то стороны это выглядит как зацикливание, а условие выхода это задать 100500 вопросов и действительно грокнуть тему или вернуться на стандартное поэтапное изучение 📖 темы.

Нет, я не говорю про то, что нужно перестать пользоваться AI, я говорю о том, что следует стараться думать 🧠 шире, разбираться почему так, сходить в документацию, хотя бы посмотреть как выглядит сайт продукта, который вы решили использовать, что у них еще есть по функционалу, может быть существуют еще лучше решения.
Cтарайтесь разговаривать с ботом: Расспрашивайте почему так? Какие есть аналоги? Что будет если сделать так? И все в таком духе.

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

P.S. На размышления меня натолкнула статья, в которой говорится о том, что начинающие разработчики все чаще не понимают, как работает ⚙️ их код.

🚀 Желаю вам продуктивного дня и хороших выходных!

#REFLECTION


🌍 Привет мир! 👋🏻

Завершаю серию постов о “ленивой загрузке”. Cегодня поговорим про Suspense, разберем что это такое и когда необходимо применять 🧐.
Перед 📖 прочтением этого поста рекомендую ознакомиться с материалами ниже 👇🏻 (необязательно, но полезно):

⚙️ Dynamic imports
⚙️ CRP
⚙️ React.Lazy

Suspense — что это

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

Благодаря fallback, можно показать заглушку (спиннер, лоадер, скелетон), вместо того чтобы отображать "белый экран” во время ожидания⏱️.

⁉️ Как работает

📎 Останавливает рендеринг дочерних компонентов, если хотя бы один из них ожидает данных.
📎 Показывает fallback вместо контента, пока данные загружаются.
📎 Продолжает рендер, когда все асинхронные операции завершены.

Когда применяется

1️⃣ Код-сплиттинг (React.lazy)

Позволяет лениво загружать компоненты и показывать fallback, пока они загружаются.

const LazyComponent = React.lazy(() => import("./LazyComponent"));

const App = () => {
return (



);
}


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

2️⃣ Асинхронные запросы с use (React 18+)

const Title = () => {
const data = use(fetchTitle());
return {data.title};
}

const App = () => {
return (



);
}


Многие frameworks поддерживают Suspense: Next.js, Remix, Relay, Gatsby, React-query и тд.

‼️ Важно: Suspense не отслеживает загрузку данных, выполняемую внутри useEffect или event handler.

3️⃣ Загрузка ресурсов (изображения, скрипты, шрифты)
Можно управлять состояниями загрузки ресурсов улучшая взаимодействие с пользователем во время ресурсоемких операций.

Как Suspense влияет на структуру рендеринга

Все дочерние компоненты внутри Suspense рассматриваются 👀 как единое целое.

Если хотя бы один компонент задерживается, то все компоненты внутри него будут заменены на fallback.

Что это значит

📌 Если несколько компонентов внутри Suspense загружаются асинхронно, UI покажет fallback до завершения всех загрузок.
📌 Упрощается управление состояниями загрузки, так как не нужно вручную проверять isLoading в каждом компоненте.

🛠 Bonus: Обработка ошибок

Suspense не обрабатывает ошибки автоматически, а просто приостанавливает рендеринг. Если в процессе загрузки данных (fetch(), useQuery(), use()) возникнет ошибка, React выбросит её в ближайший Error Boundary.

Если ErrorBoundary отсутствует, React крашнет всё приложение.

Я рекомендую 👍🏻 не писать обработчик самому, а использовать популярный пакет react-error-boundary.

const ErrorFallback = ({ error, resetErrorBoundary }) => {
return (

Ошибка: {error.message}
Попробовать снова

);
}

const App = () => {
return (





);
}


Что можно делать в ErrorBoundary

✔️ Показать альтернативный UI (например, "Ошибка загрузки данных").

✔️ Добавить кнопку "Попробовать снова" (resetErrorBoundary).

✔️ Логировать ошибку в Sentry или консоль.

💬 Делитесь своим мнением в комментариях👇! Если вам понравилась статья, не забудьте поставить лайк! 👍

#REACT


🌍 Привет, мир! 👋

⏳ Минутка полезной информации

😊 Не рекламы ради, а для удовольствия.

В ходе разработки часто необходимы различные инструменты за которыми мы лезем в интернет, к примеру: JSON diff, конвертация в base64 и обратно ну или банально сгенерить UUID.

Вот все это и даже больше есть прям в одном сайтике вот тут.

🙂 Пользуйтесь на здоровье, надеюсь кому-то будет также полезно как и мне.

🚀 Желаю вам продуктивного дня!

#CODINGTIPS


🌍 Привет мир! 👋🏻

Современный мир развивается очень и очень быстро, искусственный интеллект (AI) и четвертая промышленная революция меняют устои нашего мира. С каждого утюга только и слышно 📣:

- Вот вот нас всех заменят роботы!

Честно говоря я и сам часто думаю 🧠:

- А что делать? Куда двигаться дальше? Что учить, чтобы быть востребованным специалистом.

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

У меня куча планов 🗓 и идей благодаря которым, надеюсь, меня не заменит робот.
Но а сегодня я просто решил немного разобраться, как работает AI, но не с позиции, что сейчас изучу и пойду покорять ML вакансии, а просто иметь базовое представление, хотя бы потому что, я как backend-разработчик соприкаюсь с отделом ML.

➡️ И начать я решил с базы, а именно что такое векторная база данных.

Что такое векторная база данных (ВБД) и вектор

Это NoSQL тип БД, который хранит данные в виде многомерных векторов, каждый из которых представляет определенные характеристики или качества объекта.

Тут важно понять, что такое веткор ?

📐 Вектор — это элемент векторного пространства со своими свойствами и операциями. Если говорить проще, это массив чисел.

📝 Пример вектора изображения:

[0.12, -0.34, 0.88, 0.56]


Для 🔍 поиска или анализа данных нельзя напрямую использовать текст, изображения или аудио — их нужно преобразовывать в числа, как раз векторы позволяют представить сложные объекты (слова, картинки, аудио) в виде набора чисел.

📌 Чем больше измерений (размерность вектора), тем больше информации он содержит!

Как получить вектор объекта

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

Для каждого типа данных существуют определенные модели:

📌 Из текста с помощью NLP-моделей (Word2Vec...)
📌 Из аудиофайлов с помощью аудиомоделей (Whisper...).

и тд.

⚠️ Некоторые ВБД могут автоматически векторизовать входящие объекты (Weaviate, Qdrant...)

⁉️ Какую проблему решают ВБД

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

✏️ Пример:

В РБД формируется строгий текстовый запрос:

⚙️ Найти все товары с названием 'красные кроссовки'

Результат:

- Красные кроссовки Nike

Но не найдёт:

- Бордовые кеды Converse

При использовании ВБД, запрос формируется иначе:

🔎 Найти обувь, похожую на красные кроссовки

Результат:

- Красные кроссовки Nike
- Бордовые кеды Converse

‼️ Некоторые ВБД могут хранить не только вектора, но и метаданные исходных объектов, включая ссылки на оригинальные файлы.

Как вычисляется "схожесть" объектов?

В ВБД схожесть объектов определяется с помощью расстояния между векторами. Чем меньше расстояние, тем более схожими считаются объекты. Для оценки расстояния используются различные математические методы.

📎 Примеры метрик и где используется:

- Косинусное сходство (Текст, поиск документов)
- Евклидово расстояние (Изображения, аудио, геоданные)
- Манхэттенское расстояние (Финансовые данные)

ℹ️ Индексация в ВБД

В РБД для ускорения поиска необходимых данных как правило используются индексы, которые немного замедляют запись, но значительно ускоряют поиск и соответственно получение данных. Вот и в ВБД существуют методы оптимизации поиска векторов, так как их может быть миллионы или даже миллиарды и полный перебор займет длительное 🕑 время.

☄️ Ускорить поиск можно несколькими способами:

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

📝 Итого:

Путь получения данных выглядит следующим образом.

Запрос (промпт) → Векторизация (эмбеддинг) → Поиск ближайших векторов → результат.

🙂 Хорошего дня!

#AI

322 0 2 10 16

🌍 Привет мир! 👋

Я объединился с ребятами, которые покоряют it-рынок 🌐 и мы создали общую папку, где тусуются разработчики, команды и эксперты. Здесь делятся крутыми ⚙️ разработками, инсайтами и опытом, который сложно найти в открытом доступе.

Кому интересно, переходите по 'https://t.me/addlist/8M4M5gh_lhJlM2Y6' rel='nofollow'>ссылке 📥

Всем желаю ☀️ классных и продуктивных выходных 👌🏻.


🌍 Привет, мир! 👋

Минутка полезной информации

Уверен, что многие используют LIKE в SQL для поиска по шаблону, но не все знают про ILIKE, который иногда может упростить вам жизнь.

⬇️ Обычно запрос пишется:

SELECT * FROM users
WHERE name LIKE 'alex%';


⚠️ Но проблема в том, что LIKE чувствителен к регистру, а это значит, что "Alex" и "alex" — это разные строки, и вышеуказанный запрос не найдёт "Alex" или "ALEX".

⬇️ С помощью ILIKE можно игнорировать регистр:

SELECT * FROM users
WHERE name ILIKE 'alex%';


✅ Теперь в результате получим "alex", "Alex", "ALEX" и "aLeX" – без лишних манипуляций с LOWER().

‼️ Внимание

ILIKE работает только в PostgreSQL, в MySQL и других СУБД он не поддерживается.

🙂 Пользуйтесь на здоровье

🚀 Желаю вам продуктивного дня!

#CODINGTIPS #SQL


🌍 Привет мир! 👋

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

Это не означает, что я перестану здесь публиковать, просто там будет иногда немного больше полезного контента.💡

О ходе разработки ⚙️ я с удовольствием буду делиться с вами. Могу сказать, что технологию я уже выбрал и это будет Astro.

На мой субъективный взгляд, весьма прогрессивный web framework и + объектиный взгляд почти 10к звезд.

Что меня зацепило в Astro

Island Architecture: архитектура веб-приложений на основе компонентов, оптимизированная для сайтов с контентом (только только про данную архитектуру был пост).

➖ Независимость от UI-фреймворков (UI-agnostic): Поддерживает React, Preact, Svelte, Vue, Solid, HTMX, веб-компоненты и многое другое.

➖ Сервер в приоритете (Server-first): Переносит дорогостоящий рендеринг с устройств посетителей на сервер.

➖ Ноль JavaScript по умолчанию (Zero JS, by default): Меньше клиентского JavaScript, который может замедлить сайт.

➖ Валидация и безопасность типов TypeScript для контента на Markdown.

➖ Настраиваемость: Поддержка Tailwind, MDX и сотен интеграций на выбор.

Ну что же, буду пробовать 🙂

💬 Делитесь своим мнением в комментариях👇! Если вам понравилась статья, не забудьте поставить лайк! 👍

236 0 1 19 13

🌍 Привет мир! 👋

Cегодня поговорим про интересный архитектурный паттерн для frontend “Islands architecture”. Впервые идея данного паттерна была задокументирована создателем Preact.

🚀 Мотивация

Понимание Island Architecture дает важное представление о том, как работают современные фреймворки для создания высокопроизводительных веб-приложений, таких как Astro, Next.js, Nuxt.js, Vue 3 и ряд других. Этот подход помогает улучшить производительность, ускорить загрузку страниц и повысить гибкость в разработке.

Я уже неоднократно писал статьи про производительность и найти 🔎 их можно по хештегу #PERFORMANCE.

Как работает Island Architecture

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

✏️ Пример

📎 Когда страница запрашивается пользователем, сервер генерирует весь HTML для страницы, включая как статичный контент (компоненты), так и места для динамических компонентов.

📎 Статичный контент, такой как текст, изображения или макеты, генерируется на сервере и отправляется клиенту как готовая HTML-страница.

📎 Динамические части, такие как формы, виджеты, карты, или другие интерактивные элементы, отправляются на страницу как слоты. Эти части содержат минимальный HTML, который будет использоваться для гидратации.

❗️ Hydration - это момент, когда браузер загружает JavaScript-код, и этот код добавляет интерактивность.

✏️ Например: Кнопки начинают реагировать на клики, формы — на отправку, а элементы на странице становятся динамическими.

➖ Без гидратации: Страница просто показывает текст и картинки, но ничего нельзя нажать или изменить.
➖ После гидратации: Можно кликать по кнопкам, отправлять формы и взаимодействовать с элементами на странице.

💡 Статичные части страницы полностью отображаются сразу, а динамические компоненты, которые были отправлены как слоты, также отображаются, но являются неактивными так как в них нет JS.

Что происходит с бандлами

1️⃣ Начальный (основной) бандл, содержит минимальный JavaScript, необходимый для гидратации динамических компонентов.
2️⃣ Динамические островки: Для каждого динамического компонента или "островка" создается отдельный бандл, который будет загружен и гидратирован только тогда, когда этот компонент нужен. Такой подход называется разделением кода (code splitting).

⚙️ Ленивая загрузка (Lazy Loading): Один из способов разделения бандлов в рамках островной архитектуры. JavaScript для каждого островка загружается только по мере необходимости, что минимизирует начальную нагрузку на браузер. Например, React.lazy (про который я писал ранее).

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

❗️Islands architecture❗️ не подходит для высокоинтерактивных страниц, таких как социальные сети, для которых вероятно потребуются тысячи островов.

💬 Делитесь своим мнением в комментариях👇! Если вам понравилась статья, не забудьте поставить лайк! 👍

#PERFORMANCE #ARCHITECTURE


🌍 Привет мир! 👋

А у меня сегодня про performance, и разговор пойдет про React.lazy. На самом деле в большинстве ваших проектах можно пропустить использование Lazy, но понимание принципа работы и умение грамотно использовать данную возможность, сделает вас как разработчика еще на шаг выше остальных. Перед прочтением рекомендую ознакомиться со статьей о динамических импортах.

📈 Немного занимательной статистики

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

📎 Время загрузки страницы на мобильном устройстве в 10 секунд увеличивает показатель отказов на 123% по сравнению со скоростью загрузки в одну секунду.

📎 53% посетителей мобильных сайтов покидают страницу, если ее загрузка занимает более трех секунд.

📎 Коэффициент конверсии веб-сайта падает на 4,42% с каждой секундой загрузки, которая составляет от нуля до пяти секунд.

📎 Почти 70% посетителей говорят, что скорость загрузки страниц влияет на их готовность совершать покупки в интернет-магазине.

🚀 Мотивация

Использование ленивой загрузки это один из способов уменьшить нагрузку на браузер (за счет более скоромного начального размера бандла) и как следствие уменьшить время загрузки приложения.

В чем идея Lazy

⚙️ Принцип ленивой загрузки (lazy loading) заключается в том, что загружаются ресурсы или данные только тогда, когда они действительно нужны, а не заранее.

⚙️ Lazy использует динамический импорт, тем самым появляется возможность динамически импортировать модуль или компонент во время выполнения кода.

⚙️ Компоненты, которые могут никогда не понадобиться пользователю (например, если он никогда не переключит вкладку), вообще не будут загружены.

✏️ Пример:

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

- Что делаем?
- Конечно, используем React.lazy для ленивой загрузки.

import React, { Suspense, useState, lazy } from 'react';

// Ленивая загрузка двух компонентов
const CompA = lazy(() => import('./CompA'));
const CompB = lazy(() => import('./CompB'));

export const TestComponent = () => {
const [showCompA, setShowCompA] = useState(true);

return (

setShowCompA((prev) => !prev)}>
Показать {showCompA ? 'CompB' : 'CompA'}



{showCompA ? : }


);
}


Как это работает

1️⃣ Ленивая загрузка по необходимости: Компоненты CompA и CompB загружаются только тогда, когда они нужны. При первом рендере главный бандл не включает код этих компонентов, так как они будут загружены динамически (по запросу) благодаря lazy.

2️⃣ Начальное состояние: Несмотря на то, что начальное состояние useState установлено как true (т.е. CompA должен быть отрисован), его код не включен в главный бандл. Это связано с тем, что lazy и динамический импорт работают асинхронно, и компонент загружается только при попытке его рендера.

3️⃣ Механизм загрузки: При первом рендере, если состояние showCompA = true, React запускает динамическую загрузку кода CompA. Пока он загружается, вместо него показывается содержимое fallback из (в данном случае это Загрузка...).

4️⃣ После загрузки: Когда загрузка компонента завершается, React заменяет fallback на готовый рендер компонента.

☀️ И немного про Suspense

Suspense управляет отображением, пока лениво загружаемый компонент не станет доступен. В примере выше Suspense показывает "Загрузка..." до завершения загрузки CompA или CompB. Про Suspense подробнее поговорим в следующих статьях.

‼️ Важно: Не нужно использовать Lazy повсеместно, подходите к его применению обоснованно. Использование lazy оправдано, когда речь идет о загрузке тяжелых или редко используемых компонентов, которые не требуются при первом рендере страницы.

💬 Делитесь своим мнением в комментариях👇! Если вам понравилась статья, не забудьте поставить лайк! 👍

#REACT #PERFORMANCE


🌍 Привет мир! 👋

Понедельник день тяжелый 🔥, но ничего страшного, вечер пятницы неумолимо придет !)

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

Уже и поресерчил 👀 и дядя chatGPT советов накидал, и вот в ходе ресерча обнаружил интересный сайтик npm trends.

Там все просто: накидываете либы между которыми вы выбираете и дальше анализируете данные 🌐.

Важно смотреть на такие характеристики как:
❗️ Последняя дата обновления
❗️ Размер библиотеки
❗️ Количество issues
❗️ Количество скачиваний

Вот вам пример, выглядит очень классно.

‼️ P.S. Относитесь к таким задача очень серьзно, даже если библиотек миллион и все удовлетворяют вашим требованиям, при использовании может возникнуть проблема, которая заставит вас откатиться назад к выбору, а бизнес в свою очередь потеряет деньги 💵.

💬 Делитесь своим мнением в комментариях👇! Если вам понравилась статья, не забудьте поставить лайк! 👍

#NPM #TECHTRENDS


🌍 Привет мир! 👋

Сегодня рассмотрим 👀 рабочий кейс, связанный с историей коммитов.

Как найти коммит в котором были удалены, добавлены или изменены какие-либо данные❓

🚀 Мотивация

Иногда для совершения корректных действий в настоящее время c вашим кодом, необходимо знать предысторию файла или конкретной строчки в файле. Почему этот кусочек был удален или добавлен? Или почему в том или ином месте применены такие ключи? И еще много чего…

📖 История примера

Вы работаете с проектом, у которого тысячи и тысячи коммитов, в котором структура проекта менялась не один раз, методы претерпевали десятки изменений или вообще весь проект в одно мгновение переехал с JS на TS и так далее.

И вдруг в этом самом проекте вам прилетела задача на исправление бага.
Почему-то на одной из страничек, на одной из форм, нет селекта❓🤯
- хмм…

"Да это же изи фикс!" - подумаете вы, радостно 😜 добавите селект, любезно взятый из другой формы, проверите что все отображается корректно и с чувством выполненного долга, закроете задачку.

НО

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

❓ С какой целью убрали? Почему только тут, а не во всем проекте ? Когда? А может быть это вовсе не бага, а фича?

👉 Ведь в ответах на эти вопросы, кроется истина

Может быть так и должно работать? Или может быть раз уж тут нужно показывать, то есть и еще места которые тестеры не нашли⁉️

💻 Как раз тут и возникает необходимость пошатать старые-престарые коммиты.

🛠️ Практика

❌ Я не пользуюсь красивыми и может быть весьма удобными графическими утилитами по работае с GIT (если у вас есть что-то классное, пишите в комментариях👇).

Чтобы найти 🔎 commit, в котором были произведены какие-то действия над данными которые я сейчас изучаю, пользуюсь следующими командами:

git log -S "isShowSelectV5" -- path/to/file.js


или

git log -G "label={translate" -- path/to/file.js


git log: команда для отображения истории коммитов в репозитории.


S ("pickaxe search") "isShowSelectV5": поиск коммитов, в которых указанная строка ("isShowSelectV5") была добавлена или удалена.
‼️ Git ищет изменения в коммитах, которые точно соответствуют этой строке.

G "label={translate": Поиск всех коммитов, где происходили изменения, в которых содержался текст "label={translate". В отличие от -S включает случаи, где строка была не только удалена или добавлена, но и изменена.

path/to/file.js: Указываем путь к файлу или папке, где будет происходить поиск. Это ограничение на поиск измененений, сделанных в этом конкретном файле или папке, вместо того чтобы искать по всему репозиторию.


👇 Пример:

📄 Файл example.js с изменениями в истории

Исходная строка:

const message = "Hello, World!";


Изменения в истории:

Коммит A: Добавлена строка.
const message = "Hello, World!";


Коммит B: Строка изменена.
const message = "Hello, Universe!";


Коммит C: Строка удалена.
// Строка удалена


Пробуем поиск с флагом -S
git log -S "Hello, World!" -- example.js


✔️ Что найдёт:

📎 Коммит A, где строка "Hello, World!" была добавлена.
📎 Коммит C, где строка "Hello, World!" была удалена.

❌ Что не найдёт:

📎 Коммит B, где строка была изменена на "Hello, Universe!", потому что S ищет только точное добавление или удаление указанного текста.

Пробуем поиск с флагом -G
git log -G "Hello" -- example.js


✔️ Что найдёт:

📎 Коммит A, где строка "Hello, World!" была добавлена (содержит "Hello").
📎 Коммит B, где строка была изменена на "Hello, Universe!" (текст "Hello" остался).
📎 Коммит C, где строка "Hello, World!" была удалена (текст "Hello" исчез).

👉 Итог: Не ленитесь определять причинно-следственную связь. Ваши усилия не останутся незамеченными, так как вы будете экономить деньги компании.

💬 Делитесь своим мнением в комментариях👇! Если вам понравилась статья, не забудьте поставить лайк! 👍

#GIT


🌍 Привет мир! 👋

Выбираете 🔎 технологии для нового проекта или хотите пощупать что-то новое и классное?

Предлагаю вам такие источники для вдохновения, итоги за 2024!

📖 2024 JavaScript Rising Stars
📖 State of JavaScript 2024

Желаю вам хорошего дня! 🎈

#TECHTRENDS


🌍 Привет мир! 👋

Cегодня поговорим про Web Performance: Critical Rendering Path. Не каждое приложение может дорасти до такого состояния, когда возникает проблема с производительстью. Однако понимание того, чего следует избегать при разработке, может помочь еще больше обезопасить ваше приложение от проблем с "перфом".

🚀 Мотивация

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

⁉️ Что такое Critical Rendering Path

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

🛠️ Этапы CRP

1️⃣ Получение HTML

Браузер делает HTTP-запрос к серверу и получает HTML-код страницы. Этот код анализируется и браузер ищет связанные ресурсы: CSS, JavaScript, шрифты, изображения и т.д.

2️⃣ Парсинг HTML и создание DOM

HTML преобразуется в DOM (Document Object Model) — дерево элементов, которое отражает структуру документа.

3️⃣ Загрузка и обработка CSS

CSS-файлы загружаются, анализируются и превращаются в CSSOM (CSS Object Model) — дерево стилей.

4️⃣ Выполнение JS

Применение любого JavaScript, который изменяет DOM или CSSOM.

5️⃣ Создание Render Tree

Объединяя DOM и CSSOM, браузер создает Render Tree — визуальное представление элементов, которые нужно отобразить на экране.

6️⃣ Layout (расчет позиций)

На этом этапе браузер рассчитывает размеры и позиции всех элементов на странице, учитывая медиазапросы, шрифты и зависимости.

7️⃣ Painting (отрисовка)

Наконец - Render Tree, преобразуется в пиксели и браузер отрисовывает элементы на экране.

‼️ Важно знать:

Браузеру необходимо дождаться загрузки некоторых критически важных ресурсов, перед завершением первого рендера:

✔️ Начального HTML (особенно находящегося в ).
✔️ CSS, который используется в и не помечен как media="print".
✔️ JavaScript в , если он не помечен атрибутами async или defer.

❗ Render Tree не включает скрытые элементы (display: none) или внешние ресурсы, которые ещё не загружены.

❗ Чем больше количество узлов DOM, тем дольше длится шаг layout.

❗ Динамическое добавление или изменение DOM может запустить процесс layout и painting заново, и это сказывается на производительности.

⚙️ Оптимизация CRP

💡 Lazy Loading: Используйте loading="lazy" для изображений и .

💡 Оптимизируйте изображения: Используйте современные форматы, такие как WebP или AVIF.

💡 Старайтесь избегать использования дорогостоящих CSS стилей (box-shadow, blur..).

💡 Веб-шрифты могут быть большими и блокировать render. Попробуйте использовать font-display: swap для возврата к системному шрифту во время загрузки веб-шрифта.

💡 CDN может обслуживать файлы JavaScript с сервера, ближайшего к пользователю, сокращая время, необходимое для их загрузки.

💡 Установите соответствующие заголовки кэширования HTTP, и кэшируйте файлы JavaScript.

💡 Убедитесь, что выполняется Tree Shaking, это процесс удаления неиспользуемого кода JavaScript во время сборки.

📎 Используйте prefetch и preload:

➖ preload для текущей страницы (шрифты, критические стили).
➖ prefetch для ресурсов будущих страниц.

💡 Используйте медиазапросы для уменьшения нагрузки на мобильных устройствах.

Как определить блокирующие ресурсы

➖ Используйте WebPageTest: ресурсы, блокирующие рендеринг, отмечены оранжевым значком.
➖ Используйте Lighthouse в Chrome DevTools для анализа производительности.
➖ В DevTools вкладка Network: ищите ресурсы с пометкой "blocking".

💬 Делитесь своим мнением в комментариях👇! Если вам понравилась статья, не забудьте поставить лайк! 👍

#PERFORMANCE


🌍 Привет мир! 👋

Немного полезной информации, замечали символы (^) и (~) в package.json? А ведь они что-то означают, это не для красоты 🤗

💡 Сaret - ^

"dependencies": {
"react": "^18.0.0"
}

Этот символ говорит 🗣️ вашему приложению :
- При установке или обновлении зависимостей, я автоматически поставлю тебе новые minor и patch версии, хочешь ты этого или нет, но если что major версию трогать не буду, даже если в npm registry уже доступен мажор.

🔎 Например:

"react": "^18.0.0" означает, что имеется разрешение на обновление (до любой версии) двух крайних цифр, что-то вроде 18.0.10 или 18.10.5, но не до 19.0.0.

Кстати про major, minor и остальное я уже рассказывал здесь 😊.

Minor версия - означает добавление новой функциональности, при которой сохраняется обратная совместимость.

💡 Tilde - ~

"dependencies": {
"react": "~18.0.0"
}

Это сaret на стероидах. Данный символ позволяет обновлять только патч-версии.

🔎 Например:

"react": "~18.5.6" означает, что может обновиться только крайняя цифра, в данном случае это 6.

Patch версия - это изменения связанные только с исправлением багов.

‼️ Итог: Не забывайте про tilde и caret — оцените, действительно ли они необходимы вашему проекту.

💬 Делитесь своим мнением в комментариях👇! Если вам понравилась статья, не забудьте поставить лайк! 👍

#NPM


🌍 Привет мир! 👋

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

📊 Cтатистика

Мне стало интересно, сколько же багов создает средний разработчик, понятно что здесь миллион факторов которые влияют на значения, но все же ➕➖ что-то можно посчитать.

💡 Я нашел вот такую статистику, которую предоставила Coralogix компания.

❗ В среднем разработчик создает 70 ошибок на каждые 1000 строк кода.
❗ 15 ошибок на 1000 строк кода доходят до пользователей. Исправление ошибки занимает в 30 раз больше времени, чем написание одной строки кода.
❗ 75% времени разработчика уходит на отладку (1500 часов в год!).
❗ Только в США ежегодно тратится 113 миллиардов долларов на выявление и исправление дефектов продуктов.

💻 Проблема найденная в коде

Есть обычный функциональный компонент, в реальной проблеме он был немного больше и запутаннее, я оставил только самый сок.

const TodoComponent = ({ initialTasks = [] }) => {
const [tasks, setTasks] = useState();

useEffect(() => {
setTasks({
taskCount: initialTasks.length,
});
}, [initialTasks]);

const renderTaskCount = tasks?.taskCount ?? 0;
return (

TodoComponent
Task Count: {renderTaskCount}

);
};


🧠 Подумайте в чем здесь может быть проблема, получится ли у вас сразу спрогнозировать проблему?

Ответ: Компонент будет уходить в Infinite Render Loop из-за того, что каждый раз создается initialTasks с пустым массивом.

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




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




👇 В таком случае вы получаете:

Warning: Maximum update depth exceeded.
This can happen when a component calls setState inside useEffect,
but useEffect either doesn't have a dependency array,
or one of the dependencies changes on every render


🔎 Проблема заключается в том, что когда родительский компонент вызывает TodoComponent и не передает initialTasks, то значение по умолчанию = [] каждый раз создается заново.
Это означает, что, хотя значение initialTasks одно и то же (пустой массив), это новая ссылка при каждом рендеринге. И все бы ничего, но initialTasks идет как dependencies в useEffect.

🛠️ Как итог каждый раз обновляется состояние setTasks, которое приводит к re-render компонента и создании нового массива → Infinite Render Loop.

❗ Если такая проблема не попадает на глаз сразу, то в дальнейшем это может привести к тяжелым поискам и временным затратам.

📝 Решения

1️⃣ Использовать внешнюю константу.

const defaultInitialTasks = [];

const TodoComponent = ({ initialTasks = defaultInitialTasks }) => ...


2️⃣ Использовать мемоизацию. Это гарантия того, что значение по умолчанию для initialTasks не изменится между рендерами, если оно явно не изменено.

const defaultInitialTasks = useMemo(() => initialTasks || [], [initialTasks]);

useEffect(() => {
setTasks({
taskCount: defaultInitialTasks.length,
});
}, [defaultInitialTasks]);


🙂 Всем хорошей недели и чистого кода!

💬 Делитесь своим мнением в комментариях👇! Если вам понравилась статья, не забудьте поставить лайк! 👍

#REACT

20 last posts shown.