ТОП - Тёма о программировани
2.79K subscribers
12 photos
1 file
55 links
Канал о программировании
Реклама - @vlad_0045
Мой личный контакт - @ngArchie

Мой ютуб канал - https://www.youtube.com/@temaProg
Download Telegram
ELIMINATING WATERFALLS

🔴 CRITICAL Impact (2–10× улучшение)

Promise.all() для независимых операций
Самое базовое и важное правило — параллелизация независимых операций

Неправильно (3 round trips):

const user = await fetchUser()
const posts = await fetchPosts()
const comments = await fetchComments()


Правильно (1 round trip):

const [user, posts, comments] = await Promise.all([
fetchUser(),
fetchPosts(),
fetchComments()
])


Мои мысли: Логичное уменьшение критического пути за счёт параллельного старта всего, что не зависит друг от друга. Важно помнить: правило применимо только к независимым запросам. Если при падении одного запроса вы всё равно можете продолжать работу — используйте Promise.allSettled().

---

Не допускайте waterfall-цепочек в API routes
Критично для серверного кода — запускайте независимые операции сразу

Неправильно (config ждёт auth, data ждёт обоих):

export async function GET(request: Request) {
const session = await auth()
const config = await fetchConfig()
const data = await fetchData(session.user.id)
return Response.json({ data, config })
}


Правильно (auth и config стартуют одновременно):

export async function GET(request: Request) {
const sessionPromise = auth()
const configPromise = fetchConfig()
const session = await sessionPromise
const [config, data] = await Promise.all([
configPromise,
fetchData(session.user.id)
])
return Response.json({ data, config })
}


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

---

Dependency-based parallelization
Продвинутая параллелизация — максимизация параллелизма при частичных зависимостях

Неправильно (profile ждёт config без причины):

const [user, config] = await Promise.all([
fetchUser(),
fetchConfig()
])
const profile = await fetchProfile(user.id)


Правильно с better-all (config и profile параллельно):

import { all } from 'better-all'

const { user, config, profile } = await all({
async user() { return fetchUser() },
async config() { return fetchConfig() },
async profile() {
return fetchProfile((await this.$.user).id)
}
})


Альтернатива без библиотеки:

const userPromise = fetchUser()
const profilePromise = userPromise.then(user => fetchProfile(user.id))

const [user, config, profile] = await Promise.all([
userPromise,
fetchConfig(),
profilePromise
])


Мои мысли: Мне ближе вариант без библиотеки — минимум магии и максимум профита. Библиотека может повышать «выразительность», но, как по мне, читаемость часто становится хуже.
👍203👀1
🟡 HIGH Impact

Defer await until needed
Условная оптимизация — await только там, где данные реально используются

Неправильно (всегда загружает permissions):

async function updateResource(resourceId: string, userId: string) {
const permissions = await fetchPermissions(userId)
const resource = await getResource(resourceId)

if (!resource) {
return { error: 'Not found' }
}

if (!permissions.canEdit) {
return { error: 'Forbidden' }
}

return await updateResourceData(resource, permissions)
}


Правильно (permissions грузим только если ресурс найден):

async function updateResource(resourceId: string, userId: string) {
const resource = await getResource(resourceId)

if (!resource) {
return { error: 'Not found' }
}

const permissions = await fetchPermissions(userId)

if (!permissions.canEdit) {
return { error: 'Forbidden' }
}

return await updateResourceData(resource, permissions)
}


Простой пример с early return:

// Неправильно
async function handleRequest(userId: string, skipProcessing: boolean) {
const userData = await fetchUserData(userId)

if (skipProcessing) {
return { skipped: true }
}

return processUserData(userData)
}

// Правильно
async function handleRequest(userId: string, skipProcessing: boolean) {
if (skipProcessing) {
return { skipped: true }
}

const userData = await fetchUserData(userId)
return processUserData(userData)
}


Мои мысли: Всё просто: если что-то можно не делать — не делайте. Либо выполните что-то более полезное, либо просто сэкономьте ресурсы. Это правило применимо во множестве ситуаций, а не только в React/фронтенде.

---

Strategic Suspense boundaries
UI-оптимизация — layout показывается сразу, данные грузятся внутри

Неправильно (весь layout ждёт данные):

async function Page() {
const data = await fetchData() // блокирует всю страницу

return (
<div>
<div>Sidebar</div>
<div>Header</div>
<div>
<DataDisplay data={data} />
</div>
<div>Footer</div>
</div>
)
}


Правильно (Sidebar/Header/Footer сразу; ждёт только DataDisplay):

