Стало возможно сэкономить до 60% токенов при использовании нейросети Fable 5 — представлен способ доработать ИИ-систему и платить Anthropic в разы меньше.
Инструмент pxpipe берёт полотна промптов и превращает их в картинку. При считывании изображений платить приходится за каждый обработанный пиксель, а не за буквы на нём, благодаря чему метод куда выгоднее. В демо автору удалось выполнить ту же задачу, что и обычным промптом, но в 7 раз дешевле: за $6 против $42. При этом Fable идеально считывает текст на картинках, несмотря на сжатие. В 39 протестированных картинках нейронка Anthropic безошибочно поняла весь промпт.
Ранее разработчики обратились к специализированному инструменту Caveman, который заставляет ИИ генерировать максимально краткие ответы с имитацией стиля речи «пещерного человека». Автор инструмента Джулиус Брюсси в своё время обратил внимание на то, что значительная часть бюджета компаний расходуется на «болтовню» языковых моделей. Caveman удаляет из ответов чат-ботов слова-связки, приветствия и вводные конструкции, сохраняя программный код, команды, URL-адреса и технические детали.
Хотел просто тестировать свои OTP, а выкинул почтовый сервер
Я пилю штуки, где есть регистрация и 2FA. И регулярно упираюсь в одно и то же. Чтобы проверить, что письмо с кодом доходит и парсится на фронте правильно, мне на каждый прогон нужен свежий ящик. Заводить настоящие почты муторно. Сервисы временной почты это отдельная боль: их выпиливают, лимитируют, суют рекламу, а код то приходит через три минуты, когда он уже не нужен, то не приходит вовсе. В какой-то момент надоело.
И тут дошло, что задача сформулирована неправильно. Мне не нужен ящик. Мне нужно поймать одно входящее письмо и достать из него код. А для этого почтовый сервер не нужен вообще.
Приёмник почты без приёмника почты
Cloudflare Email Routing бесплатно ловит catch-all на мой домен и отдаёт письмо прямо в Worker, в email()-handler. Не пересылкой на другой ящик, а сырым письмом в код. Ни sendmail, ни Postfix, ни IMAP-поллинга. MX поднимается за меня, я только пишу обработчик.
Дальше то, ради чего я, собственно, и сел писать. Приём держит Email Routing. Доставку готового результата мне в чат держит Telegram Bot API. И то, и другое это инфраструктура, которую я не админю. На выходе рабочий транспорт для входящей почты без единого своего сервера, без SMTP, без IMAP и без своего IP, который можно потерять под блокировкой.
По команде /start выдаётся адрес, вставляешь куда надо, письмо падает в чат. Адрес живёт сутки и умирает сам.
Самое интересное это достать код
Транспорт собирается за вечер. Реальная инженерия начинается там, где из произвольного письма надо надёжно вытащить именно код. Потому что «код» в письме конкурирует с номером заказа, годом, куском телефона, суммой, id внутри ссылки. Наивное «первые шесть цифр» хватает мусор примерно в половине случаев.
Поэтому не регэксп в лоб, а скоринг. Сначала нормализую тело: срезаю шапки пересылки, невидимый мусор, превращаю Текст <url> в нормальные ссылки, иначе скорер спотыкается об id из урлов. Потом собираю кандидатов: цифровые и буквенно-цифровые последовательности правдоподобной длины, от 4 до 8 символов. И раздаю баллы.
Вверх:
близость к триггерам: код, code, verification, OTP, подтвержд…;
стоит на отдельной строке;
выделен жирным или моноширинным.
Вниз, анти-паттерны:
похоже на год (19xx/20xx);
похоже на телефон;
стоит после заказ/order;
сидит внутри ссылки;
рядом знак валюты.
Кто набрал больше, тот и код. Уезжает в первую строку сообщения, тап, скопировал. Вот эта часть и заняла итерации, остальное обвязка.
Честные границы
Чтобы не выглядело рекламой бесплатного волшебства, сразу про ограничения.
Сервис эфемерный by design. Сутки, и адреса нет. На стороне бота ничего не хранится: письмо разбирается на эдже и улетает в чат, где живёт уже у тебя. Это не замена нормальной почте, а одноразовый ящик под отлов кодов.
Inbound-only. Отправить с него нельзя. Под мою задачу, тестировать собственные флоу, этого ровно достаточно.
И про экономику честно. Лично мне бесплатного тира хватало за глаза. Но KV на free это 1000 записей в сутки, и стоило решить сделать из поделки сервис для братьев по клаве, как квота на записи кончилась. Так что перед тем как открыть доступ наружу, я доплатил за Workers. «На чужой инфре» это правда, но не «бесплатно из воздуха»: транспорт всё равно стоит пять долларов в месяц.
Итог
Завернул в опенсорс: https://github.com/investblog/mailbot. Если тоже гоняешь регистрации и 2FA и устал от рулетки временной почты, может пригодиться целиком. А нет, забирай хотя бы скоринг OTP к себе, он отвязан от Telegram и переносится легко.
Оказалось: агент перегружается и начинает игнорировать правила избирательно. Мой CLAUDE.md вырос до 8000 слов и стал работать хуже чем на 2000. Теперь: конкретные примеры из кода вместо абстрактных запретов. «Вот как мы делаем, вот что сломалось в прошлый раз» бьёт «никогда не используй X» в любой ситуации.
Я думал: агент выполнит то что попросили
Оказалось: агент соглашается с задачей, но реализует по-своему. Особенно на архитектурных решениях. Промпт строже не помогает. Помогают примеры из нашей кодовой базы. 200к строк TypeScript как контекст работают лучше любого правила.
Я думал: контекст это просто «открытые файлы»
Оказалось: когда агент начинает галлюцинировать — задача слишком большая. Контекст это не «открытые файлы», а активное управление объёмом. Теперь делю на подзадачи до старта, а не когда уже сломалось.
Я думал: skills это просто промпты в файлах
Оказалось: skills это lazy-loading для контекста. Агент подтягивает только то что нужно для конкретной задачи. После перехода с монолитного CLAUDE.md на skills расход токенов за сессию упал на 30–40%. И точность выросла, меньше лишнего в голове.
Я думал: AI-ревью заменит рутину
Оказалось: агент хорошо видит синтаксические и логические ошибки, но пропускает архитектурный дрейф. «Код работает, но растёт не туда» он не замечает. Human-in-the-loop на архитектурных решениях: не опция.
Через N месяцев Claude Code перестаёт быть инструментом для разовых запросов. Он становится партнёром. Общий язык: примеры из кода, границы модулей, точки где ты проверяешь а не доверяешь.
archkit v0.1 — генератор TypeScript-библиотек с Clean Architecture: от спека до npm за один день
Неделю назад опубликовал на npm первый пакет, @autosergach/archkit. Одна команда:
npx @autosergach/archkit create my-lib
И получаешь TypeScript-библиотеку с Clean Architecture из коробки: domain, application, ports, рабочий use case и пять зелёных тестов. Не «hello world», а каркас который показывает как слои должны выглядеть. Ниже как это устроено и четыре грабли по дороге к npm publish.
pnpm install && pnpm test, пять зелёных с первого запуска. Стек намеренно современный: ESM only, Node 20+, TypeScript 5.7+, vitest 3.2, eslint 9 flat config.
Архитектура изнутри
Забавно, что archkit изнутри устроен точно так же, как проект который генерирует: порты и адаптеры до мозга костей. Монорепо: приватный archkit-core (весь движок) и @autosergach/archkit (то что на npm). tsup бандлит core через noExternal, потребитель ставит один пакет.
FileSystemPort с двумя адаптерами: InMemoryFileSystemAdapter для тестов и NodeFileSystemAdapter для продакшена. Pipeline в три шага: buildInitPlan, renderTemplate, executePlan. С --dry-run третий шаг не выполняется.
Тесты: 35 + 3
35 unit-тестов гоняют весь движок через in-memory, без диска, меньше секунды на весь suite. 3 e2e-теста запускают настоящий pnpm install && pnpm test в os.tmpdir(). Именно они дают уверенность что сгенерированный проект работает у пользователя, и поймали несколько багов в шаблоне до публикации.
Один день с Claude Code
Весь v0.1.1, от пустой папки до npm publish, написал за одну сессию, примерно шесть часов. 9 атомарных коммитов: Claude Code писал код, я проверял и коммитил. До Claude Code такой объём занял бы неделю, и тесты я бы срезал.
4 урока из npm publish
1. cac и --no-X флаги. При --skip-install cac выставляет skipInstall: true по умолчанию, неявно. Фикс: проверять === true, а не !== undefined. Потерял час пока разобрался.
2. npm проверяет similarity, а не только занятость.archkit свободное имя, но npm отклонил из-за заброшенного arch-kit (2022, 12 загрузок). Ушёл в scoped namespace @autosergach/archkit, зато все следующие пакеты там же.
3. workspace:* в dependencies. Приватного archkit-core нет в registry. Если он в dependencies, npm падает при install у потребителя. Перенести в devDependencies, tsup бандлит его в dist.
4. Granular npm tokens и 2FA. Granular-токен с правами publish не проходит без «Bypass 2FA for publish». Опция выключена по умолчанию, нигде не выделена жирным. Получил 403.
Что дальше
v0.2: NestJS плюс React fullstack шаблон и --ai-ready флаг, который автогенерирует CLAUDE.md, .claude/settings.json, agents.md. Пишите в Issues если есть что сказать.
Насколько сложный проект можно сделать бесплатно в 2026 году?
Всем привет! Часто вокруг пишут, как ИИ помогает им «сделать SaaS за выходные», хайпят свои проекты и рассказывают про «миллион фич». Решил я проверить: а что реально можно сделать в 2026 году, если использовать только бесплатные тарифы и не тратить деньги?
Спойлер: получилось достаточно много.
Проект полностью экспериментальный — положится в портфолио.
Я решил сделать большой каталог, и выбрал в качестве товара приложения — PWA приложения — вдохновлялся App Store.
Что в итоге умеет платформа
Для пользователей:
- Личный кабинет с библиотекой своих приложений и избранным
- Можно оставлять комментарии, отзывы, лайки
- Сортировка по категориям, похожим на те, что в App Store
- Поиск приложений умный, использует векторное пространство имен от Google
- Приложения ранжируются по рейтингу — расчет по известной байесовской формуле — учитывает количество установок, отзывов, лайков и качество комментариев
- Задействованы, кажется, все методы установки на топ известных браузеров: от новой (2024) в один клик прямо с нашей платформы — для обладателей Chrome на ПК/Android — до пошаговых интерактивных инструкций в тех браузерах, где установка сложна или запутана
- 20 языков, 2 темы, работает офлайн. Сама платформа — тоже PWA.
- Импорт данных приложения со страниц AppStore и RuStore
- Автогенерация промо-картинки приложения + автопубликация в Pinterest
- Встраиваемый install-скрипт — один тег <script> на сайте разработчика добавляет умную кнопку установки
- 3 разных способа верификации приложений
Контентная часть:
- Масштабируемые промо-лендинги о преимуществах PWA
- Статьи-гайды по установке популярных приложений
- Для админа тоже есть свой интерфейс с множеством настроек
БД (Postgres + pgvector) Supabase — $0
Серверные функции Vercel + Edge Functions — $0
Фронтенд Vercel — $0
ИИ с API (переводы, эмбеддинги) Gemini — $0
Умный поиск Google Generative Language API + Gemini
Email Resend — $0
Авторизация Supabase Auth (Google, GitHub, Discord, GitLab и др.) — $0
Есть пару оговорок:
- Cursor 20$ в месяц — но я и без проекта его покупал
- и доменное имя wapps.store — 8$ за год. Можно было использовать то, что предоставляет Vercel бесплатно
Меня как фронтенд разработчика впечатлил масштаб бесплатных сервисов — да действительно можно реализовать свою задумку и протестировать её на будущих пользователях.
Однако надо понимать:
- бесплатные тарифы не потянут каких-то весомых нагрузок
- вайбкодить, не понимая, что генерирует нейронка — ну такое себе. Она стабильно ошибается каждый 2–3 раз и часто просто делает дикие вещи
- ну и времени приходится потратить немало, поэтому стоит подумать несколько раз: нужно ли тебе что-то такое просто «потестировать»
Поделитесь своими примеры или существующими проектами - будет интересно!
Почему зелёный CI не гарантирует, что система работает
Кейс из QA automation: как миграция на TypeScript привела к скрытому удвоению тестов без единого падения в CI
CI зелёный.
Тесты проходят.
Pull request’ы мерджатся.
Но система уже сломана.
И самое опасное — это не видно ни в логах, ни в отчётах CI.
В большинстве команд CI воспринимается как индикатор здоровья системы:
зелёный CI → всё работает
красный CI → есть проблема
Это удобная модель. Но она не всегда верна.
Контекст кейса
После миграции проекта с JavaScript на TypeScript мы заметили странное поведение:
CI стал выполняться почти в 2 раза дольше
тесты не падали
ошибок не было
метрики оставались “нормальными”
На первый взгляд — ничего критичного.
Что происходило на самом деле
Playwright начал подхватывать одновременно два набора тестов:
.spec.js
.spec.ts
В результате один и тот же тестовый набор запускался дважды.
Самое неприятное — CI не просто не показывал проблему. Он создавал иллюзию, что всё становится лучше: время выполнения росло постепенно, и это воспринималось как “нормальная деградация после миграции”.
Почему это было незаметно
Проблема усугублялась полным отсутствием сигналов:
CI оставался зелёным
тесты не фейлились
никаких warning’ов
никаких алертов
Единственный симптом — увеличение времени выполнения. Которое списали на “ну TypeScript, наверное тяжелее”.
Как проблема была обнаружена
Случайно. Ближе к завершению миграции, при удалении .js файлов, количество тестов внезапно сократилось примерно в два раза:
было ~240
стало ~120
До этого момента CI фактически выполнял двойную работу — без каких-либо признаков аномалии.
Root cause
Root cause оказался банальным — и именно поэтому его так долго не замечали.
В playwright.config.ts отсутствовал явный testMatch. Playwright по умолчанию подхватывает все файлы, соответствующие glob-паттерну — и .js, и .ts одновременно.
Фикс — одна строка:
testMatch: [‘**/*.spec.ts’]
Но чтобы до неё дойти, нужно было сначала понять, что вообще происходит.
Архитектурный вывод
Большинство проблем в тестовых системах не проявляются как падения.
Они проявляются как:
дублирование выполнения
скрытая деградация производительности
изменения в поведении runner’а без изменений в тестах
И у них нет алертов — потому что мы их не проектируем.
Например, в нашем случае проблему можно было бы поймать простым счётчиком discovered tests в CI.
Финальный вывод
CI — это не инструмент контроля качества системы. Это инструмент контроля того, что тесты не упали.
И если вы используете его как индикатор качества — вы просто получаете ложную уверенность быстрее.
CI отражает только одно: тесты выполнились без явных ошибок.
CI не отражает: тесты запустились правильно, в правильном количестве, с правильными предположениями об окружении.
Если система может быть “зелёной” и при этом работать некорректно — значит у вас есть статус выполнения, но нет наблюдаемости.
Как это выглядит в реальной системе
Именно этот кейс лёг в основу проекта, который я собирала как QA portfolio. В pipeline добавлен счётчик discovered tests: если количество отклоняется от ожидаемого, CI падает явно, а не молчит. Рядом — buggy branch с намеренно сломанной конфигурацией, чтобы можно было воспроизвести и починить самостоятельно.
Если собираешь QA портфолио или готовишься к техническому собеседованию — в Telegram-канале Тесты как система (https://t.me/qa_as_a_system) разбираю такие кейсы с кодом и объяснением: что показывать, как объяснять решения, какие находки работают на собеседовании.
Обновлена открытая библиотека theSVG из 5 880+ векторных SVG-иконок для разработчиков и дизайнеров. Есть вшитый поиск, CDN, CLI, API и готовые пакеты для React, Vue и Svelte. Бонусом у иконок есть разные варианты: цветные, монохромные, светлые, тёмные и wordmark.
Внимательно рассматривал сайт авито и глубоко философски задумался о законах скатывания продукта в хламину.
Что я считаю хорошим сайтом: максимально отзывчивые и предсказуемые, пусть и возвращающие результаты поиска не моментально. Например, все передовые изделия самого гугла - gmail, всякие промежуточные страницы логинов гугла, личный кабинет поисковой гугло-статистики сайта и почти что угодно подобное гугловое. Всё плавно, предсказуемо. Есть ощущение, что делающие гугловые сайты люди очень хорошо знакомы с внутренностями браузера или там есть менеджер-ревьюер-тестировщик, который пинает сайтоделов ногами до тех пор, пока те не узнают. Всё это предсказуемо работает даже в условиях, что от америки мы находимся на противоположном конце глобуса.
Авито:
Всё адово тормозит при рендере. Ему надо дать сильно подумать внутри браузера, прежде чем на что-то уже можно будет нажать. "эти компутеры в космос запускать можно, а вы одну кнопку нормально сделать не можете". Тупая фраза, но мысль передаётся.
Даже если сайт уже загружался ранее, то каждый раз он всё равно что-то подгружает и о чём-то там думает, прежде чем дать нажать на какую-нибудь элементарную кнопку, типа сортировки объявлений по дате на поисковой выдаче. Я жму на выпадающий список, а он не выпадает. Почему вы каждый раз заново грузите какой-то лютейший вагон .js - файлов, которые отвечают за эту кнопку и не даёте её нажать, пока это всё не прогрузится, ваши зумеры ещё не изобрели кеширование? Ребатя не понимают таких простых сайто-дизайнерских вещей, что кнопка не может не-нажиматься, если ты её уже показал.
Вёрстка, сделанная алкашами: никогда не знаешь что ещё подгрузится и вылезет где-нибудь сверху, отодвинув всё зарендеренное снизу. Что за манера подгрузить какой-то баннер, отложенно непредсказуемо поменяв положение всех элементов управления ниже, к которым юзер уже прицелился? За непонимание даже одной этой элементарной штуки на первом классе всех дизайнерских школ бьют по морде табуретом с размаху.
Непродуманные элементы управления в принципе дофига где. Много слабо интуитивного, неудачные расположения, пропадающие элементарные фильтры в непредсказуемых местах. В одной категории фильтр "Б\У" есть, а если подняться в родительскую - уже нет. Почему? Например контр-интуитивен и туп сам факт того, что нельзя просто написать в строке поиска used:1 pricerange:100-500 и просто вывалить кучу всего бу из любых категорий от 100 до 500 руб. Какие-то выпадающие менюшки вокруг логотипа "авито" такие, что раскрываются и загораживают сам логотип, если ты попытался прицелиться в него (чтобы перейти на главную) и чуть промахнулся. Жмёшь на какой-то пункт этой менюшки в итоге.
Я вот просто в целом экономически не понимаю как так получается. Что за АвтоВАЗ? Там у вас победило "можно, а зачем"? За что вы платите 450к/сек фронтендерам? Видимо просто за "желательно ничего не сломать, но внедрить новую кнопку от партнёра". Ну ладно, допустим - корпорация, все заняты митингами и KPI, работать некогда, а исследовать внутренности google chrome и всё оптимизировать - тем более никто не даст. А в гугле почему дают? Там просто денег больше? Там это почему работает, хотя их ЦК КПСС в разы жирнее авитовской корпорации.
Но непонятно ещё и другое: это ведь золотая жила для пилильщиков альтернативных площадок по продаже Б\У хлама? Можно ведь просто не напрягаясь сделать простенький аналог сабжа, хоть и с ужасно медленной модерацией и без кучи нужного сервиса, но который будет просто шикарен по юзабилити в сравнении с сабжем.
Извините, просто подумал вслух о помоечном состоянии user interface сабжа. Интересны скорее законы скатывания продукта в хламину и невозможность выделить бюджет на сравнительно небольшой отдел, доводящий лицо проекта до идеала, причём при условии бесконечных толстых потоков денег. Нельзя уволить на мороз какого-нибудь там директора департамента по HR или корпоративного психолога и закинуть освободившиеся 700 тыр в месяц в какого-нибудь гения в области google-chrome движка?
В backtest-kit модуль volume-anomaly используется как источник в графе сигналов - параллельно с GARCH. Если GARCH отвечает на вопрос «достаточно ли ожидаемое движение», то volume-anomaly отвечает на вопрос «является ли прямо сейчас статистически необычным моментом в микроструктуре рынка».
Пример кода
import { sourceNode, outputNode } from '@backtest-kit/graph';
import { predict } from 'volume-anomaly';
import { getCandles } from 'backtest-kit';
const ANOMALY_CONFIDENCE = 0.75;
const N_TRAIN = 1200; // обучающее окно — должно быть без аномалий
const N_DETECT = 200; // окно детекции
const reversalSource = sourceNode(
async (symbol) => {
// Важно: recent не должен пересекаться с historical
const all = await getAggregatedTrades(symbol, N_TRAIN + N_DETECT);
const historical = all.slice(0, N_TRAIN); // старые сделки — baseline
const recent = all.slice(N_TRAIN); // новые — без overlap
return predict(historical, recent, ANOMALY_CONFIDENCE);
// {
// anomaly: true,
// confidence: 0.81,
// direction: 'long' | 'short' | 'neutral',
// imbalance: 0.61,
// }
},
);
const entrySignal = outputNode(
async ([reversal, ...]) => {
if (!reversal.anomaly) return null;
if (reversal.direction === 'neutral') return null;
const position = reversal.direction; // 'long' | 'short'
return {
id: randomString(),
position,
priceTakeProfit: ...
priceStopLoss: ...
minuteEstimatedTime: 60,
};
},
reversalSource,
...
);
Ключевые детали
Hawkes Process - кластеризация ордеров
CUSUM- сдвиг buy/sell дисбаланса относительно исторической нормы
BOCPD- смена режима: момент когда распределение дисбаланса само меняется
Как использовать
Классическая проблема DCA - ты усредняешься в падающий нож. Цена идёт против, ты докупаешь, а она продолжает падать. volume-anomaly заточен именно под это: докупать не по расписанию или по сетке уровней, а только когда ордерфлоу показывает разворот агрессии.
Две полоски - лучший и худший случай, его можно прогнозировать
В backtest-kit GARCH используется как один из источников в графе сигналов. Идея: вход открывается только если GARCH-канал достаточно широк, чтобы TP и SL уместились с запасом над комиссиями.
Например, этим можно законтрить боковик, который был на BTCUSDT в Феврале 2024
5–10 февраля, 73% нейтральных баров
11–16 февраля, 63% нейтральных баров
19–24 февраля, 75% нейтральных баров
26–29 февраля, 69% нейтральных баров
Пример кода
import { sourceNode, outputNode } from '@backtest-kit/graph';
import { predict } from 'garch';
import { getCandles } from 'backtest-kit';
const CANDLES_FOR_GARCH = 300;
const GARCH_CONFIDENCE = 0.6827; // ±1σ
const garchSource = sourceNode(
Cache.fn(
async (symbol) => {
const candles = await getCandles(symbol, '8h', CANDLES_FOR_GARCH);
return predict(candles, '8h', null, GARCH_CONFIDENCE);
},
{ interval: '8h', key: ([symbol]) => symbol },
),
);
const entrySignal = outputNode(
async ([trend, volume]) => {
// Пропускаем если модель не сошлась
if (!volume.reliable) return null;
// Проверяем что до границ канала достаточно места
const upperDiff = percentDiff(trend.close, volume.upperPrice);
const lowerDiff = percentDiff(trend.close, volume.lowerPrice);
if (upperDiff < TAKE_PROFIT_PERCENT) return null;
if (lowerDiff < STOP_LOSS_PERCENT) return null;
// TP и SL по границам GARCH-канала
const tp = trend.position === 'long' ? volume.upperPrice : volume.lowerPrice;
const sl = trend.position === 'long' ? volume.lowerPrice : volume.upperPrice;
return { position, priceOpen: trend.close, priceTakeProfit: tp, priceStopLoss: sl };
},
trendSource,
garchSource,
);
GARCH здесь не генерирует направление. Он отвечает только на вопрос «достаточно ли ожидаемое движение». Направление приходит от другого источника (это может быть Pine Script через @backtest-kit/pinets или LLM через @backtest-kit/ollama)
Ключевые детали
Parkinson estimator для per-candle RV: (1/4ln2) · ln(H/L)² — в ~5× эффективнее squared returns
Log-normal bands: P·exp(±z·σ) — не линейное приближение, правильное маппирование в ценовое пространство
Cursor или Harvi Code: какой ИИ для кодинга в 2026 году реально работает в России без VPN и головной боли с платежами
В 2026 году почти каждый разработчик в России стоит перед одним и тем же выбором: хочешь мощный ИИ, который реально ускоряет разработку, или хочешь, чтобы всё работало просто, без посредников и ежемесячных нервов с оплатой.
Cursor — это сейчас, пожалуй, самый продвинутый AI-редактор на рынке. По сути, это VS Code, в который встроили настоящий искусственный интеллект на стероидах. Composer позволяет одной командой править сразу десяток файлов, агент понимает весь проект, хорошо справляется с рефакторингом, поиском багов и даже архитектурными решениями. Качество кода от Claude Sonnet 4.5 или свежих GPT часто вызывает искреннее «вау».
Но есть большая ложка дёгтя. Cursor — американский продукт, и российские карты он не принимает. Чтобы купить подписку Pro, приходится либо использовать виртуальные карты через крипту, либо платить посредникам (Oplatym и подобные), либо покупать готовые аккаунты (что рискованно). Сам редактор после оплаты работает без VPN, но первоначальная настройка оплаты — это отдельный квест. Бесплатная версия быстро упирается в лимиты, особенно если активно юзаешь мощные модели.
Harvi Code— Первый в России AI кодинг-агент. Российский ответ на все эти заморочки. Это полноценный AI-агент прямо внутри VS Code. Пишешь задачу в чате — он генерит код, рефакторит, фиксит баги, работает с контекстом всего проекта. Не тормозит, контекст держит хорошо, интерфейс привычный.
Самое приятное — модели на любой бюджет. Есть топовые (Claude Sonnet 4.5, GPT-5.4 и другие). А главное — очень низкая стоимость токенов. Для каждой модели есть свой коэффициент стоимости. Для большинства повседневных задач их хватает с головой, и можно вообще почти не тратить деньги. Оплата — российскими картами или СБП, без всяких посредников и VPN.
Коротко по делу:
Если тебе нужен мощный multi-file agent и ты готов один раз настроить оплату через проверенного посредника — бери Cursor. Он до сих пор в топе по возможностям.
Если хочешь работать стабильно, без лишних телодвижений и не думать каждый месяц про «как бы оплатить» — Harvi Code сейчас выглядит гораздо практичнее для российского разработчика.
А вы как сейчас кодите с ИИ? Пробовали оба варианта? Что в итоге оставили в основном редакторе? Пишите в комментариях, интересно почитать реальный опыт.
Смотрите пробуйте играйте, формируйте своё мнение, и всегда помните — хост — это не игрок, он не может выбирать ответы, но вы можете запустить игру с пк, и зайти с телефона. Или с одного пк на разных браузерах.
Представлен открытый проект TUI Studio (Visual Terminal UI Designer), среды для визуального проектирования интерфейсов пользователя, работающих в текстовом терминале. Среда позволяет в интерактивном режиме наглядно формировать интерфейс, перетаскивая готовые блоки мышью, редактируя свойства в визуальном режиме и предпросматривая результат на лету. Сформированный макет интерфейса может быть экспортирован для использования во фреймворках Ink, BubbleTea, Blessed, Textual, OpenTUI и Tview.
Решение написано на TypeScript с использованием React, Vite, Zustand, Tailwind CSS и Lucide React. Код распространяется под лицензией MIT. Из особенностей разработки отмечается, что почти весь код TUI Studio написан ИИ‑ассистентом Claude.
В TUI Studio предоставляется более 20 готовых компонентов для формирования интерфейса (кнопки, меню, таблицы, списки, индикатор прогресса, диалоги, всплывающие подсказки и тому подобное) и поддерживается 8 тем оформления, а также светлый и тёмный режим, градиентные заливки, ASCII‑цвета и акцентные цвета. Имеется возможность отката изменений. Доступен интерфейс для создания своих компонентов. Проекты сохраняются в формате JSON.
В продолжение прошлого поста, собрал новый трек курса из вашей обратной связи. Углубил тему, сделал ориентир на уже более опытных. Если есть куда еще копать - пишите в комментарии.
P.S. Все также бесплатно и таким останется, пока у меня есть деньги на поддержку и развитие ресурса.
Недавно общался с крупной зарубежной продуктовой компанией. Штат 500–1000 человек, вроде зрелые процессы, ЗП у разрабов 5000€ баг-репорты по ISO/IEC/IEEE 29119. И при этом:
«Не успеваем уделять время автотестам. Сфокусированы на скорости разработки и релизах.»
Что меня зацепило — каждый их аргумент против тестов я интерпретировал как аргумент за:
— «Слишком частые релизы» → А не потому ли они такие частые, что баги проскакивают на прод?
— «Требования постоянно меняются» → Тем более — как вы контролируете, что старое не ломается?
— «И так работают наизнос если еще и тесты заставить писать — выгорят» → А не от бесконечного ли футбола с багами они выгорают?
А как у вас? Есть автотесты на проекте? Или тоже «не до них»?
Открываешь проект 2020 года и видишь знакомые имена в package.json: create-react-app, enzyme, moment.js, axios. Пять лет назад это был золотой стандарт. Сегодня же эти технологии вызывают у коллег искреннее недоумение: «Зачем это тут?»
Подготовили для вас быстрый, но очень полезный срез того, как за 5 лет поменялась ментальная модель фронтендера. Внутри инструменты реально умерли, разберемся почему SSR/SSG снова в игре, а TypeScript теперь почти must-have, узнаем почему фронтенд всё чаще = full-stack и что с этим делать.
OAuth на практике: что оказалось удобным, а что отпугнуло пользователей
Мы запустили молодую платформу с двумя типами аккаунтов: обычные пользователи и разработчики (публикуют PWA и управляют приложениями).
Бренда и доверия пока нет, поэтому вопрос авторизации быстро стал не техническим, а психологическим.
С чего начали
Для обычных пользователей: • Email / пароль • Google • GitHub
Для разработчиков — жёстче: • Обязательная привязка Google • Обязательная привязка GitHub
Логика казалась разумной: «Разработчик = есть GitHub» «Двойная верификация = меньше спама»
На практике это не сработало.
Первые тревожные сигналы
Регистрация разработчиков шла крайне медленно, несмотря на интерес к публикации приложений.
Сначала списывали на: • новый продукт • низкое доверие • отсутствие аудитории
Но после общения с разработчиками (в том числе через Habr) картина прояснилась.
Что отпугивало разработчиков
Новый сервис → нежелание делиться данными
Даже если это «просто email», психологический барьер остаётся.
Когда с первого шага нужно: • линковать внешние аккаунты • проходить несколько этапов подтверждения • подключать сторонние сервисы
это воспринимается как лишний фрикцион.
Особенно для соло-разработчиков и небольших команд.
Git ≠ GitHub
Ключевой инсайт.
Мы обнаружили, что: • не все хотят логиниться через GitHub • часть использует GitLab или Bitbucket • некоторые принципиально не хотят связывать GitHub с новым сервисом
Обязательная привязка GitHub стала серьёзным барьером.
А мнение стандартных пользователей разделилось:
Часть говорила:
«Чем больше OAuth-кнопок, тем солиднее выглядит платформа».
Логика простая: • если есть Google / Facebook / Discord — значит не ноунейм • интеграции с крупными сервисами повышают доверие
Это не про безопасность — это про ощущение легитимности.
Другие говорили ровно противоположное:
«Слишком много кнопок — ощущение перегруженности».
И это тоже справедливый аргумент.
Что мы изменили
Упростили форму для пользователей
Оставили: • Google • Facebook • Discord
Достаточно выбора для доверия, без визуального шума.
Git-провайдеры вынесли в отдельную группу
Под отдельной кнопкой: • GitHub • GitLab • Bitbucket
Для разработчиков это стало понятнее и логичнее.
Убрали обязательный GitHub
Теперь для developer-аккаунта нужно подключить любой Git-аккаунт, если ни один не подключён.
Без принудительного GitHub.
Первые цифры (осторожно)
Прошла всего неделя, выборка маленькая, платформа всё ещё молодая.
Тем не менее: • Зарегистрированные пользователи: +13% (было 0–6% в неделю) • Зарегистрированные разработчики: +16% (было 0–3%)
Похоже, это те разработчики, которые знали о платформе, но их останавливало требование GitHub.
Выводы (пока не финальные) • OAuth — это не только безопасность, но и психология доверия • Жёсткие требования на старте почти всегда бьют по росту • Git ≠ GitHub — и это важно • Много провайдеров могут как повышать доверие, так и перегружать UI
Для молодой платформы даже такие ранние сигналы уже показательны.
Интересно услышать опыт коллег: добавляли ли вы OAuth-провайдеров после запуска? были ли случаи, когда обязательная авторизация через конкретный сервис тормозила рост?
Модуль метрик в Gramax Enterprise Server. Появились отчеты с метриками просмотров, визитов и посетителей на портале документации. А также статистика поисковых запросов. Отчеты можно фильтровать по дате и пользователям, выбирать период (день, неделя, месяц).
Поддержка Git LFS . Добавили возможность работать большими бинарными файлами (изображения, архивы, PDF и др.) через спецификацию Git LFS.
Превью файлов. На портале для читателей доступно превью файлов PDF и DOCX по клику. Читателю не обязательно скачивать файл на компьютер — он может просмотреть его прямо в браузере.
Свойства на портале. Раньше свойства отображались только в приложении, теперь можно настроить отображение и на портале для читателей. Читатель увидит их на статье, а также сможет отфильтровать результаты в поисковой строке.
Ссылки между каталогами. Добавили возможность добавлять относительные ссылки на статьи в других каталогах.
Удаление запроса на слияние. Теперь можно закрыть запрос на слияние в интерфейсе Gramax — он будет удален для всех пользователей после публикации изменений.
История комментариев. В просмотре изменений теперь проще отслеживать обновления комментариев: слева появляется иконка комментария, которая показывает, что в тексте изменились или появились комментарии. Там же можно кликнуть по комментарию, открыть его и отредактировать.
Представлена открытая платформа LifeForge. Этот проект — швейцарский нож для мониторинга жизни и работы. Инструмент заменяет такие сервисы: планировщик задач, трекер привычек, заметки, финансы, цели, обучение, дневник и ещё десятки инструментов — всё в одном месте. Внутри есть контроль задач, проектов и дедлайнов, учёт расходов и бюджета, заметки, идеи, дневник, обучение, флешкарты, база знаний, личные цели и прогресс. Работает локально, без облаков. Можно настроить под себя и отключить лишнее. По сути это Notion + Todoist + трекер привычек + финансы + личная CRM + учебная платформа в одном проекте.
Коллеги привет, искал себе решение как реагировать на изменения в объекте и нашел отличный сервис, который используется внутри директив таких как NgClass и NgStyle.
KeyValueDiffers позволяет создать KeyValueDiffer для сравнения изменений текущих пар ключ-значение с новыми. Если вы используете иммутабельные объекты, то можно просто обернуть все в эффект, ну а если вы наследники крутого легаси, где все объекты мутируются по ссылке, тогда проверку нужно вешать в DoCheck, чтобы реагировать на каждый тик change detection.
Накидал оба примера, чтобы поделиться с вами:
Иммутабельный с effect:
@Component({
selector: 'app-test',
template: ''
})
export class TestComponent {
public state = input.required<Record<string, string | number>>();
private differs = inject(KeyValueDiffers);
private differ: KeyValueDiffer<string, string | number> | undefined;
constructor() {
effect(() => {
const currentState = this.state();
// создаем диффер, если он еще не создан
if (!this.differ) {
this.differ = this.differs.find(currentState).create();
}
// Эффект будет перезапускаться при изменении инпут-сигнала.
const changes = this.differ.diff(currentState);
// только если есть изменения
if (changes) {
changes.forEachAddedItem((record) => {
console.log(`В объект добавлена запись: Ключ: ${record.key} | Значение: ${record.currentValue}`)
});
changes.forEachChangedItem((record) => {
console.log(`Изменено: ${record.key} | Новое значение: ${record.currentValue}`)
});
changes.forEachRemovedItem((record) => {
console.log(`Удалено: ${record.key}`)
});
// Остальные методы forEachItem и forEachPreviousItem по необходимости
}
})
}
}
Легаси подход, которого, надеюсь, ни у кого нет, но на всякий случай :)
@Component({
selector: 'app-legacy',
template: ''
})
export class LegacyComponent implements OnInit, DoCheck {
@Input({ required: true }) state!: Record<string, string | number>;
private differs = inject(KeyValueDiffers);
private differ: KeyValueDiffer<string, string | number> | undefined;
ngOnInit() {
// Создаем диффер при инициализации
this.differ = this.differs.find(this.state).create();
}
// Запускается на каждый тик change detection, так как мутации по-другому не отследим.
ngDoCheck(): void {
const changes = this.differ?.diff(this.state);
if (changes) {
changes.forEachAddedItem((record) => {
console.log(`В объект добавлена запись: Ключ: ${record.key} | Значение: ${record.currentValue}`)
});
changes.forEachChangedItem((record) => {
console.log(`Значение изменилось: ${record.key}`)
});
changes.forEachRemovedItem((record) => {
console.log(`Запись удалена: ${record.key}`)
});
// Остальные методы forEachItem и forEachPreviousItem по необходимости
}
}
}
Решил сегодня почитать, что пишут в Ангуляр комьюнити Хабра, и увидел сильно популярный пост с аж 51 лайком и 71 закладкой.
Начал читать и был удивлен примерами. Автор с уверенностью говорит, как писать на Ангуляр грамотно, и при этом приводит плохие практики в качестве примеров. Я дошел до примера с RxJS, который меня немного триггернул.
Не буду разбирать все кейсы указанные в данном посте, покажу лишь самый плохой пример который меня немного тригернул:
Автор условно говорит, что у нас есть плохой пример использования:
this.http.get('/api/data').subscribe((data) =>; {
this.data = data; // Что если запрос не вернётся?
});
и затем приводит хороший пример с сигналами и RxJs:
readonly data = signal([]);
readonly error = signal(null);
loadData() {
this.http.get('/api/data').pipe(
tap(() =>; this.error.set(null)), // Сбрасываем предыдущую ошибку перед загрузкой
catchError((err) =>; {
this.error.set('Не удалось загрузить данные');
return of([]); // Возвращаем пустой массив, чтобы поток не прерывался
})
).subscribe((result) =>; {
this.data.set(result);
});
}
я даже не буду указывать на количество антипатернов и плохих практик в данном примере, я просто покажу правильный пример с сигналами и RxJs:
Почему стоит использовать protected в Angular компонентах?
Если вы используете в своих компонентах только public и private, вы упускаете возможность сделать архитектуру чище. Я предлагаю четко разделять ответственность членов класса.
Часто мы по инерции делаем public любые методы и свойства, которые нужны в шаблоне (HTML). Но public в TypeScript означает, что это публичный API компонента - к этим методам может получить доступ любой родительский компонент через @ViewChild.
Почему стоит использовать protected:
1. Явное намерение: protected сигнализирует, что метод предназначен для использования внутри класса или в его шаблоне, но не должен вызываться извне.
2. Защита от регрессии: Если другой разработчик попытается вызвать такой метод через @ViewChild, TypeScript выдаст ошибку. Это заставит его задуматься: «Действительно ли мне нужно делать этот метод публичным?» или «Может, стоит создать отдельный метод для API?».
3. Читаемость: Открывая код, вы сразу видите: public - для внешнего мира, protected - для шаблона, private - для внутренней логики сервисов и подписок.
Разделяйте Public API и внутреннюю логику шаблона - ваш код станет надежнее и понятнее.
@Component({
selector: 'app-user-profile',
template: `
<!-- В шаблоне мы без проблем обращаемся к protected свойствам -->
<div class="card">
<h3>{{ userName() }}</h3>
<button (click)="onUpdateClick()">Обновить</button>
@if(isLoading()) {
<div>Загрузка...</div>
}
</div>
`
})
export class UserProfileComponent {
// PRIVATE: Внутренняя логика.
// Не доступно ни в шаблоне, ни родительскому компоненту.
private _userId = 123;
// PROTECTED: Доступно только внутри класса и в ШАБЛОНЕ.
// Идеально для переменных состояния UI и обработчиков событий.
protected userName = signal('Алексей');
protected isLoading = signal(false);
protected onUpdateClick(): void {
this.logAction();
console.log('Кнопку нажали в шаблоне');
}
// PUBLIC: Публичный API компонента.
// Только эти методы мы разрешаем вызывать родительскому компоненту.
public resetState(): void {
this.userName.set('Гость');
this.isLoading.set(false);
}
private logAction(): void {
console.log(`Action logged for userId: ${this._userId}`);
}
}
Как получить почти бесконечное зацикливание без использования циклов и без переполнения стека вызовов:
// Установите N = 64, и эта функция никогда не завершится
// Количество вызовов (calls) = 2^(N+1)
// Максимальная глубина вложенности = N
let calls = 0
const N = 18
function func(state, visited) {
calls++
if (calls > 10_000_000) {
throw new Error('calls: ' + calls)
}
if (visited.includes(state)) return
const newVisited = [...visited, state]
func((state + 1) % N, newVisited)
func((state + 1) % N, newVisited)
}
func(0, [])
console.log('calls:', calls)
Почему это работает без переполнения стека?
func(0, [])
├── func(1, [0])
│ ├── func(2, [0,1])
│ │ └── ... глубина растёт до N
│ │ и перебираются все возможные комбинации значений в newVisited
│ └── func(2, [0,1]) - возвращается, глубина УМЕНЬШАЕТСЯ
└── func(1, [0]) - второй вызов, стек уже освободился
А Garbage Collector (GC) при этом бесконечно удаляет созданные ранее массивы newVisited
Стек "дышит" - достигает максимума N, потом сворачивается, потом снова растёт. Это обход огромного дерева, имеющего небольшую глубину, но очень большую ширину. Это не бесконечная рекурсия. Но при N = 64 количество вызовов будет 2^65 (примерно 10^19) - это займёт тысячи лет, и стек никогда не переполнится.
Философия IT-собеседований: взгляд разработчика и DevOps-инженера
Привет, Хабр! Мой пост носит дискуссионный характер. В веб-разработке, администрировании и DevOps я уже 17 лет. Долгое время работал «на себя», оказывая помощь клиентам, с которыми выстроены надёжные взаимоотношения, но текущие реалии рынка подтолкнули к поиску работы по ТК, об этом я и хочу поговорить.
Обо мне: 40 лет, из которых 17 лет в коммерческой разработке. Прошел долгий путь как в fullstack-разработке (web), так и в создании embedded-решений (каршеринг), администрировании и DevOps.
Раньше мой процесс найма редко выходил за рамки одного интервью. Сейчас же я регулярно сталкиваюсь с многоступенчатыми отказами, иногда даже на этапе HR-скрининга. Этот контраст заставил меня задуматься: что делает найм эффективным, а что превращает его в фарс? Решил систематизировать свои наблюдения и поделиться тем, что в современных собеседованиях кажется здравым, а что — откровенно лишним.
Описываю позитивные практики, с которыми сталкивался, практики за которые я уважаю потенциальных работодателей и команды. Это парадигма, в которой я вёл деятельность с начала карьеры.
Диалог на равных. Мое лучшее интервью: техлид не мучил теорией, а предложил обсудить реальную дилемму, которую он решает в данный момент (внедрение NoSQL-хранилища ради одного специфичного сервиса, т.е. доп. точка отказа vs производительность). Без таймера и стресса мы искали решение. Итог — оффер и годы отличной работы.
Проверка логики, а не памяти. Люблю кейсы в духе: «Вот дано А, почему происходит Б?». Из банального: может ли Вася из другого города достучаться до вашего локального IP? Это показывает понимание базы лучше любого теста.
Ценность универсальных знаний. Универсальные знания долгое время позволяли быстро находить решение практически любой проблемы от хардверной, до нарушения самых элементарных паттернов проектирования в коде и эффективно их устранять. Мне нравятся задачи, где проблема может быть скрыта на любом уровне и нравятся клиенты, понимающие, как я могу снять их головную боль обеспечив работоспособность ПО в любой среде и условиях.
А теперь я хочу описать то, от чего меня бомбит. Это факторы которые будут отпугивать меня вплоть до момента, когда будет нечего кушать и я буду вынужден прогнуться под выгодное предложение.
Лайвкодинг. В 40 лет написание кода для меня — процесс интимный... хотя я практикую парное программирование в реальной команде и это мне нравится, но в предвкушении собеседований иногда хочется "психануть" и на предложение выбрать время для лайвокдинга сказать — "предлагаю парное программирование с одним из ваших специалистов, ведь для меня тоже важно, с кем я буду вести разработку". (Не пробовал так отвечать, но попробую, как только выдастся случай).
Вакансии-обманки. Зачем заманивать стеком DevOps (Linux, Nginx, Ansible, Terraform, Puppet, Docker, Kubernetes, MySQL, PostgreSQL, Elasticsearch, Logstash, Kibana, Zabbix), если по факту сообщаете, что ничего этого не будет, а ищите классического сисадмина 9-18? — Давайте адкеватный запрос, а не тратьте время.
Терминологическая каша. Сложно отвечать экспертно, когда интервьюер путает CI и OCI или Redis и Rabbit. Если нет погружения в контекст, конструктивного диалога не выйдет. Готовиться к собеседованию должен не только соискатель, но и тот, кто нанимает.
Отсутствие пунктуальности. Для меня было шоком, что фаундер может просто не явиться на собседование, или рекретер забывает о диалоге и назначенной встрече. У вас там всё нормально?) Хотя рекрутер мало чем отличается от агента недвижимости, но фаундер забывающий про собеседование для меня персонаж странный.
Узкая специализация. Раньше, как мне кажется, ценилась универсальность, способность разработчика понимать инфраструктуру, а инженера/админа — код. Сегодня индустрия уходит в жесткую сегментацию, видимо, для более точного просчёта рисков. А я считаю, что именно универсальность — это страховка проекта от того, что решение будет принято в вакууме одного стека, без учета общей картины.
За годы менторства по Angular (в том числе в HTML Academy) я заметил одну системную проблему: студенты и даже миддлы часто знают синтаксис RxJS, но не понимают реактивного мышления. В итоге мы получаем subscribe внутри subscribe и императивную лапшу.
Я искал интерактивные курсы, но большинство бесплатных ресурсов ограничиваются основами.
Курс бесплатный. Делал для себя и студентов, но теперь делюсь со всеми.
Буду рад фидбеку и баг-репортам (проект активно допиливаю).
Как мы избавились от рутины в сетевом коде с помощью собственного фреймворка Chord 🪄
Расскажем на крупнейшей конференции для разработчиков разного профиля — Holly JS 🤟
Спикером конференции станет Дмитрий Дин, fullstack-лид Далее. В докладе «Chord’овская декларативность: побеждаем бойлерплейт сетевого взаимодействия» он поделится опытом внедрения собственного инструмента Chord (на базе JSON-RPC), который уже больше года работает в продакшене и избавляет команды от рутины при взаимодействии между клиентом и сервером.
Доклад будет особенно полезен frontend- и fullstack-разработчикам (уровня Middle и выше), которые работают с TypeScript и современными фреймворками вроде SvelteKit, Next.js или Nuxt.
Приходите послушать доклад Димы 21 ноября, с 15.30, в секции Фреймворки.
Представлен открытый проект релейного компьютера 1961 года Minivac 601, работающий в браузере (код на GitHub). До появления микрочипов компьютеры строились на основе механических реле. Это рабочая модель Minivac 601, образовательного компьютера, разработанного Клодом Шенноном.
Недавно я копался в мире ИИ-инструментов для разработки — тех, что помогают писать код быстрее и умнее. Знаете, когда сидишь за проектом и думаешь: "А не взять ли помощника, который подхватит идеи на лету?" Решил поделиться обзором нескольких интересных вариантов на рынке. Это не глубокий разбор с бенчмарками (для этого нужны отдельные тесты), а просто описание, чтобы понять, что можно выбрать под свои нужды. Я опираюсь на личный опыт и отзывы из сообществ — вдруг кому-то пригодится для экспериментов.
Давайте по порядку:
Cursor — это как эволюция VS Code с встроенным ИИ. Он автокомплитит код, генерирует фрагменты по описанию, понимает контекст проекта и даже помогает с отладкой. Подходит для тех, кто любит привычный интерфейс, но хочет ускорить рутину. Работает на Windows, macOS и Linux, есть бесплатная версия, но премиум открывает больше моделей ИИ. Идеально для соло-разработчиков или команд, где нужно быстро итератировать.
Harvi Code — российский продукт, первый в России аналог Cursor, построенный на мощной модели Sonnet 4.5 (от Anthropic, которая славится точностью и скоростью). Это расширение для VS Code и Cursor с удобным интерфейсом, как в знакомых IDE, плюс фокус на хороших ценах (не дерут втридорога за подписку). Подходит для генерации кода, отладки и работы с проектами. Если вы в РФ и ищете локальный вариант без заморочек с платежами — стоит попробовать.
Lovable — здесь акцент на создание веб-приложений без глубокого кодинга. Чат с ИИ: описываешь идею на естественном языке, и он генерирует full-stack app — от фронта до бэка. Удобно для прототипов или MVP, особенно если вы не хотите копаться в деталях. Поддерживает интеграции с базами данных и API. Минус — иногда нужно дорабатывать вручную, но для стартапов или хобби-проектов это спасение.
Bolt (bolt.new) — браузерный инструмент для быстрого создания сайтов, приложений и прототипов. Вводишь промпт — и вуаля, он строит всё от начала до конца, включая деплой. Работает с веб, iOS и Android. Круто для тех, кто хочет экспериментировать без установки софта. Есть интеграции с Expo для мобильных apps. Подходит новичкам или когда нужно быстро проверить концепцию.
Roo Code — это расширение для VS Code и Cursor, как целая команда ИИ-агентов прямо в вашем редакторе. Он анализирует весь проект, предлагает мульти-шаговые решения, ускоряет редактирование в 10 раз. Поддерживает разные модели ИИ (Anthropic, OpenAI), есть инструменты для автоматизации задач. Хорош для сложных проектов, где нужен глубокий контекст — не просто автокомплит, а умный помощник.
Kilo Code — открытый ИИ-агент в виде расширения для VS Code, JetBrains и Cursor. Генерирует код, автоматизирует задачи, предлагает рефакторинг. Есть система инструментов для взаимодействия с окружением (безопасно, с контролем). Бесплатный, с опцией кастомизации. Идеален для тех, кто предпочитает open-source и хочет интегрировать в свой workflow без лишних зависимостей.
В общем, выбор зависит от вашего стиля: если любите браузер — Bolt или Lovable; если вглубь кода — Cursor, Harvi, Roo или Kilo. Я пробовал пару из них на пет-проектах, и реально сэкономил время. Что вы думаете? Пользовались кем-то из списка? Делитесь в комментах, может, вместе разберёмся, какой подойдёт под разные языки или фреймворки. Буду рад обсуждению! 🚀
При работе над React-приложениями я часто сталкиваюсь с тем, что мои коллеги смешивают в одном файле и JSX, и CSS-in-JS стили, и логику, и типы компонента. Работать с таким месивом очень сложно. Даже если настаивать на выделении логики, стилей и типов в отдельные файлы, это то делается, то нет. Для введения жёсткой структуры компонентов мною была написана простейшая библиотека react-component-structure.
В файле logic.ts мы пишем хук useLogic - контроллер компонента, включающий в себя всю его бизнес-логику - все хуки useCallback, useEffect, useMemo и подобные. В этом хуке у нас есть доступ к props компонента.
В файле styles.ts мы помещаем хук useStyle со стилями нашего компонента. Тут мы можем использовать inline-стили, CSS-in-JS или Tailwind. В этом хуке у нас есть доступ к props нашего компонента и к его контроллеру.
В файле render.tsx мы помещаем хук useRender с JSX, то бишь отображение компонента. В этом хуке у нас есть доступ и к props компонента, и к его контроллеру logic, и к стилям.
import type { Props } from './types';
import type useLogic from './logic';
import type useStyle from './style';
const useRender = (props: Props, logic: ReturnType<typeof useLogic>, style: ReturnType<typeof useStyle>) => {
return (
<div>
<div style={style.title}>Hello {props.greeting}!</div>
<div style={style.counter}>Count: {logic.count}</div>
<div onClick={logic.onClickMinus}>Decrease</div>
<div onClick={logic.onClickPlus}>Increase</div>
</div>
);
};
export default useRender;
В index.ts файле мы соединяем все три хука с помощью функции createComponent:
import { createComponent } from 'react-component-structure';
import useLogic from './logic';
import useRender from './render';
import useStyle from './style';
const Component = createComponent({ useLogic, useRender, useStyle });
export default Component;
И в файле types.ts мы объявляем тип для props компонента:
Если у компонента нет props, то можно объявить их так:
export type Props = unknown
При использовании каждый компонент нашего приложения имеет чёткую структуру, состоящую из файлов контроллера, отображения, стилей и типов. Это разделение подобно разделению на HTML (отображение), CSS (стили) и JavaScript (контроллер) в ванильных JS-приложениях.
Если подход и библиотека вам понравились, поставьте репозиторию звезду на гитхабе. Надеюсь этот подход будет вам полезен.
TypeScript и C++ в одном бинаре. Первый open source-проект от МойОфис
Команда МойОфис выложила в open source собственную разработку — компилятор tsnative. Это кроссплатформенный инструмент, который объединяет удобство TypeScript с производительностью C++ в одном приложении. Исходники — на GitHub под лицензией Apache 2.0.
Компилятор tsnative — это первая и ключевая часть более масштабного проекта под названием AntiQ, в котором мы переосмысляем подход к кроссплатформенной разработке без тяжёлых фреймворков.
AntiQ разделен на два самостоятельных компонента. Сейчас в open source опубликован только tsnative — главный модуль, в котором сосредоточена основная логика и заложены архитектурные принципы всей платформы.
Зачем это нужно?
tsnative — это кроссплатформенный компилятор, преобразующий TypeScript в нативный машинный код. Он обеспечивает бесшовную интеграцию с C++ без glue-кода или JavaScript-движков, объединяя удобство высокоуровневой разработки с производительностью системного кода. В результате вы получаете один бинарник, собранный из двух языков.
Как это работает:
C++-функции помечаются TS_EXPORT;
генерируются .d.ts-декларации для TS;
TypeScript- и C++-код собираются через LLVM;
на выходе — один исполняемый файл, без обёрток.
// math.cpp
#include "TS.h"
TS_EXPORT int add(int a, int b) {
return a + b;
}
// index.ts
console.log(add(2, 3)); // -> 5
// index.ts
console.log(add(2, 3)); // -> 5
Проект может быть интересен тем, кто:
делает нативные приложения, но хочет писать часть логики на TS;
ищет замену закрытым коммерческим компиляторам;
любит ковыряться в сборке, кросс-компиляции и низкоуровневом коде.
Открытый код — не просто «выложили и забыли». Мы хотим, чтобы проектом пользовались, коммитили, обсуждали. Поэтому будем рады pull request’ам, issue и звёздочкам. Всё как обычно :)
Под пост в телеграм про наш ответ аналог Grafana пришли руководители "Лаборатории Числитель" и конкретно "Пульта", в чью систему входит платформа мониторинга и анализа "Графиня".
Дмитрий Унтила и Владимир Утратенко любезно ответили на ряд вопросов по платформе, и я хотел бы подвести краткое резюме:
Запрос на аналог Grafana появился в момент продажи "Пульта", так как "не всем можно брать забугорный опесорс себе в контур. Потому решили делать. А название Графиня просто ради лулзов."
Графиня писалась с полного нуля. Хотя предложение взять за основу Grafana было, но команда смогла обосновать геморрой, который на неё упадёт, если взяться за доработку, и объяснила руководству, почему лучше сделать с нуля.
Время разработки: 3 месяца - MVP, 6 месяцев - 1 релиз.
На мое предложение сделать проект опенсорс Дмитрий Унтила пообещал подумать. Но, понятное дело, если это часть коммерческого продукта, прям сильно думать в лаборатории не будут))
Демо-стенда в интернете пока нет, можно только записаться на показ системы через форму обратной связи.
Благодарю парней за такой актив и обратную связь, рад, что у людей есть на это время!
Кнопка 'Загрузить еще' (либо автоматическая подгрузка данных при скролле) довольно часто встречается в проектах и обычно решение связано с большим количеством подписок и переменных.
Как всегда, для оптимизации чего либо нам на помощь приходит великий и могучий RxJS, а в данной ситуации конкретно операторы scan & mergeScan.
В Angular 20 afterRender был переименован в afterEveryRender, и это очень логично, так как теперь он более четко отражает суть (нейминг решает). Сам afterRender (далее afterEveryRender) и его брат afterNextRender появились в версии 17. Рассмотрим, почему эти два мощных инструмента управления рендерингом — не просто альтернативы ngAfterViewInit, а полноценные хуки жизненного цикла с бесшовной поддержкой SSR!
Это хуки? Да! Это хуки нового типа, которые выполняются после рендеринга компонента:
Они не заменяют ngAfterViewInit/ngAfterContentInit, а дополняют их
Включают гранулярные реакции на рендеры, включая обновления
Почему идеально подходит для SSR? Главное преимущество: обратные вызовы выполняются только на клиенте! ✅ После гидратации (в SSR) ✅ После первоначального рендеринга (в CSR) ✅ Больше никаких ошибок «документ не определен»
Использование: constructor() { // 🚫 Не запускается на сервере // ✅ Запускается только один раз после загрузки браузера! // 📊 Идеально подходит для однократной инициализации afterNextRender(() => { console.log('Next'); });
// 🚫 Не запускается на сервере // 🔄 Запускается после каждого цикла обнаружения изменений // ✨ Отлично подходит для обновлений, зависящих от DOM afterEveryRender(() => { console.log('Every'); }); }
Когда использовать?
afterNextRender
Одноразовые операции (инициализация библиотеки, загрузка данных)
Безопасная замена ngAfterViewInit для SSR
afterEveryRender
Отслеживание изменений DOM (измерения элементов, позиции)
⚠️ Внимание: может повлиять на производительность
Основные выводы
Интегрировано в систему жизненного цикла Angular
Автоматический пропуск на стороне сервера - больше никаких хаков isPlatformBrowser!
afterNextRender - "один раз после рендеринга"
afterEveryRender - "после каждого обновления"
"Я пока не использовал afterEveryRender в своих проектах - есть ли у вас практические примеры использования? Поделитесь в комментариях!"
Манипуляций довольно много, но мы все к этому привыкли и это кажется нормальным.
Но с withComponentInputBinding() все стало намного проще: 1. Создаем сигнальный инпут... и... Вот и все!
Никаких дополнительных манипуляций, и значение «у вас в кармане». Все, что вам нужно, чтобы это работало, — это передать withComponentInputBinding() в качестве аргумента в provideRouter().
Функция не новая (кажется, появилась в Angular 16), но я редко ее видел в проектах.
Немного технической информации из документации:
🔍Маршрутизатор передает данные в input() из:
Параметров запроса (?page=1&sort=asc)
Параметров пути и матрицы (/users/123;details=true)
Статических данных маршрута (data: { role: 'admin' })
Результатов резолвера (resolve: { user: userResolver })
🔍 Приоритеты: Если есть дублирующиеся ключи, данные переопределяются в порядке выше — резолверы имеют наивысший приоритет и перезапишут остальные.
🚩 Важный нюанс Если в маршруте нет данных для input(), он получит undefined (например, если параметр запроса удален из URL).
ℹ️ Как задать значения по умолчанию?
✔ Через resolver (чтобы данные всегда были в маршруте) ✔ Через transform в input() (если нужно обрабатывать undefined)
Спасибо разработчикам Angular за эту функциональность 🙏.