💡 Toolkit или Ties — узлы на пересечении горизонтальных и вертикальных слоёв системы. Это инструменты, которые связывают юз-кейсы со всеми слоями архитектуры, сохраняя при этом модульность и тестируемость.
📘 Об этом подробно рассказывает Роберт Мартин в первых главах «Чистой архитектуры». Ключевая мысль: избавляйтесь от нестабильных импортов.
Если вы импортируете что-то из внешнего источника (например,
Так вы превращаете нестабильный импорт в стабильный, контролируемый вами.
🔧 Пример:
вместо прямого
Захотите поменять инструмент — меняете только внутреннюю реализацию, а не весь код, использующий это.
🎯 Ещё один принцип — направление зависимостей:
импорты кода идут от центра к периферии, а не наоборот.
Общий слой не должен знать о специфичном.
Но здесь может появиться ловушка. Например, транспортный слой, который просто делает
🧩 На помощь приходит DI (Dependency Inversion).
Мы определяем контракт для обработки ошибок, например:
Для базового случая используем заглушку:
А при необходимости — переопределяем поведение, не трогая общий код:
И даже в рамках одного юзкейса можно временно заменить зависимость:
В итоге:
* основной код остаётся нетронутым
* транспорт остаётся общим
* а конкретное поведение легко настраивается через DI
📘 Об этом подробно рассказывает Роберт Мартин в первых главах «Чистой архитектуры». Ключевая мысль: избавляйтесь от нестабильных импортов.
Если вы импортируете что-то из внешнего источника (например,
npm-пакет), вынесите этот код в свой слой.Так вы превращаете нестабильный импорт в стабильный, контролируемый вами.
🔧 Пример:
вместо прямого
import * as Sentry from 'sentry' создайте свой хук useTracking, который внутри может использовать Sentry, Datadog, Prometheus — что угодно.Захотите поменять инструмент — меняете только внутреннюю реализацию, а не весь код, использующий это.
🎯 Ещё один принцип — направление зависимостей:
импорты кода идут от центра к периферии, а не наоборот.
Общий слой не должен знать о специфичном.
Но здесь может появиться ловушка. Например, транспортный слой, который просто делает
fetch-запросы, вдруг должен начать понимать, что ошибки с core-backend надо обрабатывать по-особому. Потом появляется второй сервис, третий… и в коде множатся if и импорты.🧩 На помощь приходит DI (Dependency Inversion).
Мы определяем контракт для обработки ошибок, например:
if (!response.ok) {
const parsedError = await this.errorTools.parseError(response.clone());
if (parsedError) { ... }
}Для базового случая используем заглушку:
di.bind<ErrorTools>(ERROR_TOOLS_DI_TYPE).to(BaseErrorTools);
А при необходимости — переопределяем поведение, не трогая общий код:
di.rebind<ErrorTools>(ERROR_TOOLS_DI_TYPE).to(SpecificErrorTools);
И даже в рамках одного юзкейса можно временно заменить зависимость:
export const getOrder = (input: GetOrderInput) => {
di.rebind<ErrorTools>(ERROR_TOOLS_DI_TYPE).to(SpecificErrorTools);
const result = di.get<GetOrderUseCase>(GET_ORDER_DI_TYPE).exec(input);
di.rebind<ErrorTools>(ERROR_TOOLS_DI_TYPE).to(BaseErrorTools);
return result;
};В итоге:
* основной код остаётся нетронутым
* транспорт остаётся общим
* а конкретное поведение легко настраивается через DI
🔥3❤2💯2
UI Renderer или Representation — следующий слой нашей архитектуры.
Есть ощущение, что всё, что я уже написал, больше подходит для бэкенд-разработки?
Да, это практически так и есть. MATRIX появилась в условиях разработки BFF, а это и есть обычный бэкенд-сервис.
Но на фронтенде ситуация практически та же самая.
Я имею в виду все те принципы, что мы уже рассмотрели:
* доменные сущности и их преобразования,
* стабильные импорты,
* направление импортов и т. д.
😦 Из нового здесь, пожалуй, лишь то, что у нас все компоненты — "глупые".
Надеюсь, все знакомы со статьёй Дэна Абрамова где он описал паттерн разделения React-компонентов на презентационные (глупые) и контейнерные (умные). Презентационные компоненты отвечают только за отображение UI и получают данные через props, а контейнерные управляют логикой и состоянием.
Так вот, чтобы "умные" компоненты не становились слишком "умными", мы вообще от них отказались. "Умный" — значит, много знает про бизнес-логику и доменные сущности, а мы уже решили, что всё, что как-то обрабатывает доменные сущности, к домену и относится.
Поэтому у нас остаются только "глупые" компоненты, для которых мы прописываем свой контракт взаимодействия (пропсы), чтобы они приняли нужные пропсы и отобразили нужный UI. Остаётся только как-то передать эти пропсы в компоненты. Здесь на помощь приходит паттерн composeHooks.
На самом деле, это что-то вроде connect из Redux, который подключает компонент к стору с данными. Только в нашем случае composeHooks подключает компоненты к доменным сущностям в агностик режиме.
React Hooks Compose — композиция хуков для чистой архитектуры 🧩
Библиотека react-hooks-compose позволяет отделить хуки от компонентов, создавая переиспользуемые контейнеры. Она работает по принципу Redux connect, но для хуков — принимает хук и компонент, возвращает компонент с внедрёнными данными. Ключевой момент: хуки не содержат бизнес-логику, а служат адаптерами для подключения доменных сущностей к UI.
#hooks #architecture #composition
Есть ощущение, что всё, что я уже написал, больше подходит для бэкенд-разработки?
Да, это практически так и есть. MATRIX появилась в условиях разработки BFF, а это и есть обычный бэкенд-сервис.
Но на фронтенде ситуация практически та же самая.
Я имею в виду все те принципы, что мы уже рассмотрели:
* доменные сущности и их преобразования,
* стабильные импорты,
* направление импортов и т. д.
😦 Из нового здесь, пожалуй, лишь то, что у нас все компоненты — "глупые".
Надеюсь, все знакомы со статьёй Дэна Абрамова где он описал паттерн разделения React-компонентов на презентационные (глупые) и контейнерные (умные). Презентационные компоненты отвечают только за отображение UI и получают данные через props, а контейнерные управляют логикой и состоянием.
Так вот, чтобы "умные" компоненты не становились слишком "умными", мы вообще от них отказались. "Умный" — значит, много знает про бизнес-логику и доменные сущности, а мы уже решили, что всё, что как-то обрабатывает доменные сущности, к домену и относится.
Поэтому у нас остаются только "глупые" компоненты, для которых мы прописываем свой контракт взаимодействия (пропсы), чтобы они приняли нужные пропсы и отобразили нужный UI. Остаётся только как-то передать эти пропсы в компоненты. Здесь на помощь приходит паттерн composeHooks.
На самом деле, это что-то вроде connect из Redux, который подключает компонент к стору с данными. Только в нашем случае composeHooks подключает компоненты к доменным сущностям в агностик режиме.
React Hooks Compose — композиция хуков для чистой архитектуры 🧩
Библиотека react-hooks-compose позволяет отделить хуки от компонентов, создавая переиспользуемые контейнеры. Она работает по принципу Redux connect, но для хуков — принимает хук и компонент, возвращает компонент с внедрёнными данными. Ключевой момент: хуки не содержат бизнес-логику, а служат адаптерами для подключения доменных сущностей к UI.
#hooks #architecture #composition
👍5❤1💯1
Incoming ports — входящие порты — последний недостающий элемент, который связывает слой домена и слой UI.
Именно порты — это то место, где система получает инструкции извне и знает, как их обработать.
По сути, порты — это граница между нашим BFF и тем, что находится в браузере пользователя.
Подробно останавливаться на них нет смысла — всё это уже отлично описано в документации по шестиугольной архитектуре (Hexagonal Architecture). Формально, входящие порты в матричной архитектуре выполняют ту же роль.
Зато стоит отметить, какими могут быть виды входящих портов 👇
* API-вызов
Когда мы напрямую обращаемся к хендлеру и обрабатываем параметры запроса.
* Серверный action
Почти то же самое, что и API-хендлер, но с улучшенным DX — вызов эндпоинта замаскирован под вызов обычной функции.
* Серверный компонент
Вариант для случаев, когда мы работаем с fullstack-компонентами или layout-структурами в новом роутере Next.js.
Вероятно, существуют и другие способы запускать use case в приложении, но мы используем только эти три на постоянной основе.
Именно порты — это то место, где система получает инструкции извне и знает, как их обработать.
По сути, порты — это граница между нашим BFF и тем, что находится в браузере пользователя.
Подробно останавливаться на них нет смысла — всё это уже отлично описано в документации по шестиугольной архитектуре (Hexagonal Architecture). Формально, входящие порты в матричной архитектуре выполняют ту же роль.
Зато стоит отметить, какими могут быть виды входящих портов 👇
* API-вызов
Когда мы напрямую обращаемся к хендлеру и обрабатываем параметры запроса.
* Серверный action
Почти то же самое, что и API-хендлер, но с улучшенным DX — вызов эндпоинта замаскирован под вызов обычной функции.
* Серверный компонент
Вариант для случаев, когда мы работаем с fullstack-компонентами или layout-структурами в новом роутере Next.js.
Вероятно, существуют и другие способы запускать use case в приложении, но мы используем только эти три на постоянной основе.
👍2❤1🔥1
🌐 eXternal Adapter — последний ключевой элемент матричной архитектуры.
Как видно из названия, это слой, который адаптирует запросы нашего приложения к внешнему миру.
Приложение может существовать само по себе, внешние сервисы — тоже, но чтобы они могли взаимодействовать, нужен общий протокол.
Слой адаптера как раз и выполняет эту роль.
🧩 Что считается внешней системой?
Чаще всего — это другой бекенд-сервис (микросервис), который принимает запросы и возвращает данные.
Но также внешней системой может быть:
* файловая система
* шина данных
* вебхуки
* или любые другие источники вне нашего приложения.
Соответственно, протокол взаимодействия будет зависеть от типа системы:
* для бэкендов — HTTP или gRPC
* для файлов — локальное чтение, S3 и т.д.
Поэтому внутри адаптера обычно выделяют подслой транспорта, который отвечает за конкретную коммуникацию.
⚙️ Пример: взаимодействие с бекендом
Слой адаптера, как и любой другой слой, должен иметь свой интерфейс.
Для сетевых запросов мы можем свести всё к двум операциям —
Где бы нам ни понадобилось обратиться к внешнему сервису, мы используем эти два метода, а уже адаптер решает, как именно выполнить запрос — через REST, GraphQL или что-то ещё.
🧱 Как сделать транспорт стабильным?
Проблема: параметры запроса в
Решение: развернуть зависимость на стабильный импорт.
Создаём свой интерфейс
* вместо
* вместо
Так мы создаём единый контракт, не зависящий от конкретного транспорта.
📁 Пример с файловой системой
Здесь тоже появляется дополнительный уровень:
создаём интерфейс
Дальше — транспорты:
*
*
При этом сам адаптер FS может иметь минимальный набор методов, например:
*
*
*
То же самое и с API-адаптером — он просто предоставляет
💡 В итоге eXternal Adapter — это граница между вашим приложением и внешним миром,
которая изолирует сложность коммуникации и делает систему по-настоящему стабильной и расширяемой.
Как видно из названия, это слой, который адаптирует запросы нашего приложения к внешнему миру.
Приложение может существовать само по себе, внешние сервисы — тоже, но чтобы они могли взаимодействовать, нужен общий протокол.
Слой адаптера как раз и выполняет эту роль.
🧩 Что считается внешней системой?
Чаще всего — это другой бекенд-сервис (микросервис), который принимает запросы и возвращает данные.
Но также внешней системой может быть:
* файловая система
* шина данных
* вебхуки
* или любые другие источники вне нашего приложения.
Соответственно, протокол взаимодействия будет зависеть от типа системы:
* для бэкендов — HTTP или gRPC
* для файлов — локальное чтение, S3 и т.д.
Поэтому внутри адаптера обычно выделяют подслой транспорта, который отвечает за конкретную коммуникацию.
⚙️ Пример: взаимодействие с бекендом
Слой адаптера, как и любой другой слой, должен иметь свой интерфейс.
Для сетевых запросов мы можем свести всё к двум операциям —
query и mutation (да, почти как в GraphQL).Где бы нам ни понадобилось обратиться к внешнему сервису, мы используем эти два метода, а уже адаптер решает, как именно выполнить запрос — через REST, GraphQL или что-то ещё.
🧱 Как сделать транспорт стабильным?
Проблема: параметры запроса в
fetch (method, body, headers) и в GraphQL (query, variables) — разные.Решение: развернуть зависимость на стабильный импорт.
Создаём свой интерфейс
TransportRequest, в котором обобщаем параметры:* вместо
resource для REST используем query для GraphQL* вместо
body — graphql query stringТак мы создаём единый контракт, не зависящий от конкретного транспорта.
📁 Пример с файловой системой
Здесь тоже появляется дополнительный уровень:
создаём интерфейс
FileMeta с полем baseDir, где локально это корень проекта, а для S3 — сервер с файлами.Дальше — транспорты:
*
node:fs для локальной работы*
s3-sdk для облакаПри этом сам адаптер FS может иметь минимальный набор методов, например:
*
files()*
write()*
read()То же самое и с API-адаптером — он просто предоставляет
query() и mutation().💡 В итоге eXternal Adapter — это граница между вашим приложением и внешним миром,
которая изолирует сложность коммуникации и делает систему по-настоящему стабильной и расширяемой.
🔥3❤1👍1
Итак, новая неделя — новая тема для серии.
Вообще, в Питере наступает настоящая осень: небо затянуло серой непроглядной тьмой, и единственное, что приходит на ум — «набросить на вентилятор» 😈
Так вот, давайте набросим на самое дорогое для фронтендеров — стейт-менеджеры не нужны!
Ну реально — это же нескончаемый источник хейта среди разработчиков. Зачем ещё плодить холивары?
А если немного вернуться в объективное русло, то у нас ведь всегда был самый крутой стейт-менеджер — Браузер и его адресная строка.
Всё состояние страницы можно описать прямо в URL — фильтры, сортировки, активные вкладки, выбранные элементы. Когда придёт время, приложение просто подгружает нужные данные в соответствии с этим состоянием.
🧩 В типичном фронтенд-приложении стейт обычно размазан по нескольким слоям:
* основная масса живёт на бэкенде,
* часть хранится на BFF, чтобы быстро получать данные,
* остатки — на клиенте, где мы с ними возимся.
И чтобы ничего не потерять, запускается бесконечный цикл синхронизации между этими слоями.
Пользователь изменил инпут → сработал эффект → эффект дернул ручку → запрос ушёл на BFF → там его обогатили → передали дальше → вернули ответ → разгрузили → обновили клиент...
♻️ И так по кругу.
Почему бы не сделать этот круг единым?
Есть адрес, описывающий состояние приложения → загружаешь приложение в нужном состоянии.
Что-то изменилось → обновился URL → приложение загрузило новое состояние.
Просто. Прозрачно. Логично.
Используйте для этого серверные компоненты или loader-pattern — и всё начнёт работать естественным образом, без лишнего прослойного хаоса.
📄 «А как же промежуточное состояние? Пока я не сабмитнул форму, где мне хранить данные?»
Отличный вопрос. Но тут тоже есть ответ.
Для формочек ты, скорее всего, уже используешь библиотеку — а ведь форма сама по себе и есть стейт-менеджер.
Пока ты заполняешь инпуты, внутреннее устройство хранит твои данные, даёт возможность подписываться и изменять стор.
Формы — это тот самый локальный стейт-менеджер, который уже у тебя есть.
Доклад по теме: Роутер как у сына маминой подруги — Павел Малышев
А ты как считаешь, нужны стейт-менеджеры или нет?
💯 — согласен, стейт-менеджеры не нужны
🗿 — не согласен, без стейт-менеджеров только лендинги клепать
Вообще, в Питере наступает настоящая осень: небо затянуло серой непроглядной тьмой, и единственное, что приходит на ум — «набросить на вентилятор» 😈
Так вот, давайте набросим на самое дорогое для фронтендеров — стейт-менеджеры не нужны!
Ну реально — это же нескончаемый источник хейта среди разработчиков. Зачем ещё плодить холивары?
А если немного вернуться в объективное русло, то у нас ведь всегда был самый крутой стейт-менеджер — Браузер и его адресная строка.
Всё состояние страницы можно описать прямо в URL — фильтры, сортировки, активные вкладки, выбранные элементы. Когда придёт время, приложение просто подгружает нужные данные в соответствии с этим состоянием.
🧩 В типичном фронтенд-приложении стейт обычно размазан по нескольким слоям:
* основная масса живёт на бэкенде,
* часть хранится на BFF, чтобы быстро получать данные,
* остатки — на клиенте, где мы с ними возимся.
И чтобы ничего не потерять, запускается бесконечный цикл синхронизации между этими слоями.
Пользователь изменил инпут → сработал эффект → эффект дернул ручку → запрос ушёл на BFF → там его обогатили → передали дальше → вернули ответ → разгрузили → обновили клиент...
♻️ И так по кругу.
Почему бы не сделать этот круг единым?
Есть адрес, описывающий состояние приложения → загружаешь приложение в нужном состоянии.
Что-то изменилось → обновился URL → приложение загрузило новое состояние.
Просто. Прозрачно. Логично.
Используйте для этого серверные компоненты или loader-pattern — и всё начнёт работать естественным образом, без лишнего прослойного хаоса.
📄 «А как же промежуточное состояние? Пока я не сабмитнул форму, где мне хранить данные?»
Отличный вопрос. Но тут тоже есть ответ.
Для формочек ты, скорее всего, уже используешь библиотеку — а ведь форма сама по себе и есть стейт-менеджер.
Пока ты заполняешь инпуты, внутреннее устройство хранит твои данные, даёт возможность подписываться и изменять стор.
Формы — это тот самый локальный стейт-менеджер, который уже у тебя есть.
Доклад по теме: Роутер как у сына маминой подруги — Павел Малышев
А ты как считаешь, нужны стейт-менеджеры или нет?
💯 — согласен, стейт-менеджеры не нужны
🗿 — не согласен, без стейт-менеджеров только лендинги клепать
YouTube
002. Роутер как у сына маминой подруги - Павел Малышев
Enjoy the videos and music you love, upload original content, and share it all with friends, family, and the world on YouTube.
🗿6💯3✍1🔥1
Юнит-тесты не нужны! (...больше?)
Каждый раз, когда заходит речь о тестировании, где-то обязательно всплывает пирамида тестирования — и кто-то с умным видом говорит: «юниты — это база, щегол, пиши».
Ладно, бекендеров можно понять: у них тесты давно встроены в культуру. Без них тимлид просто перестанет тебя уважать и не прожмёт апрув. Но как объяснить фронтендерам, что тесты — это не пытка, а инструмент?
С развитием фронтенд-тулинга ситуация, к счастью, меняется.
Тот же TypeScript и появление мета-фреймворков (Next.js, Remix и т.д.) превратили классическую пирамиду в кубок тестирования 🏆 — концепт от Кента Доддса.
Благодаря статической типизации можно меньше писать юнитов и сосредоточиться на интеграционных тестах — ведь именно там живут связи и самые критичные сценарии.
🔗 The Testing Trophy and Testing Classifications
«Кубок тестирования и классификация тестов» 🏆
Кент Доддс предлагает заменить пирамиду тестирования на «кубок»: меньше юнитов, больше интеграционных тестов, а E2E — как вершина уверенности в системе.
#testing #frontend #kentdodds
При этом E2E-тесты всегда остаются в меньшинстве.
Аргумент классический: дорого, долго, муторно.
Но, кажется, больше нет!
Недавно я уже писал про тулинг для LLM и про MCP — протокол взаимодействия моделей с инструментами.
Теперь представьте: вы прикручиваете браузерный движок (Playwright, Puppeteer и тд) к LLM — и модель сама заходит в браузер, смотрит страницу и пишет на неё тесты. 🤯
Так мы и сделали.
У нас был один монолит без тестов, и было страшно его трогать. Решили написать смоуки, но чисто на вайбе — через LLM.
За неделю, в неспешном режиме, всё было готово. И даже для меня — душнилы на ревью — код автотестов оказался на удивление приемлемым.
💡 Выводы после эксперимента:
Нет, полностью автоматизировать процесс без участия человека не выйдет.
Но создать гибрид человек–LLM–браузер — реально.
Ты просишь модель открыть браузер, сам выставляешь нужное состояние, а потом — просишь перевести всё это в тест.
Ваши сознания буквально сливаются, как в фильме про кайдзю 🦖: вы видите одно и то же, понимаете контекст и друг друга.
Главное — стоимость тестов реально падает.
Ты меньше устаёшь, не переключаешь режимы (писатель, наблюдатель, редактор), а код ревью всё так же может делать другой человек.
А ты что думаешь?
💯 — согласен, юниты больше не нужны, e2e и так всё покрывают
🗿 — не согласен, если каждый модуль протестирован, то и вся система норм
Каждый раз, когда заходит речь о тестировании, где-то обязательно всплывает пирамида тестирования — и кто-то с умным видом говорит: «юниты — это база, щегол, пиши».
Ладно, бекендеров можно понять: у них тесты давно встроены в культуру. Без них тимлид просто перестанет тебя уважать и не прожмёт апрув. Но как объяснить фронтендерам, что тесты — это не пытка, а инструмент?
С развитием фронтенд-тулинга ситуация, к счастью, меняется.
Тот же TypeScript и появление мета-фреймворков (Next.js, Remix и т.д.) превратили классическую пирамиду в кубок тестирования 🏆 — концепт от Кента Доддса.
Благодаря статической типизации можно меньше писать юнитов и сосредоточиться на интеграционных тестах — ведь именно там живут связи и самые критичные сценарии.
🔗 The Testing Trophy and Testing Classifications
«Кубок тестирования и классификация тестов» 🏆
Кент Доддс предлагает заменить пирамиду тестирования на «кубок»: меньше юнитов, больше интеграционных тестов, а E2E — как вершина уверенности в системе.
#testing #frontend #kentdodds
При этом E2E-тесты всегда остаются в меньшинстве.
Аргумент классический: дорого, долго, муторно.
Но, кажется, больше нет!
Недавно я уже писал про тулинг для LLM и про MCP — протокол взаимодействия моделей с инструментами.
Теперь представьте: вы прикручиваете браузерный движок (Playwright, Puppeteer и тд) к LLM — и модель сама заходит в браузер, смотрит страницу и пишет на неё тесты. 🤯
Так мы и сделали.
У нас был один монолит без тестов, и было страшно его трогать. Решили написать смоуки, но чисто на вайбе — через LLM.
За неделю, в неспешном режиме, всё было готово. И даже для меня — душнилы на ревью — код автотестов оказался на удивление приемлемым.
💡 Выводы после эксперимента:
Нет, полностью автоматизировать процесс без участия человека не выйдет.
Но создать гибрид человек–LLM–браузер — реально.
Ты просишь модель открыть браузер, сам выставляешь нужное состояние, а потом — просишь перевести всё это в тест.
Ваши сознания буквально сливаются, как в фильме про кайдзю 🦖: вы видите одно и то же, понимаете контекст и друг друга.
Главное — стоимость тестов реально падает.
Ты меньше устаёшь, не переключаешь режимы (писатель, наблюдатель, редактор), а код ревью всё так же может делать другой человек.
А ты что думаешь?
💯 — согласен, юниты больше не нужны, e2e и так всё покрывают
🗿 — не согласен, если каждый модуль протестирован, то и вся система норм
Kentcdodds
The Testing Trophy and Testing Classifications
How to interpret the testing trophy for optimal clarity
👍3💯3🗿3🤔1
Swagger не нужен!
Как часто у вас бывает, что команда разделена на бэкендеров и фронтендеров, и между ними минимум коммуникации?
Фронт пилит своё, бэк — своё, а когда приходит время интеграции, бэкендер просто кидает ссылку:
«Вот тебе Swagger, разбирайся».
И ведь поддерживать Swagger в актуальном состоянии никто не собирается 🙃
Стоит в контракте появиться новому обязательному полю или поменяться структуре — фронт падает.
И начинается классика жанра: «А что, вы не знали? Мы же в Jira написали!»
Проблема стара как REST.
Все эти попытки наладить процесс обмена знаниями о новых схемах обычно кончаются ничем — потому что знание не передаётся, пока не ломается прод.
🎯 У нас есть продукт — заказ трансферов.
Типичный кейс: аренда машины с водителем из аэропорта в отель и обратно.
Когда продукт только начинался, мы сами добавляли поставщиков:
договаривались о контрактах, согласовывали схемы данных, тестировали ручки.
За три года добавили всего четырёх поставщиков — медленно, мучительно, предсказуемо.
А потом продукт выстрелил 🚀
И мы поняли, что в таком темпе не вывезем.
Решение оказалось простым:
мы сделали reverse API — когда не мы интегрируем поставщиков, а они сами интегрируются к нам.
Потому что мы крутые 😎
Результат — 20+ новых поставщиков за следующие 3 года.
💡 И вот тогда меня осенило.
Почему фронтендеры не могут поступить так же?
Почему бы, не ждать, пока фронт упадёт из-за новой схемы, а сделать так, чтобы бэкендеры сами приходили и говорили:
«Ребята, мы сейчас будем вас ломать — вот новая схема, поддержите её».
⚙️ Как это реализовать?
Очень просто.
Пишешь автотесты (привет прошлому посту 👋), но добавляешь их не к себе в пайплайн, а в пайплайн бэкенда.
Теперь бэкенд не сможет выкатиться без твоего апрува, пока ты не подтвердишь, что фронт готов к новой схеме.
И да, если хочется избежать всей этой бюрократии — сделай все поля опциональными и не рассчитывай ни на кого. 😉
А ты как считаешь?
💯 — даёшь реактивный подход, пусть бэкенд сам просит поддержать их схему
🗿 — проактивный подход норм, мы сами будем следить за своими источниками данных
Как часто у вас бывает, что команда разделена на бэкендеров и фронтендеров, и между ними минимум коммуникации?
Фронт пилит своё, бэк — своё, а когда приходит время интеграции, бэкендер просто кидает ссылку:
«Вот тебе Swagger, разбирайся».
И ведь поддерживать Swagger в актуальном состоянии никто не собирается 🙃
Стоит в контракте появиться новому обязательному полю или поменяться структуре — фронт падает.
И начинается классика жанра: «А что, вы не знали? Мы же в Jira написали!»
Проблема стара как REST.
Все эти попытки наладить процесс обмена знаниями о новых схемах обычно кончаются ничем — потому что знание не передаётся, пока не ломается прод.
🎯 У нас есть продукт — заказ трансферов.
Типичный кейс: аренда машины с водителем из аэропорта в отель и обратно.
Когда продукт только начинался, мы сами добавляли поставщиков:
договаривались о контрактах, согласовывали схемы данных, тестировали ручки.
За три года добавили всего четырёх поставщиков — медленно, мучительно, предсказуемо.
А потом продукт выстрелил 🚀
И мы поняли, что в таком темпе не вывезем.
Решение оказалось простым:
мы сделали reverse API — когда не мы интегрируем поставщиков, а они сами интегрируются к нам.
Потому что мы крутые 😎
Результат — 20+ новых поставщиков за следующие 3 года.
💡 И вот тогда меня осенило.
Почему фронтендеры не могут поступить так же?
Почему бы, не ждать, пока фронт упадёт из-за новой схемы, а сделать так, чтобы бэкендеры сами приходили и говорили:
«Ребята, мы сейчас будем вас ломать — вот новая схема, поддержите её».
⚙️ Как это реализовать?
Очень просто.
Пишешь автотесты (привет прошлому посту 👋), но добавляешь их не к себе в пайплайн, а в пайплайн бэкенда.
Теперь бэкенд не сможет выкатиться без твоего апрува, пока ты не подтвердишь, что фронт готов к новой схеме.
И да, если хочется избежать всей этой бюрократии — сделай все поля опциональными и не рассчитывай ни на кого. 😉
А ты как считаешь?
💯 — даёшь реактивный подход, пусть бэкенд сам просит поддержать их схему
🗿 — проактивный подход норм, мы сами будем следить за своими источниками данных
😁6🗿5💯2🔥1
Мусорные npm-пакеты не нужны! (кто бы сомневался)
На этот раз даже не пришлось придумывать оправдание тейку — потому что, как водится, на всё есть свой нумероним.
🤔 Что за e18e?
Когда я впервые увидел это сокращение, у меня перед глазами пронеслись классические a11y, l10n и i18n.
А потом я узнал, что e18e расшифровывается как Ecosystem Performance — и это, внимание, движение по очистке JavaScript-экосистемы от мусора.
💡 Идея простая, но мощная:
e18e — это комьюнити, которое объединяет разработчиков вокруг идеи сделать экосистему JS легче, быстрее и чище.
Если коротко, это как обещание «убрать мусор из океана зависимостей».
Благородно, но с чего вообще начать?
🧹 Команда e18e определила три направления:
1️⃣ Clean up — убрать или заменить избыточные зависимости.
2️⃣ Speed up — ускорить популярные пакеты и фреймворки.
3️⃣ Level up — строить современные, лёгкие альтернативы старым библиотекам.
🔥 Началось всё с репозитория replacements project, где собраны community-driven альтернативы популярным пакетам.
Эти данные уже используются разными инструментами:
* ESLint-плагин, который советует, какие зависимости стоит вычистить,
* набор codemods, которые автоматически мигрируют ваш код на современные пакеты или нативные API.
Кроме того, участники e18e активно делают performance-патчи в известных JS-библиотеках и публично тегают тех, кто помогает чистить экосистему.
А ты что думаешь?
💯 – да, это благородная миссия
🗿– не уверен, что JS-экосистему можно спасти
На этот раз даже не пришлось придумывать оправдание тейку — потому что, как водится, на всё есть свой нумероним.
🤔 Что за e18e?
Когда я впервые увидел это сокращение, у меня перед глазами пронеслись классические a11y, l10n и i18n.
А потом я узнал, что e18e расшифровывается как Ecosystem Performance — и это, внимание, движение по очистке JavaScript-экосистемы от мусора.
💡 Идея простая, но мощная:
e18e — это комьюнити, которое объединяет разработчиков вокруг идеи сделать экосистему JS легче, быстрее и чище.
Если коротко, это как обещание «убрать мусор из океана зависимостей».
Благородно, но с чего вообще начать?
🧹 Команда e18e определила три направления:
1️⃣ Clean up — убрать или заменить избыточные зависимости.
2️⃣ Speed up — ускорить популярные пакеты и фреймворки.
3️⃣ Level up — строить современные, лёгкие альтернативы старым библиотекам.
🔥 Началось всё с репозитория replacements project, где собраны community-driven альтернативы популярным пакетам.
Эти данные уже используются разными инструментами:
* ESLint-плагин, который советует, какие зависимости стоит вычистить,
* набор codemods, которые автоматически мигрируют ваш код на современные пакеты или нативные API.
Кроме того, участники e18e активно делают performance-патчи в известных JS-библиотеках и публично тегают тех, кто помогает чистить экосистему.
А ты что думаешь?
💯 – да, это благородная миссия
🗿– не уверен, что JS-экосистему можно спасти
GitHub
GitHub - es-tooling/module-replacements: A manifest of JS modules and their more modern/active replacements
A manifest of JS modules and their more modern/active replacements - es-tooling/module-replacements
💯12🗿5👍1🤔1🤡1
Сегодня без набросов 🌿
Выступаю на конференции в Светлогорске – осень уже добралась и сюда 🍂
Но, как ни странно, смена обстановки реально снимает токсичность.
А ещё хотел вернуться к посту про вакансию в Островок.
Там есть приятный бонус:
— Амбассадоры компании могут бронировать отели бесплатно (в рамках командировок, конечно 😄)
— Остальные сотрудники получают корпоративные цены на отели и транспорт.
Ни на что не намекаю 😉
Всем хорошей пятницы и выходных!
Выступаю на конференции в Светлогорске – осень уже добралась и сюда 🍂
Но, как ни странно, смена обстановки реально снимает токсичность.
А ещё хотел вернуться к посту про вакансию в Островок.
Там есть приятный бонус:
— Амбассадоры компании могут бронировать отели бесплатно (в рамках командировок, конечно 😄)
— Остальные сотрудники получают корпоративные цены на отели и транспорт.
Ни на что не намекаю 😉
Всем хорошей пятницы и выходных!
🔥7❤2💯2
Есть такое ощущение, что людей, пишущих MCP-серверы, гораздо больше, чем тех, кто их реально использует 😅
Недавно попробовал новый фреймворк для написания MCP — xmcp.
На первый взгляд всё круто: удобная структура, DX на уровне, TypeScript — всё как мы любим.
Но вот UI-ресурсы не захотели дружить с новым Apps SDK от OpenAI 🤷♂️
Зато официальный SDK для MCP работает чётко, без танцев.
Видимо, пока придётся остаться на нём — а за xmcp понаблюдать, потенциал у проекта явно есть.
#mcp #openai
Недавно попробовал новый фреймворк для написания MCP — xmcp.
На первый взгляд всё круто: удобная структура, DX на уровне, TypeScript — всё как мы любим.
Но вот UI-ресурсы не захотели дружить с новым Apps SDK от OpenAI 🤷♂️
Зато официальный SDK для MCP работает чётко, без танцев.
Видимо, пока придётся остаться на нём — а за xmcp понаблюдать, потенциал у проекта явно есть.
#mcp #openai
GitHub
GitHub - basementstudio/xmcp: The TypeScript MCP framework
The TypeScript MCP framework. Contribute to basementstudio/xmcp development by creating an account on GitHub.
💯3❤1👍1
Пост для тех, кто не стал слезать с кофеиновой иглы, а решил копнуть поглубже.
Есть такое, что определённые кофейные напитки напоминают разработку.
🧊 Капучино — фронтенд-разработка
Всегда украшен латте-артом, разнообразные архитектуры, тысячи вариаций — но по факту разное количество молока.
Главная цель — сделать вкусно пользователю.
☕️ Эспрессо — бэкенд-разработка
Кратко, мощно, концентрировано.
Как и хороший backend-код — его не видно, но он делает всю тяжёлую работу.
Без украшений, без пенки и сиропов — только суть.
Требует точности: одна секунда лишнего — и вкус испорчен. Как и запрос к базе или по API.
И всё бы ничего…
Но как будто эти дескрипторы эспрессо — выдают в себе что-то фронтендерское, правда ведь? 😏
Есть такое, что определённые кофейные напитки напоминают разработку.
🧊 Капучино — фронтенд-разработка
Всегда украшен латте-артом, разнообразные архитектуры, тысячи вариаций — но по факту разное количество молока.
Главная цель — сделать вкусно пользователю.
☕️ Эспрессо — бэкенд-разработка
Кратко, мощно, концентрировано.
Как и хороший backend-код — его не видно, но он делает всю тяжёлую работу.
Без украшений, без пенки и сиропов — только суть.
Требует точности: одна секунда лишнего — и вкус испорчен. Как и запрос к базе или по API.
И всё бы ничего…
Но как будто эти дескрипторы эспрессо — выдают в себе что-то фронтендерское, правда ведь? 😏
👍2💯2🔥1
Новый Big Thing в разработке при помощи ИИ?
Anthropic представили новый подход к тому, как помочь LLM лучше понимать, чего вы от неё хотите.
Они назвали это Skills — по сути, это обычный
Например, Skill для генерации PDF содержит примеры, инструкции и рекомендации, как собирать файлы без ошибок.
LLM, видя такой файл, может выбрать нужный «скилл» и действовать по заранее описанным правилам.
🎯 Главная идея — оптимизация контекста.
Вместо огромного системного промпта «на все случаи жизни» — чёткие описания навыков, которые подгружаются по необходимости.
Что-то похожее я уже рассказывал, когда писал про memory-bank для Cursor: там IDE понимала, какие файлы ей нужны в зависимости от режима.
Теперь же — та же концепция, но уже в виде официальной реализации. Ещё один сайд-проект стал каноном.
На первый взгляд может показаться, что это калька с MCP — ведь и там есть ресурсы, помогающие LLM.
Но разница в масштабе:
* 🧩 MCP — это целый протокол, сервера и клиенты.
* 🪶 Skills — это просто файлы. Простые, лёгкие и при этом экономные по токенам.
Даже банальное переключение режимов теперь не нужно — какой-нибудь Skill Gateway сам подгрузит нужные инструкции или гайдлайны.
📎 Ссылки для погружения:
* Equipping Agents for the Real World with Agent Skills — 🌍 как Anthropic видит будущее LLM-агентов.
* Anthropic Skills overview — 🧠 подробности о формате и целях.
* Simon Willison on Claude Skills — 💬 мнение разработчика о практическом применении.
* Anthropic Skills Repo — 🛠 репозиторий с примерами «скиллов»
#ai #anthropic #claude #llm
А ты как думаешь?
💯 — согласен, новый виток в тулинге для ИИ
🗿 — не увидел ничего прорывного
Anthropic представили новый подход к тому, как помочь LLM лучше понимать, чего вы от неё хотите.
Они назвали это Skills — по сути, это обычный
md-файл, описывающий, как именно действовать в конкретной области.Например, Skill для генерации PDF содержит примеры, инструкции и рекомендации, как собирать файлы без ошибок.
LLM, видя такой файл, может выбрать нужный «скилл» и действовать по заранее описанным правилам.
🎯 Главная идея — оптимизация контекста.
Вместо огромного системного промпта «на все случаи жизни» — чёткие описания навыков, которые подгружаются по необходимости.
Что-то похожее я уже рассказывал, когда писал про memory-bank для Cursor: там IDE понимала, какие файлы ей нужны в зависимости от режима.
Теперь же — та же концепция, но уже в виде официальной реализации. Ещё один сайд-проект стал каноном.
На первый взгляд может показаться, что это калька с MCP — ведь и там есть ресурсы, помогающие LLM.
Но разница в масштабе:
* 🧩 MCP — это целый протокол, сервера и клиенты.
* 🪶 Skills — это просто файлы. Простые, лёгкие и при этом экономные по токенам.
Даже банальное переключение режимов теперь не нужно — какой-нибудь Skill Gateway сам подгрузит нужные инструкции или гайдлайны.
📎 Ссылки для погружения:
* Equipping Agents for the Real World with Agent Skills — 🌍 как Anthropic видит будущее LLM-агентов.
* Anthropic Skills overview — 🧠 подробности о формате и целях.
* Simon Willison on Claude Skills — 💬 мнение разработчика о практическом применении.
* Anthropic Skills Repo — 🛠 репозиторий с примерами «скиллов»
#ai #anthropic #claude #llm
А ты как думаешь?
💯 — согласен, новый виток в тулинге для ИИ
🗿 — не увидел ничего прорывного
Anthropic
Equipping agents for the real world with Agent Skills
Discover how Anthropic builds AI agents with practical capabilities through modular skills, enabling them to handle complex real-world tasks more effectively and reliably.
💯7🗿3👍1
Как впихнуть в LLM больше контекста? 🌐
После появления текстовых моделей логичным шагом стали мультимодальные — они могут принимать текст, изображения, голос, видео и отвечать по содержанию, которое вы им передали. Чего стоит только история, когда по рисунку на салфетке новая (на тот момент) ChatGPT сгенерировала код для приложения.
Так вот, дают ли такие модели что-то ещё кроме дополнительных каналов связи?
💸 Иногда — да. На мультимоделях можно экономить.
Слово «токен» у всех прочно связано с чисто текстовыми моделями. Но токены есть и у моделей «изображения+текст» — просто считаются они иначе. Очень-очень грубо: один токен в такой модели может соответствовать, например, патчу изображения 20×20 пикселей. Если подобрать шрифт и качество картинки, в этот «визуальный токен» можно упаковать больше текста за ту же цену, чем если бы мы кормили модель чистым текстом. Этот трюк называют оптической компрессией.
Это примерно как смотреть YouTube на скорости ×2: мозг справляется, а вы экономите время. Здесь модель «смотрит» текст как картинку и экономит токены.
Подробнее про оптическую компрессию
🧩 Should LLMs just treat text content as an image?
Короткая заметка о том, почему визуальные токены могут быть информативнее текстовых: изображение кодируется более «плотно», а значит часть задач выгоднее решать через картинку с текстом, чем через текстовые токены. Автор обсуждает компромиссы и где такой подход даёт экономию.
#multimodal #tokenization #compression
Подробно про топовые визуальные LLM
🤖 How to use frontier vision LLMs: Qwen 3 VL-2
Разбор современного Qwen 3 VL-2: как запускать, чем он хорош для OCR, анализа документов и многошагового вывода; практические примеры промптов и режимов ввода. Полезно как стартовое руководство по работе с сильной мультимодальной моделью.
#qwen
Открытые модели для OCR и пайплайны
📄 Supercharge your OCR Pipelines with Open Models
Обзор открытых OCR-стеков: как современные модели учитывают разметку страницы, когда помогает промпт-ориентированная настройка и что выбрать для документов со сложной структурой. Есть рекомендации по моделям и практические советы для продакшн-кейсов.
#ocr #opensource
После появления текстовых моделей логичным шагом стали мультимодальные — они могут принимать текст, изображения, голос, видео и отвечать по содержанию, которое вы им передали. Чего стоит только история, когда по рисунку на салфетке новая (на тот момент) ChatGPT сгенерировала код для приложения.
Так вот, дают ли такие модели что-то ещё кроме дополнительных каналов связи?
💸 Иногда — да. На мультимоделях можно экономить.
Слово «токен» у всех прочно связано с чисто текстовыми моделями. Но токены есть и у моделей «изображения+текст» — просто считаются они иначе. Очень-очень грубо: один токен в такой модели может соответствовать, например, патчу изображения 20×20 пикселей. Если подобрать шрифт и качество картинки, в этот «визуальный токен» можно упаковать больше текста за ту же цену, чем если бы мы кормили модель чистым текстом. Этот трюк называют оптической компрессией.
Это примерно как смотреть YouTube на скорости ×2: мозг справляется, а вы экономите время. Здесь модель «смотрит» текст как картинку и экономит токены.
Подробнее про оптическую компрессию
🧩 Should LLMs just treat text content as an image?
Короткая заметка о том, почему визуальные токены могут быть информативнее текстовых: изображение кодируется более «плотно», а значит часть задач выгоднее решать через картинку с текстом, чем через текстовые токены. Автор обсуждает компромиссы и где такой подход даёт экономию.
#multimodal #tokenization #compression
Подробно про топовые визуальные LLM
🤖 How to use frontier vision LLMs: Qwen 3 VL-2
Разбор современного Qwen 3 VL-2: как запускать, чем он хорош для OCR, анализа документов и многошагового вывода; практические примеры промптов и режимов ввода. Полезно как стартовое руководство по работе с сильной мультимодальной моделью.
#qwen
Открытые модели для OCR и пайплайны
📄 Supercharge your OCR Pipelines with Open Models
Обзор открытых OCR-стеков: как современные модели учитывают разметку страницы, когда помогает промпт-ориентированная настройка и что выбрать для документов со сложной структурой. Есть рекомендации по моделям и практические советы для продакшн-кейсов.
#ocr #opensource
Seangoedecke
Should LLMs just treat text content as an image?
Several days ago, DeepSeek released a new OCR paper. OCR, or “optical character recognition”, is the process of converting an image of text - say, a scanned…
👍4❤1
🎨 CSS: функции и условные стили
5 полезных CSS-функций на новом правиле @function
Уна Кравец показывает, как писать собственные CSS-функции (начиная с Chrome 139): отрицание значений, полупрозрачные цвета, fluid-типографика, условный радиус и layout-сайдбар. Функции принимают аргументы и возвращают вычисленное значение — удобно для дизайн-систем, но кросс-браузерная поддержка пока отстает.
#css #functions
Разбираемся с CSS if(): условное цветовое оформление
Автор объясняет, как
#css #if
Пользовательские функции в браузерном CSS
Мириам Сюзанн о прототипе author-defined функций, доступном в Chromium Canary с флагом Experimental Platform Features. Разбирается синтаксис (
#css #functions
🧩 Данные и сериализация
jsonriver: быстрый потоковый парсер JSON
Инкрементально парсит JSON из стрима (сетевой запрос, LLM и т. п.), отдавая всё более полные значения по мере поступления байтов. Маленький, без зависимостей, на стандартных Web API.
#json #streaming
Сериализация и десериализация — и как не «сломать» React
Практики, чтобы
#react #serialization #performance
maml.js: парсер формата MAML для JS/TS
Крошечный парсер/сериализатор для MAML JSON: 0 зависимостей, ~2 kB gz, работает в Node/Deno/Bun/браузерах. В бенчмарках существенно быстрее YAML/TOML (до ×64).
#maml #json
🛡 Безопасность npm и загрузок
pompelmi: сканер файлов для Node.js с YARA и deep-ZIP
Быстро проверяет загружаемые файлы на вредоносный код, умеет глубокий анализ архивов и встраивается как middleware для Express/Koa/Next.js и GitHub Action для CI. Акцент на приватность и минимализм.
#nodejs #security #malwarescanning
NPM Security Best Practices: защита от атак цепочки поставок
Сводка практик для разработчиков и мейнтейнеров. База – фиксируйте версии, используйте lock-файлы, отключайте lifecycle-скрипты, вводите минимальный «возраст» релиза, включайте 2FA и provenance. Охватывает npm, bun, deno, pnpm и yarn.
#npm #supplychain #bestpractices #security
npq: проверка пакетов до установки
CLI-утилита, которая до инсталла оценивает пакет по базе уязвимостей (Snyk) и эвристикам: возраст, скачивания, наличие README/лицензии, pre-/postinstall-скрипты. Можно добавить алиас на обычный
#npm #security #cli
5 полезных CSS-функций на новом правиле @function
Уна Кравец показывает, как писать собственные CSS-функции (начиная с Chrome 139): отрицание значений, полупрозрачные цвета, fluid-типографика, условный радиус и layout-сайдбар. Функции принимают аргументы и возвращают вычисленное значение — удобно для дизайн-систем, но кросс-браузерная поддержка пока отстает.
#css #functions
Разбираемся с CSS if(): условное цветовое оформление
Автор объясняет, как
if() даёт инлайновые условия прямо в декларациях css — удобно для темизации на кастомных свойствах.#css #if
Пользовательские функции в браузерном CSS
Мириам Сюзанн о прототипе author-defined функций, доступном в Chromium Canary с флагом Experimental Platform Features. Разбирается синтаксис (
@function --name() { result: … }), параметры и условные результаты.#css #functions
🧩 Данные и сериализация
jsonriver: быстрый потоковый парсер JSON
Инкрементально парсит JSON из стрима (сетевой запрос, LLM и т. п.), отдавая всё более полные значения по мере поступления байтов. Маленький, без зависимостей, на стандартных Web API.
#json #streaming
Сериализация и десериализация — и как не «сломать» React
Практики, чтобы
JSON.parse/stringify не вызывали лишние ререндеры если ваш единый источник данных это десериализованнй стейт: write-only режим и структурное шаринг-обновление через replaceEqualDeep.#react #serialization #performance
maml.js: парсер формата MAML для JS/TS
Крошечный парсер/сериализатор для MAML JSON: 0 зависимостей, ~2 kB gz, работает в Node/Deno/Bun/браузерах. В бенчмарках существенно быстрее YAML/TOML (до ×64).
#maml #json
🛡 Безопасность npm и загрузок
pompelmi: сканер файлов для Node.js с YARA и deep-ZIP
Быстро проверяет загружаемые файлы на вредоносный код, умеет глубокий анализ архивов и встраивается как middleware для Express/Koa/Next.js и GitHub Action для CI. Акцент на приватность и минимализм.
#nodejs #security #malwarescanning
NPM Security Best Practices: защита от атак цепочки поставок
Сводка практик для разработчиков и мейнтейнеров. База – фиксируйте версии, используйте lock-файлы, отключайте lifecycle-скрипты, вводите минимальный «возраст» релиза, включайте 2FA и provenance. Охватывает npm, bun, deno, pnpm и yarn.
#npm #supplychain #bestpractices #security
npq: проверка пакетов до установки
CLI-утилита, которая до инсталла оценивает пакет по базе уязвимостей (Snyk) и эвристикам: возраст, скачивания, наличие README/лицензии, pre-/postinstall-скрипты. Можно добавить алиас на обычный
npm/yarn, чтобы проверка была всегда.#npm #security #cli
🔥4👍2
OpenAI и MCP: как OAuth 2.1 решает главную проблему интеграций?
OpenAI объявила о полной поддержке Model Context Protocol (MCP) в режиме разработчика!
🤔 Что происходит?
OpenAI запустила Apps SDK — инструмент для создания приложений, которые работают прямо внутри ChatGPT. Представьте: вы пишете в чат "Найди мне квартиру в Москве до 50к", и ChatGPT вызывает приложение с картой, фильтрами и всей логикой — без перехода на другой сайт. Под капотом всё это работает через MCP.
К концу 2025 года OpenAI планирует открыть размещение приложений для всех желающих.
🧑💻 Проблема, которую все игнорировали:
Когда разработчики начали создавать MCP-серверы для продакшена, они столкнулись с неприятным вопросом: как аутентифицировать пользователей?
Цепочка выглядит так:
От чьего имени делать запросы к вашему серверу? Как понять, что пользователь действительно имеет право читать финансовые данные или создавать заказы? API-ключи работают для демок, но в продакшене это дыра в безопасности — один утекший ключ даёт полный доступ навсегда.
MCP долго не имел стандартного решения для авторизации пользователей. До тех пор, пока в спецификацию не вписали OAuth 2.1.
🗝 Почему именно OAuth 2.1
OAuth 2.1 решает сразу несколько критичных задач:
1. Scoped tokens вместо master keys
Вместо одного ключа на всё — токены с ограниченными правами (
2. Время жизни токенов
Токены автоматически истекают через заданное время. Утёк токен? Ничего страшного — через час он мёртв.
3. PKCE для публичных клиентов
ChatGPT — это публичный клиент, он не может безопасно хранить секреты. PKCE (Proof Key for Code Exchange) позволяет безопасно аутентифицироваться без встроенных паролей.
4. Dynamic Client Registration
MCP-клиенты могут регистрироваться автоматически через RFC 7591. Не нужно вручную создавать OAuth-приложения для каждого сервера — всё происходит на лету.
5. Discovery через metadata
MCP-сервер публикует метаданные по адресу
🗄 Как это работает на практике
1. Пользователь вызывает инструмент в ChatGPT
2. MCP-клиент получает 401 от сервера с указанием на metadata
3. ChatGPT динамически регистрируется на authorization server
4. Пользователь логинится через OAuth (Google, корпоративный SSO)
5. ChatGPT получает access token с нужными scopes
6. Все последующие запросы идут с заголовком
7. MCP-сервер проверяет JWT: issuer, audience, expiry, scopes.
🔗 Полезные ресурсы:
* OpenAI Apps SDK — официальная документация
* Apps SDK Authentication — про OAuth 2.1 в контексте OpenAI
* MCP Authorization Spec — полная спецификация протокола
* WorkOS MCP Auth Guide — практическое руководство с примерами кода
OpenAI объявила о полной поддержке Model Context Protocol (MCP) в режиме разработчика!
🤔 Что происходит?
OpenAI запустила Apps SDK — инструмент для создания приложений, которые работают прямо внутри ChatGPT. Представьте: вы пишете в чат "Найди мне квартиру в Москве до 50к", и ChatGPT вызывает приложение с картой, фильтрами и всей логикой — без перехода на другой сайт. Под капотом всё это работает через MCP.
К концу 2025 года OpenAI планирует открыть размещение приложений для всех желающих.
🧑💻 Проблема, которую все игнорировали:
Когда разработчики начали создавать MCP-серверы для продакшена, они столкнулись с неприятным вопросом: как аутентифицировать пользователей?
Цепочка выглядит так:
user → ChatGPT → MCP server → external API → response backОт чьего имени делать запросы к вашему серверу? Как понять, что пользователь действительно имеет право читать финансовые данные или создавать заказы? API-ключи работают для демок, но в продакшене это дыра в безопасности — один утекший ключ даёт полный доступ навсегда.
MCP долго не имел стандартного решения для авторизации пользователей. До тех пор, пока в спецификацию не вписали OAuth 2.1.
🗝 Почему именно OAuth 2.1
OAuth 2.1 решает сразу несколько критичных задач:
1. Scoped tokens вместо master keys
Вместо одного ключа на всё — токены с ограниченными правами (
read:data, write:orders). Нужны только данные? Получите токен только на чтение.2. Время жизни токенов
Токены автоматически истекают через заданное время. Утёк токен? Ничего страшного — через час он мёртв.
3. PKCE для публичных клиентов
ChatGPT — это публичный клиент, он не может безопасно хранить секреты. PKCE (Proof Key for Code Exchange) позволяет безопасно аутентифицироваться без встроенных паролей.
4. Dynamic Client Registration
MCP-клиенты могут регистрироваться автоматически через RFC 7591. Не нужно вручную создавать OAuth-приложения для каждого сервера — всё происходит на лету.
5. Discovery через metadata
MCP-сервер публикует метаданные по адресу
/.well-known/oauth-protected-resource. ChatGPT читает документ, узнаёт, какой authorization server использовать, какие scopes поддерживаются, и автоматически запускает OAuth-флоу. (То самое, "Войти через Google")🗄 Как это работает на практике
1. Пользователь вызывает инструмент в ChatGPT
2. MCP-клиент получает 401 от сервера с указанием на metadata
3. ChatGPT динамически регистрируется на authorization server
4. Пользователь логинится через OAuth (Google, корпоративный SSO)
5. ChatGPT получает access token с нужными scopes
6. Все последующие запросы идут с заголовком
Authorization: Bearer <token>7. MCP-сервер проверяет JWT: issuer, audience, expiry, scopes.
🔗 Полезные ресурсы:
* OpenAI Apps SDK — официальная документация
* Apps SDK Authentication — про OAuth 2.1 в контексте OpenAI
* MCP Authorization Spec — полная спецификация протокола
* WorkOS MCP Auth Guide — практическое руководство с примерами кода
Openai
Apps SDK
Learn how to use Apps SDK by OpenAI. Our framework to build apps for ChatGPT.
🔥5👍2
🎯 А вот и гайды для Next.js подъехали: как запустить фреймворк внутри ChatGPT
Next.js не был бы самим собой, если бы не надо было патчить нативные API. Очевидно, чтобы поддержать уровень безопасности на высоте, OpenAI пытается вставить палки в колёса злоумышленникам, но при этом страдают обычные разработчики. Чтобы ваше приложение работало в полной изоляции, Apps SDK подразумевает, что оно будет запускаться triple iframe способом. То есть
🔧 Какие с этим проблемы:
1. Triple-iframe убивает asset loading
ChatGPT рендерит приложения в трёхслойной структуре iframe'ов. Next.js думает, что его origin — web-sandbox.oaiusercontent.com, и все запросы к
Решение: assetPrefix в next.config.ts форсирует запросы на реальный домен.
2. Относительные URL ломаются везде
Изображения, шрифты, API calls — всё резолвится к sandbox-домену.
Решение: HTML
3. Browser History палит реальный домен
history.pushState сохраняет полные URL
Решение: патч, оставляющий только path + search + hash.
4. Client-side navigation делает fetch не туда
При клике на Link, Next.js делает fetch за RSC payload, но запрос идёт на sandbox-домен.
Решение: пропатчить
5. CORS блокирует React Server Components
Cross-origin запросы фейлятся без CORS headers.
Решение: Next.js middleware обрабатывает OPTIONS и добавляет CORS headers ко всем ответам.
🔗 Почитать подробнее:
* Running Next.js inside ChatGPT
* Next.js Starter Template
#nextjs #chatgpt #openai #appsdk
Next.js не был бы самим собой, если бы не надо было патчить нативные API. Очевидно, чтобы поддержать уровень безопасности на высоте, OpenAI пытается вставить палки в колёса злоумышленникам, но при этом страдают обычные разработчики. Чтобы ваше приложение работало в полной изоляции, Apps SDK подразумевает, что оно будет запускаться triple iframe способом. То есть
ChatGPT → Sandbox iframe → Inner iframe → Your app🔧 Какие с этим проблемы:
1. Triple-iframe убивает asset loading
ChatGPT рендерит приложения в трёхслойной структуре iframe'ов. Next.js думает, что его origin — web-sandbox.oaiusercontent.com, и все запросы к
/_next/static/ возвращают 404.Решение: assetPrefix в next.config.ts форсирует запросы на реальный домен.
2. Относительные URL ломаются везде
Изображения, шрифты, API calls — всё резолвится к sandbox-домену.
Решение: HTML
<base href={baseUrl}> устанавливает базовый URL для всех относительных путей.3. Browser History палит реальный домен
history.pushState сохраняет полные URL
https://your-app.vercel.app/about, что ломает sandbox security.Решение: патч, оставляющий только path + search + hash.
4. Client-side navigation делает fetch не туда
При клике на Link, Next.js делает fetch за RSC payload, но запрос идёт на sandbox-домен.
Решение: пропатчить
window.fetch, переписывая same-origin запросы на правильный base URL с mode: "cors".5. CORS блокирует React Server Components
Cross-origin запросы фейлятся без CORS headers.
Решение: Next.js middleware обрабатывает OPTIONS и добавляет CORS headers ко всем ответам.
🔗 Почитать подробнее:
* Running Next.js inside ChatGPT
* Next.js Starter Template
#nextjs #chatgpt #openai #appsdk
Vercel
Running Next.js inside ChatGPT: A deep dive into native app integration - Vercel
Next.js now runs natively in ChatGPT with working navigation, React Server Components, and full features. Learn how we made this possible behind ChatGPTs triple iframe architecture and deploy our starter template to get started.
👍5🔥1
Тайлер Виген — человек, который превратил статистический троллинг в искусство. 🖼
С 2014 года на его сайте Spurious Correlations опубликовано более 25 тысяч переменных (мемы, профессии, google-запросы, акции), которые он сравнивает между собой абсолютно все со всем. Получается 636 миллионов комбинаций. И в этом хаосе обязательно найдутся идеальные совпадения и корреляции.
Например, потребление маргарина в США коррелирует с уровнем разводов в штате Мэн с коэффициентом 0.99 — почти функциональная зависимость. Популярность мема "distracted boyfriend" коррелирует с количеством офисных клерков в Кентукки. Расстояние между Нептуном и Меркурием — с рейтингами ТВ-шоу.
Звучит как бред? Именно в этом и смысл.
📊 Что такое data dredging
Data dredging (он же p-hacking, он же data fishing) — это когда вы прогоняете тысячи статистических тестов на одном датасете и публикуете только те, что дают "статистически значимый" результат.
Виген честно пишет на сайте: "Я швыряю данные в блендер и смотрю, какие корреляции вывалятся. Это опасный способ анализа, потому что любой достаточно большой датасет даст вам сильные корреляции полностью случайно".
Понятно, что все совпадения случайны и математически некорректны, но выглядит забавно, когда просто смотришь на графики. Отличный пример для всех презентаций, которые используют графики как доказательство чего-то.
С 2014 года на его сайте Spurious Correlations опубликовано более 25 тысяч переменных (мемы, профессии, google-запросы, акции), которые он сравнивает между собой абсолютно все со всем. Получается 636 миллионов комбинаций. И в этом хаосе обязательно найдутся идеальные совпадения и корреляции.
Например, потребление маргарина в США коррелирует с уровнем разводов в штате Мэн с коэффициентом 0.99 — почти функциональная зависимость. Популярность мема "distracted boyfriend" коррелирует с количеством офисных клерков в Кентукки. Расстояние между Нептуном и Меркурием — с рейтингами ТВ-шоу.
Звучит как бред? Именно в этом и смысл.
📊 Что такое data dredging
Data dredging (он же p-hacking, он же data fishing) — это когда вы прогоняете тысячи статистических тестов на одном датасете и публикуете только те, что дают "статистически значимый" результат.
Виген честно пишет на сайте: "Я швыряю данные в блендер и смотрю, какие корреляции вывалятся. Это опасный способ анализа, потому что любой достаточно большой датасет даст вам сильные корреляции полностью случайно".
Понятно, что все совпадения случайны и математически некорректны, но выглядит забавно, когда просто смотришь на графики. Отличный пример для всех презентаций, которые используют графики как доказательство чего-то.
Tylervigen
Spurious Correlations
Correlation is not causation: thousands of charts of real data showing actual correlations between ridiculous variables.
👍5
Искать сеньера в конце 2025-го, конечно, впечатляет. Процентов 80 кандидатов на сеньорские позиции пытаются юзать ИИ прямо во время интервью. И палятся моментально. 🧠
С одной стороны, думаешь: а что если разрешить? Выкрутить сложность на максимум, типа — собери звездолёт за полтора часа, используй что угодно. Как олимпиада, где все официально на стероидах. Но в реальности с теми, кто сидит с ИИ-суфлёром, делаешь шаг в сторону — и всё, темнота. Способны только читать готовые ответы. И уже в открытую просят повторять вопросы погромче 🤡 Непонятно пока, как с этим работать.
Удивительно еще, что мидлы намного честнее. Процент жуликов ниже в разы.
Раньше на собесах спрашивали "что происходит, когда нажимаешь enter в браузере". Теперь, похоже, пора переходить на новый стандарт: "что происходит, когда сабмитишь промпт в ChatGPT".
Кстати, ByteByteGo как раз выпустили статью на эту тему — разжёвывают всю цепочку от промпта до ответа. 😉
С одной стороны, думаешь: а что если разрешить? Выкрутить сложность на максимум, типа — собери звездолёт за полтора часа, используй что угодно. Как олимпиада, где все официально на стероидах. Но в реальности с теми, кто сидит с ИИ-суфлёром, делаешь шаг в сторону — и всё, темнота. Способны только читать готовые ответы. И уже в открытую просят повторять вопросы погромче 🤡 Непонятно пока, как с этим работать.
Удивительно еще, что мидлы намного честнее. Процент жуликов ниже в разы.
Раньше на собесах спрашивали "что происходит, когда нажимаешь enter в браузере". Теперь, похоже, пора переходить на новый стандарт: "что происходит, когда сабмитишь промпт в ChatGPT".
Кстати, ByteByteGo как раз выпустили статью на эту тему — разжёвывают всю цепочку от промпта до ответа. 😉
Bytebytego
What Actually Happens When You Press ‘Send’ to ChatGPT
Behind this simple interface lies a powerful set of technologies.
😁9
🎭 Лебедь, рак и щука: три философии React
Осень в React-экосистеме как никогда напоминает басню Крылова. Next.js по-прежнему тянет к серверу, но теперь без экспериментальных флагов для новой модели кеширования, Турбопака, PPR и кучи других фичей, Remix 3 уходит к нативной веб-платформе, оставляя React позади, а TanStack Start цепляется за клиент с изоморфными лоадерами. Каждый считает, что именно его путь — единственно верный.
🐋 Next.js 16 продолжает гнуть server-first линию
Подробно тут не буду останавливаться, так как у меня есть такой пост, на сбор которого я потратил практически целый год 🥲
🦞 Remix 3: возвращение назад к веб-платформе
Представленный на Jam 2025, Remix решительно отказывается от React runtime в пользу Preact-подобного лёгкого ядра и нативных Web APIs.
Принципы:
* Web-First: события — нативные браузерные (через свою библиотеку), никакого SyntheticEvent. Все триггеры через универсальный on-проп.
* Imperative UI: вместо декларации view = f(state) — вызов this.update() после мутаций.
* Progressive Enhancement: формы работают без JS, фолбэки на нативные API.
* Архитектура островов через механизм, напоминающий работу по Iframe.
* Модульный релиз: пока фреймворк состоит из отдельных пакетов, единый пакет remix выйдет в 2026.
Remix 3 — революция, бросающая вызов идее React-фреймворка.
🦢 TanStack Start: клиент в приоритете
TanStack Start противопоставляет себя остальным как client-first решение с мощными серверными возможностями.
* Первая навигация: SSR + SEO. Дальнейшая навигация исключительно client-side с мгновенной подгрузкой данных из кеша.
* Изоморфные лоадеры: один и тот же код для SSR и навигации на клиенте, проверяющий кеш TanStack Query.
* Server Functions через createServerFn без API-слоя, type-safe end-to-end.
* Selective SSR: настраивается на каждый роут - full ssr, data-only (загружает только новые данные в кеш) или spa like
Никаких компромиссов в UX: useState, useEffect, useContext работают как в классическом SPA, не нужно задумываться, что это за компонент и будет ли в нем работать хук. React Server Components появятся опционально в v1.x, но не займут место client-first модели.
🔗 Ссылки для погружения:
* TanStack Start Introduction — введение в TanStack Start
* TanStack Start Deep Dive — глубокий анализ TanStack Start
* Thoughts on Remix 3 — обзор новой философии Remix 3
Осень в React-экосистеме как никогда напоминает басню Крылова. Next.js по-прежнему тянет к серверу, но теперь без экспериментальных флагов для новой модели кеширования, Турбопака, PPR и кучи других фичей, Remix 3 уходит к нативной веб-платформе, оставляя React позади, а TanStack Start цепляется за клиент с изоморфными лоадерами. Каждый считает, что именно его путь — единственно верный.
🐋 Next.js 16 продолжает гнуть server-first линию
Подробно тут не буду останавливаться, так как у меня есть такой пост, на сбор которого я потратил практически целый год 🥲
🦞 Remix 3: возвращение назад к веб-платформе
Представленный на Jam 2025, Remix решительно отказывается от React runtime в пользу Preact-подобного лёгкого ядра и нативных Web APIs.
Принципы:
* Web-First: события — нативные браузерные (через свою библиотеку), никакого SyntheticEvent. Все триггеры через универсальный on-проп.
* Imperative UI: вместо декларации view = f(state) — вызов this.update() после мутаций.
* Progressive Enhancement: формы работают без JS, фолбэки на нативные API.
* Архитектура островов через механизм, напоминающий работу по Iframe.
* Модульный релиз: пока фреймворк состоит из отдельных пакетов, единый пакет remix выйдет в 2026.
Remix 3 — революция, бросающая вызов идее React-фреймворка.
🦢 TanStack Start: клиент в приоритете
TanStack Start противопоставляет себя остальным как client-first решение с мощными серверными возможностями.
* Первая навигация: SSR + SEO. Дальнейшая навигация исключительно client-side с мгновенной подгрузкой данных из кеша.
* Изоморфные лоадеры: один и тот же код для SSR и навигации на клиенте, проверяющий кеш TanStack Query.
* Server Functions через createServerFn без API-слоя, type-safe end-to-end.
* Selective SSR: настраивается на каждый роут - full ssr, data-only (загружает только новые данные в кеш) или spa like
Никаких компромиссов в UX: useState, useEffect, useContext работают как в классическом SPA, не нужно задумываться, что это за компонент и будет ли в нем работать хук. React Server Components появятся опционально в v1.x, но не займут место client-first модели.
🔗 Ссылки для погружения:
* TanStack Start Introduction — введение в TanStack Start
* TanStack Start Deep Dive — глубокий анализ TanStack Start
* Thoughts on Remix 3 — обзор новой философии Remix 3
Telegram
Спасибо, я лайкнул
#all_about_rsc #rsc #react #nextjs
Про внутренности серверных компонентов:
1. Знаете, я тоже сам своего рода стример: SSR и Server Components | Антон Петров | FrontendConf
2. Абсолютно новое мышление с Server Components | АйТи Синяк
3. Making Sense of…
Про внутренности серверных компонентов:
1. Знаете, я тоже сам своего рода стример: SSR и Server Components | Антон Петров | FrontendConf
2. Абсолютно новое мышление с Server Components | АйТи Синяк
3. Making Sense of…
👍7
Директивы захватывают React-экосистему! 🎯
JavaScript годами жил с одной директивой —
Сейчас мы наблюдаем взрывной рост фреймворковых директив:
🆚 Как мы уже выяснили — TanStack выбрал путь противоположный философии Next.js и вместо директив предлагает использовать явные импорты и понятный типо-безопасный API.
🛣 К чему это может привести?
Путь Vercel/React.js/Next.js: Директивы как DX-магия. Простота для 80% случаев, vendor-оптимизация через FdI (Framework-defined Infrastructure), максимальная интеграция. Риск — lock-in и фрагментация экосистемы.
Путь TanStack: Явные API, чёткая граница платформа/фреймворк/язык, портируемость. Риск — больше бойлерплейта, медленнее внедрение и внесение в стандарт.
🔗 Ресурсы почитать/посмотреть:
* Tanner Linsley: Directives and the Platform Boundary
* Next.js 16 Directives
* Vercel's Workflow Directives
* React's 19 Directives
* This is good, actually. Theo - t3.gg
JavaScript годами жил с одной директивой —
use strict. Стандартизирована, понятна, работает везде одинаково. Чёткий контракт между языком, движками и разработчиками.Сейчас мы наблюдаем взрывной рост фреймворковых директив:
use client, use server, use cache, use workflow, use step — и это только начало. Выглядят как фичи языка, находяться на месте реальных фич языка, влияют на бандлинг и выполнение. Но это не JavaScript.🆚 Как мы уже выяснили — TanStack выбрал путь противоположный философии Next.js и вместо директив предлагает использовать явные импорты и понятный типо-безопасный API.
// Вместо директив
'use cache: remote'
const fn = () => 'value'
// Явный API
import { cache } from 'next/cache'
export const fn = cache(() => 'value', {
strategy: 'remote',
ttl: 60,
})
🛣 К чему это может привести?
Путь Vercel/React.js/Next.js: Директивы как DX-магия. Простота для 80% случаев, vendor-оптимизация через FdI (Framework-defined Infrastructure), максимальная интеграция. Риск — lock-in и фрагментация экосистемы.
Путь TanStack: Явные API, чёткая граница платформа/фреймворк/язык, портируемость. Риск — больше бойлерплейта, медленнее внедрение и внесение в стандарт.
🔗 Ресурсы почитать/посмотреть:
* Tanner Linsley: Directives and the Platform Boundary
* Next.js 16 Directives
* Vercel's Workflow Directives
* React's 19 Directives
* This is good, actually. Theo - t3.gg
Tanstack
Directives and the Platform Boundary | TanStack Blog
A Quiet Trend in the JavaScript Ecosystem For years, JavaScript has had exactly one meaningful directive, "use strict". It is standardized, enforced by runtimes, and behaves the same in every environm...
👍7❤1