function Page() {
return (
<div>
<div>Sidebar</div>
<div>Header</div>
<div>
<Suspense fallback={<Skeleton />}>
<DataDisplay />
</Suspense>
</div>
<div>Footer</div>
</div>
)
}

async function DataDisplay() {
const data = await fetchData() // блокирует только этот компонент
return <div>{data.content}</div>
}


Продвинутый вариант (несколько компонентов используют одни данные):

function Page() {
const dataPromise = fetchData() // стартует сразу, но не await

return (
<div>
<div>Sidebar</div>
<div>Header</div>
<Suspense fallback={<Skeleton />}>
<DataDisplay dataPromise={dataPromise} />
<DataSummary dataPromise={dataPromise} />
</Suspense>
<div>Footer</div>
</div>
)
}

function DataDisplay({ dataPromise }: { dataPromise: Promise<Data> }) {
const data = use(dataPromise)
return <div>{data.content}</div>
}

function DataSummary({ dataPromise }: { dataPromise: Promise<Data> }) {
const data = use(dataPromise)
return <div>{data.summary}</div>
}


Мои мысли: Правильная композиция решает огромное количество проблем — и тут мы снова упираемся в это. Организуйте интерфейс так, чтобы как можно быстрее начать отдавать пользователю его части (без перегибов). При этом важно следить за кэшем и дедупликацией: при сильном разбиении легко дернуть один и тот же запрос несколько раз — это и лишние ресурсы, и риск неконсистентного интерфейса (ответы могут отличаться). Второй вариант решения с прокидыванием проммисов в пропы мне не нравится...
👍35❤‍🔥5
Здарова, работяги!

В этой послепраздничной суете, планированиях и т. д. я совсем забыл выложить пост про «Я люблю фронтенд».

Для меня эта конфа — одна из любимых. И не только потому, что Яндекс, но и потому, что это одна из первых фронтендерских конференций, на которые я вообще попал. Поэтому стараюсь её не пропускать — как и в этот раз.

У ребят всегда всё хорошо с организацией: много весёлых активностей и бодрые доклады.

В этот раз конференция пройдёт 14 февраля — дата достаточно символическая))) Регистрация ещё открыта, так что советую поспешить.

Если будете там — пишите, буду рад пообщаться в перерыве между докладами)
111👍5🔥5🥰2
Здарова, работяги! 🤖

В одном из прошлых постов мы начали разбирать AI-скилы правильного использования реакта. Но про сам ai я так ничего и не написал. Я долго думал об, надо или нет, вроде мы тут больше про фронтенд и т. д. Пришел к следующей мысли - на текущий момент я уже слабо представляю современную фронтенд, да вообще любую разработку без ai. И нет, я не хочу сказать, что теперь ai наше всё и т. п. Можно ли жить без него? «Можно, а зачем?» Зачем пытаться упираться гнать на велосипеде, если соседи уже освоили машину. Чтобы ноги были сильные? Для этого есть тренажерный зал, можно кататься в парке и т. д. А в вопросах эффективности/КПД логика иная. Машина просто в большинстве кейсов будет быстрее велосипеда. Давайте разверну мысль подробнее...

Начну с признания - я активно использую агентов и прочее. Использую как в тимлидстве, программировании, так и в быту - приготовление еды(это топ), спорт(спасибо за подбор струн на ракетку), питание(да, я составляю рацион через ИИ, анализы стали лучше). Учитывая такой разброс кейсов, я не могу ограничиться только одним примером/сравнением/иллюстрацией. Поэтому будет два)))

1. ИИ = универсальный язык общения с миром. Мы привыкли, что иностранный язык — это английский, французский и т. д. Но на самом деле для многих разговор юристов, инженеров на русском по кол-ву понятых слов аналогичен разговору иностранцев. Что уже говорить про язык программирования и т. д. Чем тут интересен ИИ? По моему мнению, он стирает этот барьер. Теперь вы можете общаться с миром на нативном именно вам языке(с вашим контекстом) - объяснить что-то машине, получить перевод сложного документа на понятном именно вам языке и т. д. В моих глазах это революция. Очень похоже на переход от языков низкого уровня к языкам высокого. Но помните, что «переводчик» еще учится и иногда сочиняет.

2. Это новые идеешки-инструменты. Очень часто слышу это сравнение и полностью с ним согласен. Когда у меня появилась идея(я тогда еще джаву использовал), я совсем забыл про всё, что было до. И не вижу смысла возвращаться к блокнотам и прочему. Так и с ИИ. Инструменты с агентами работают в разы бодрее, поэтому возвращаться обратно совсем нет желания. Яркий пример — поиск: цель поиска — получить информацию, в большинстве случаев мне не нужен сайт, статья и т. д., мне нужна инфа.

Является ли ИИ серебрянной пулей? Не, конечно. Но и отрицать прогресс, считаю, смысла нет. Просто старайтесь применять голову, развивайте критическое мышление, будьте дотошными, перепроверяйте инфу и т. д. Помните, что ответственность несете вы: следовали советам ИИ в готовке и суп получился соленым? Да, пересолили именно вы))) С кодом аналогично.

Ну и во всей этой суматохе, как всегда, очень важен опыт, поэтому для меня сейчас особенно становятся актуальны конфы про ИИ, т. к. там можно после докладика поспрашивать спикера, подискутировать и т. д. Считаю, в текущих условиях это топ один источник инфы, т. к. очень всё молодо-зелено. В ближайшее время планирую посетить AI Dev Day, он пройдет уже 15-го числа, но там нужно регаться, поэтому не затягивайте. Если будете там — пишите, буду рад поделиться опытом)

В каком лагере вы? Делитесь опытом в комментах.
🔥16👍85🙈2
Здарова, работяги!

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

А какие модели/связки-моделей используете вы в своей работе?
Forwarded from Сиолошная
Cursor написали в своём блоге о том, как отслеживают качество моделей в написании кода. Они используют гибридный онлайн-офлайн процесс.

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

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

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

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

Онлайн и офлайн бенчмарк очень скоррелированы и имеют одинаковое ранжирование моделей (третья картинка) — в топе GPT-5.4, чуть ниже Opus 4.6 на уровне с GPT-5.2, а собственная модель компании Composer 1.5 обходит Sonnet 4.5 (при том что она гораздо быстрее за счёт инференса на чипах Cerebras).

Приятно удивлён, что пользователи Cursor так высоко оценивают модели OpenAI — но ещё здорово и то, что они требуют меньше токенов для решения задач.

Задачи CursorBench решаются в рамках одной сессии, но компания ожидает, что в течение следующего года подавляющее большинство задач по разработке будет передано агентам с длинным горизонтом планирования, работающим на своих собственных мощностях где-то в облаке — и бенчмарк придётся адаптировать к этому.
👍8
Здарова, работяги!

Сегодня принес полезный материал для тимлидов и сочувствующих. Уже совсем скоро пройдет митап Dream Teamlead.

Не на каждой конфе набирается такой бодрый набор спикеров, как тут. Особенно хочу отметить:

• Евгений Антонов(Тимлид Очевидность) — читаю его канал(@general_it_talks), слушаю подкаст — всем рекомендую, очень крутые материалы.

• Александр Поломодов — один из лучших каналов(@book_cube) на русском языке(по моему скромному мнению). Рекомендую не только лидам, но и инженерам. Огромное кол-во материалов про лидерство, систем-дизайн, AI и т. д.

По традиции, если будете там и захотите пообщаться — пишите в лс
4👍3🔥3
Композер 2 только вышел, и уже угодил в скандал. Пупупум....
2
Forwarded from эйай ньюз
Похоже Composer 2 — это украденная Kimi 2.5

Сразу после выхода Composer 2 пользователи заметили что модель на эндпоинте называется kimi-k2p5-rl-0317-s515-fast, а чуть позже пошли (ныне удалённые) шокированные твиты от команды Kimi — по их словам они ничего не знали об использовании Cursor их весов. И раньше ходили слухи что оригинальный Composer был основан на китайской модели — GLM 4.6, так что прецедент такого "ребрендинга" есть, но там ситуация отличается.

Дело в лицензии — если GLM лицензирована по MIT, то у Kimi 2.5 лицензия более сложная — подобные к лицензии MIT права она даёт только до 100 миллионов пользователей продукта или 20 миллионов выручки в месяц. То есть тюн GLM не нарушал лицензию оригинальных весов, а тюн Kimi — нарушает.

Ситуацию обостряет конфликт Anthropic с авторами Kimi — компания обвиняет Moonshot в использовании более чем 3.4 миллионов запросов для дистилляции. Возможно руководство Cursor решило, что из-за собственных проблем с данными, Moonshot не отважится подать на них в суд и им за это ничего не будет.

Достаём попкорн и наблюдаем за ситуацией

@ai_newz
👍141🔥1
Здарова, работяги!

У меня сложилось впечатление, что в сообществе есть определённая путаница на тему мемори-банков, рулсов, MCP и скиллов. Поэтому сегодня хочу поговорить с вами именно на эту тему.

Начнем с определений.

Memory bank — это внешняя память агента о проекте или пользователе.
Туда обычно кладут долгоживущий контекст: архитектурные решения, договорённости, особенности проекта, вкусы команды, важные факты, которые агент должен помнить между сессиями.
По сути, это способ не объяснять одно и то же заново в каждом чате.
Memory bank как “папка с простынями контекста, которую агент должен перечитывать перед работой” — почти устаревший паттерн.

Rules / рулсы — это инструкции для агента, которые задают рамки его поведения.
Например: “используй только pnpm”, “не трогай файлы миграций”, “компоненты называем через PascalCase”, “перед изменением API сначала предложи план”.

MCP — это протокол, через который агент подключается к внешним инструментам и данным.
Например, к GitHub, Jira, Figma, базе данных, Sentry, файловой системе, внутренним сервисам компании.
MCP превращает агента из “чата, который умеет писать текст” в участника рабочего процесса, который может ходить в нужные системы и получать оттуда контекст.

Skills / скиллы — это переиспользуемые сценарии работы агента под конкретные задачи.
Например: “как делать code review”, “как заводить новый пакет в монорепе”, “как писать тесты в этом проекте”, “как оформлять PR”.

Если совсем коротко:
Memory bank хранит контекст.
Rules задают правила поведения.
MCP даёт доступ к инструментам.
Skills описывают рабочие сценарии.

Использовать агента без них сейчас нет совершенно никакого смысла, качество его работы драматически падает без них. Но нужны ли прям все эти инструменты?
Сейчас всё больше фокус смещается в сторону связки rules и skills.

Rules играет роль закона: они всегда в силе и задают рамки, которые агент не должен нарушать. Агент держит их в контексте всегда.

Skills работают как инструменты: агент знает, что они есть и когда их применять, но не держит их целиком в контексте постоянно.
Нужен code review — достал skill для review.
Нужно завести новый пакет — достал skill для этого сценария.

Окей, с теорией разобрались. Давайте попробуем теперь написать алгоритм выбора инстурмента.

Я бы шёл в таком порядке.

1. Сначала линтеры, форматтеры, тесты, типы и скрипты
Если правило можно проверить автоматически, лучше проверять его автоматически. Не надо забивать микроскопом гвозди.
Линтер не забудет, не потратит токены и не начнёт “творчески интерпретировать” инструкцию.

2. Потом skills
Если речь не про жёсткую проверку, а про сценарий действий, лучше оформить это как skill.
Например: как делать code review, как заводить новый модуль, как расследовать падение CI, как готовить релиз.
Skill хорош тем, что не висит в контексте всегда. Агент знает, когда его доставать, и подтягивает подробную инструкцию только под конкретную задачу.

3. И только потом rules
Rules стоит использовать для того, что должно ограничивать агента всегда и не может быть надёжно выражено через автоматику или skill.
Они самые дорогие, потому что постоянно занимают место в контексте и влияют на каждую задачу, даже если конкретно сейчас это правило не нужно.

Резюмируя
• Если можно зашить в автоматику — зашиваем в автоматику.
• Если это сценарий — пишем skill.
• Если это постоянный инвариант, который агент обязан помнить всегда — пишем rule.

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

Интересно ли вам было бы почитать про то, как я пишу скиллы для своих проектов, какие там есть фишки и особенности?
133👍15🔥12😎3🥱1
Воскресенье, 3 мая — последний день подачи тестовых в Летние школы

Здарова, работяги!

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

Главное о школах:

1️⃣ Направления: бэк (C++ и Java), мобилка (iOS и Android), фронтенд и фулстек, аналитика

2️⃣ Занятия очно в июле и августе в московском офисе. Программа насыщенная, но не помешает учёбе, работе и просто отдыху

3️⃣ Ограничений по возрасту, вузу, ступени обучения — нет. Ждём всех, кто справится с отбором и готов поучиться летом, а осенью выйти на стажировку

4️⃣ Планируем Школы на 400 человек — тебя ждёт широкий нетворк и плотная работа с ментором

5️⃣ В программе собрали всё самое прикладное: актуальные технологии и подходы, практические домашки, командную работу над проектами, хакатоны, публичные выступления и вечеринки!


Важная инфа: до 3 мая ждём и заявки, и выполненное тестовое — оно приходит на почту сразу после регистрации.

@Young_and_Yandex
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥2
Здарова, работяги!

В прошлый раз разобрались, чем отличаются memory bank, rules, MCP и skills, и сошлись на том, что основной фокус сейчас — связка rules + skills. Сегодня — как я пишу скилы: что стоит оформлять, что нет, и на что обращать внимание.

Коротко напомню разницу

Rules — правила, которые агент держит в контексте всегда и применяет на каждой задаче.
Skills — переиспользуемые сценарии. Агент знает, что они есть и когда их доставать, но не держит целиком в контексте.

Две главные мысли

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

Вторая: скилы не пишем впрок.
Отношусь к ним как к коду — пишу по мере необходимости. Со временем набирается своя база, и появляется чувство:
• какие скилы я всегда тащу в новый проект, потому что они проверены опытом;
• какие подключаю ситуативно — например, для React-проекта имеет смысл взять скилы Vercel про React(но не все);
• какие пишу с нуля под конкретные грабли, которые увидел в работе агента.

Скилл «на будущее» обычно не попадает в реальные сценарии и просто висит балластом. А если их много, агент хуже выбирает нужный и описания начинают конфликтовать. Поэтому: увидел поведение, которое не устраивает → если ответ «скилл», только тогда написал.

Алгоритм: что делать, когда хочется добавить guidance

1. Это уже покрыто? Существующий skill, rules, системный промпт, линтер. Если да — обновляю существующее, а не плодю новое.
2. Можно ли решить тулзами? Линтер, тайпчек, скрипт, кодген. Если правило детерминированное — заводим автоматику. Скилл тогда максимум объясняет, что делать поверх тулзы.
3. Это всегда или ситуативно? Всегда и на каждой задаче — rule. Под конкретный тип задач (ревью, новый пакет и тд) — skill.

Как писать сам скилл

Description — самое важное. Агент видит только description в списке доступных скилов и по нему решает, доставать его или нет. Должно быть два блока:
• WHAT: что скилл делает.
• WHEN: триггеры — слова, контексты, типы задач.
Плохо: «помогает с тестами».
Хорошо: «как писать тесты в проекте. Используй при написании, добавлении или рефакторинге test-файлов. Триггеры: ‘написать тест’, ‘покрыть тестами’, ‘тесты падают’».
SKILL.md держу коротким. Ориентир — до 100 строк. Что не влезает — выношу в отдельные файлы и линкую из основного. Глубже одного уровня ссылок не делаю — агент может просто не дочитать.
Прогрессивное раскрытие. В SKILL.md — то, что нужно в 80% случаев. Детали и редкие сценарии — в отдельные файлы.
Один путь, а не пять вариантов. Если в скиле «можно вот так, или вот так» — агент каждый раз выбирает заново и каждый раз по-разному. Даю дефолт и явный запасной вариант для редких случаев.
Конкретные примеры. «Вот вход, вот выход» работает в разы лучше, чем абзац объяснений.
Скрипты вместо генерации. Детерминированную операцию лучше положить готовым скриптом и вызвать, чем описывать «сгенерируй такой-то код». Скрипт надёжнее и не жрёт токены на генерацию.

Резюме
• Сначала пробуем тулзы, потом скилы, в последнюю очередь — rules.
• Скилы не пишем впрок, только по факту.
• В самом скиле: подробное description с WHAT и WHEN, короткий SKILL.md, один путь, конкретные примеры, скрипты для детерминированных операций.

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

В следующий раз могу показать свою личную подборку скилов — глобальные и те, что чаще всего беру в новые проекты. Интересно?
1🔥381👍1
Пост фана и чутка рекламы 🚶

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

В какой-то момент я смирился: ну, видимо, город такой. Сконцентрировался на учёбе, потом на работе.

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

Сейчас я уже совсем не могу надолго уехать: быстро начинаю скучать. Обожаю осень, весну и лето в Москве. Зиму, правда, так и не полюбил 😄

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

Яндекс решил организовать один из таких форматов — «Рекурсия по городу»: командное офлайн-приключение в формате CTF. Будет 35+ заданий по маршруту через точки, связанные с историей российской IT-индустрии: в том числе через территорию МГУ, центр фундаментальных исследований РАН и другие места.

Старт — в одной из моих любимых локаций: штаб-квартире Яндекса в «Красной Розе».

Если вам тоже интересны такие активности, переходите по ссылке и регайте команду
10🔥6🥰3👍2
Здарова, работяги!

В прошлый раз говорили про скилы. Сегодня — про линтеры и форматтеры: как я выбирал стек на новом проекте, почему сначала взял Biome и почему переехал на oxlint + oxfmt.

Почему про линтеры

Как уже писал, прежде чем тащить guidance в скилы и рулы, стоит посмотреть, нельзя ли закрыть это автоматикой. Линтер — бесплатный детерминированный гейт: не забывает, не интерпретирует, не жжёт токены. Особенно ценно при работе с агентом — каждое правило в линтере = минус один пункт в guidance и минус один способ облажаться.

Что было на столе

— ESLint + Prettier — максимум правил и плагинов, но два тула, медленно, конфигурить долго.
— Biome — один тул на всё (lint + format + import sort), быстрый, конфиг простой.
— oxlint + oxfmt — Rust-стек от oxc: быстрый линтер с большим покрытием ESLint-правил и отдельный форматтер.

Сравнение коротко

— Скорость: oxlint > Biome >> ESLint+Prettier.
— Количество тулов: Biome — один. oxlint + oxfmt и ESLint + Prettier — два, но oxlint + oxfmt живут в одной экосистеме и конфигурятся проще.
— Покрытие правилами: ESLint — максимум. oxlint — большая часть популярных ESLint-правил, пул растёт. Biome — свой набор, заметно уже.
— Конфигурируемость: ESLint — максимум. oxlint — гибко, overrides, плагины. Biome — намеренно ограничено.
— Экосистема: ESLint — всё. oxlint — догоняет, ключевые плагины (react, typescript, import) уже есть. Biome — самодостаточно, плагинов нет.

Почему сначала взял Biome

Просто, быстро, один тул. На старте проекта это закрывает 90% потребностей с нулевой настройкой.

Почему слез

Пожил пару недель и понял, что правил банально не хватает.

— Нет аналога consistent-type-assertions. Запрет as SomeType — критичное правило, потому что агенты обожают кастить типы вместо того, чтобы написать type guard или поправить сигнатуру. Без линтера это ловится только на ревью, и то не всегда.
— Слабый no-restricted-imports. Хотелось паттернами фиксировать границы модулей в монорепе — в Biome либо никак, либо очень куцо.
— Нет react/no-multi-comp и подобных мелочей, которые модель регулярно норовит нарушить.
— overrides по glob сильно ограничены, не получается тонко настроить правила под разные части репы.

В итоге половину инвариантов пришлось бы тащить в AGENTS.md как текстовое правило — а это ровно то, чего стараюсь избегать.

Переход на oxlint + oxfmt

— Все важные ESLint-правила, которых не хватало, есть из коробки.
— overrides по glob позволяют жёстко зафиксировать границы между приложениями и пакетами в монорепе.
— Скорость на уровне Biome, на больших прогонах даже лучше.
AGENTS.md похудел: куча пунктов уехала в линтер.

Форматтер (oxfmt) пока проще биомовского, но мне его хватает.

Резюме

— При работе с агентами линтер обязателен.
— Biome — отличный выбор для небольших проектов, пока хватает встроенных правил.
— ESLint + Prettier сейчас не вижу смысла брать: медленнее, конфигурить дольше, а у oxlint уже хорошее покрытие правил.
— oxlint + oxfmt — мой текущий дефолт.
127🔥74👍4
Интересен ли вам еще формат видео(утуб, вквидео и тд) или лучше сконцентрироваться на тг?
Anonymous Poll
83%
Да 🤓
17%
Нет, лучше больше постов в тг 🤬
🍌2
Здарова, работяги!

Сегодня разберёмся, в чём боль code-first, что меняет schema-first и как это выглядит в Fastify.

Code-first

Правила формы данных живут в коде, рассыпанные по разным местам. Валидация — отдельная функция. Типы — отдельный интерфейс. Обе сущности — копии одной и той же правды в разных синтаксисах.

Знакомая картина — ручная валидация формы:


function validateUserForm(values) {
const errors = {}
if (!values.email) errors.email = 'required'
if (!values.age || Number.isNaN(+values.age)) errors.age = 'must be number'
return errors
}

// где-то рядом
type UserForm = { email: string; age: number }


Два источника правды на одну сущность. Один обновил — другой забыл. Дальше прод, неприятный сюрприз, разбор полётов в Slack.

Schema-first

Подход, при котором описание формы данных живёт отдельно от бизнес-логики и является источником правды. Описываем форму декларативно — например, объектом JSON Schema. Дальше из этого объекта получаются:

— валидация входа (запрос проверяется по схеме до того, как попадёт в обработчик);
— сериализация выхода (ответ режется по схеме, лишние поля не уйдут наружу);
— TypeScript-типы (генерятся из схемы — например, через TypeBox или json-schema-to-ts).

Одна декларация — три артефакта. Обновил схему — всё остальное само догнало.

Как это в Fastify

Fastify построен вокруг schema-first из коробки. Минимальный пример:


const schema = {
body: {
type: 'object',
required: ['email', 'age'],
properties: {
email: { type: 'string', format: 'email' },
age: { type: 'integer' }
},
additionalProperties: false
},
response: {
201: {
type: 'object',
properties: {
id: { type: 'integer' },
email: { type: 'string' }
}
}
}
}

fastify.post('/users', { schema }, async (req, reply) => {
const user = await db.users.insert(req.body)
reply.code(201).send(user)
})


Что мы получили бесплатно:

— request body валидируется до обработчика. Невалидный — 400 с понятным сообщением, обработчик даже не дёргается;
— response сериализуется по схеме. Если в user внезапно прилетело password_hash — он не уйдёт наружу. Это и про безопасность, и про предсказуемость контракта;
— additionalProperties: false режет лишние поля на входе. Прислали лишнее — до обработчика оно не доедет. Если хочется именно 400, это уже настраивается через Ajv.

Бонусом — скорость

Под капотом сериализация ответа идёт не через JSON.stringify, а через fast-json-stringify: на старте по response-схеме компилируется специализированная функция, и дальше она работает в разы быстрее (в бенчах самой библиотеки — до 2x на типовых ответах). JSON.stringify каждый раз обходит объект на ходу и не знает заранее, какие поля в нём окажутся. fast-json-stringify знает структуру и идёт почти прямым проходом по известным полям. Платим за это одной компиляцией на старте — копейки.

Дока Fastify.

Резюме

— schema-first даёт один источник правды — декларацию данных, из которой вытекают валидация, сериализация и типы;
— code-first проще на старте, но копии одной правды быстро расходятся, и это всегда вылазит больно;
— в Fastify это работает из коробки, плюс бонусом сериализация в разы быстрее обычного JSON.stringify.
1🔥203👍3🍌2
Здарова, работяги!

Около четырёх лет назад я прочитал лекцию React(продвинутый) в ШРИ. Там был большой разбор про то, как React работает под капотом.

Лекция неожиданно для меня хорошо зашла: я-то её планировал на аудиторию студентов ШРИ, а получилось 92к просмотров. До сих пор люди иногда пишут, что именно после неё у них щёлкнуло понимание React, и это меня сильно мотивирует.

Потом я надолго почти перестал писать про React.
Причина простая: я несколько лет преподавал React, не только в ШРИ, и в какой-то момент накопилась усталость скорее от преподавания, чем от самой темы.

А пока отдыхал, React взял и уехал вперёд.

Что осталось прежним
Главная база из той лекции не умерла.

React всё ещё не “просто меняет DOM”. Он строит work-in-progress дерево, сравнивает его с текущим деревом, готовит изменения и потом коммитит результат.

Ререндер всё ещё не равен “браузер перерисовал весь экран”.

key всё ещё влияет на то, считает ли React компонент “тем же самым” между рендерами.

Ремаунт всё ещё может внезапно стереть локальный state.

Фаза коммита всё ещё не то место, где React может спокойно сказать: “ой, браузер занят, я продолжу позже”. Если дошли до применения изменений — надо применять.

То есть если вы тогда поняли идею current tree и work-in-progress tree, это знание не превратилось в тыкву.

Но сменился фокус
Раньше React часто объясняли через Virtual DOM.

Мол, React строит виртуальное дерево, сравнивает с прошлым, находит разницу и аккуратно обновляет настоящий DOM.

Как первая ступенька — норм. Как полная модель — уже слабовато.

Современный React всё меньше хочется объяснять через “сравнение деревьев” и всё больше через планирование работы.

Не просто:
— что изменилось;
— какой компонент ререндерится;
— сколько DOM-нод надо обновить.

А ещё:
— срочная это работа или нет;
— можно ли её прервать;
— можно ли показать старый UI, пока новый готовится;
— можно ли часть работы сделать на сервере;
— можно ли вообще не делать ручную мемоизацию, потому что её заберёт Compiler.

Вот это, по моему ощущению, главный сдвиг последних лет.

React стал не только библиотекой для описания UI. Он всё больше становится runtime-ом, который управляет тем, когда, где и с каким приоритетом этот UI должен появиться.

В старой лекции был классический пример:
родитель хранит count, рядом лежит тяжёлый ChildVerySlow, нажимаем кнопку — и внезапно страдает вообще не тот компонент, который визуально поменялся.

Решения тогда были понятные:
— изолировать state ближе к месту использования;
— не поднимать состояние без причины;
— следить за ремаунтами;
— аккуратно использовать React.memo;
— профилировать, а не гадать по ощущениям.

И это всё ещё хорошие советы.
Но теперь этого слоя знаний уже недостаточно.

React 18 принёс автоматический батчинг и конкурентный рендеринг. Появились startTransition и useDeferredValue. Suspense перестал быть просто красивой обёрткой вокруг lazy. Server Components поменяли вопрос с “как быстрее отрендерить на клиенте” на “а должна ли эта работа вообще попасть на клиент”. React Compiler начал двигать нас в сторону мира, где часть ручного memo, useMemo и useCallback становится внутренней заботой React, а не обязательной ручной работой разработчика.
Не магия. Не “теперь можно не думать”. Скорее наоборот: думать надо глубже и немного о другом.

Поэтому я хочу сделать серию постов про современный React через призму той старой лекции.
Не “что нового в React 18/19” списком из ченджлогов. А нормально, по-работяжьи:
— что из старой модели всё ещё держится;
— где старые объяснения стали слишком грубыми;
— как батчинг, транзишены и отложенный рендеринг меняют разговор про ререндеры;
— почему Suspense теперь не только про React.lazy;
— зачем нужны Server Components и почему use client нельзя расставлять на автопилоте;
— что React Compiler меняет в привычке мемоизировать всё руками.

Короче, будем снова залезать под капот React. Только уже не того React времён “хуки ещё выглядят свежей штукой”, а React, который пытается управлять всей жизнью интерфейса: от серверной работы до срочности обновлений на клиенте.
5🔥113👍2013🦄3🙏2
«Кто-то должен был это сказать!» — эта мысль не покидала нас, пока слушали новый сезон подкаста «Свободный слот» 🌟

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

А ещё у ребят есть канал — там они делятся мыслями, которые не попали в выпуски, полезными статьями и анонсами митапов. Очень советуем заглянуть!
Please open Telegram to view this post
VIEW IN TELEGRAM
4🤮2👍1👏1👌1
Здарова, работяги!

Продолжаем про React.

Если бы я сейчас пересобирал старую лекцию про React, я бы начал не с FPS.

Тогда я заходил через плавность интерфейса: пользователь нажал кнопку, ввёл текст, открыл попап — интерфейс должен ответить без подвисаний.

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

Старый заход

В той лекции я шел через 60 FPS.

Идея простая: между двумя кадрами у браузера очень мало времени. Если JS надолго занял поток, браузер не успел отрисовать следующий кадр — интерфейс дёрнулся.

Это не устарело. Просто 60 FPS — слишком грубая рамка, если на ней остановиться.

Fiber в этой истории был ответом на проблему: React перестал воспринимать рендер как один большой кусок работы. Новое дерево можно готовить частями, а не в режиме «начали — теперь все ждут».

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

Но как объяснение современного React этого уже мало.

Чего здесь не хватает

Проблема не только в том, сколько работы делает интерфейс. Проблема ещё и в том, какая это работа.

Пользователь печатает в инпуте — символ должен появиться сразу. Иначе это ощущается не как «рендер не успел», а как сломанная клавиатура.

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

Раньше мы почти всегда упирались в один совет: сделай работу быстрее. Профилируй, мемоизируй, выноси state ближе к месту использования.

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

Что изменилось в модели

Современный React всё меньше похож на прослойку для обновления DOM и всё больше — на механизм управления работой интерфейса.

Не только:
— что изменилось;
— какие компоненты надо пересчитать;
— какие DOM-изменения потом применить.

А ещё:
— что должно ответить сразу;
— что можно подготовить в фоне;
— что можно прервать и начать заново;
— что вообще лучше не тащить на клиент.

Вот почему старая рамка 60 FPS стала тесной.

Пример такой фичи

startTransition — просто самый наглядный пример этой идеи.

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

Но это не пост про startTransition. Для него нужен отдельный разбор.

Важно отметить, что transition не делает медленный код быстрым. Синхронный фильтр на десять тысяч строк React не превратит в фоновую магию.

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

Как я бы объяснял сейчас

Раньше я бы больше давил на то, как React сам организует рендер: строит новое дерево, может прервать подготовку, потом одним куском коммитит результат.

Сейчас я бы добавил второй слой: разработчик тоже всё чаще участвует в разговоре о приоритетах. Что должно ответить сразу. Что можно подготовить позже. Где показать старый экран, пока новый ещё собирается.

Разница в формулировке маленькая, а в голове большая.

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

Вот это, по-моему, и есть главный сдвиг.

Резюме

— ограничение по времени на кадр всё ещё актуально, но это не вся история;
— современный React удобнее объяснять через вопрос: что делать сейчас, а что позже;
— React и раньше управлял рендером, но теперь разработчик чаще явно участвует в выборе приоритетов;
— главный вопрос теперь не только «как сделать меньше работы», но и «что пользователь должен увидеть сразу».
3🔥26👍112