TGViewer
Channel Public Channel
DartWay Ru | Flutter & Fullstack Dart

DartWay Ru | Flutter & Fullstack Dart

@dartway_dev_ru

Flutter и fullstack Dart в реальной разработке —
без занудства и ненужных абстракций.

Архитектура, практические приёмы, разборы кода.

Для Flutter-разработчиков, которые хотят увереннее чувствовать себя в реальных проектах

💬 @dartway_dev_ru_community
Subscribers
596
Photos
22
Videos
0
Links
36

Showing posts older than #146 · Back to latest

Older Posts 20 shown
Post #144 468
Всё! Ядро DartWay на pub.dev.

Сегодня я опубликовал все основные пакеты и CLI инструмент.

Это значит: весь стек DartWay теперь ставится с pub.dev одной командой — не git-зависимости, а dart pub global activate dartway_cli → dartway create. Пустая папка → работающее fullstack-приложение: сервер, база, real-time, авторизация. Один язык от базы до виджета.

Самое главное, что даёт ядро:

CRUD без единого эндпоинта. Модель → конфиг → живой экран. Одна DwCrudConfig на модель описывает всё поведение: кто читает, кто пишет, какие правила. Эндпоинты писать не нужно — их нет. Фича приходит из модели, а не из руками собранного API.

Secure by default. Доступ не настроен — модель не отдаётся никому. Это не «забыли закрыть», а «не открыли»: доступ выдаётся явно, а не отбирается задним числом. ИИ-агент физически не может выкатить фичу с открытым бэкендом по недосмотру.

Данные — типизированный живой список. ref.watchModelList<T>() — одна строка: real-time-синхронизация, пагинация, скелетоны на загрузке. Ни репозиториев, ни сервисов, ни сокетов, ни инвалидации кэша.

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

Ядро — четыре пакета в одной версии. Вокруг — тулбокс приложения, линты под конвенции, CLI. Всё на pub.dev.

Завтра — живое демо.

Суббота, 18.07, 14:00 МСК — «Fullstack-приложение на чистом Dart за 90 минут».
С пустой папки: команда, модель, бизнес-правило, real-time — без единого написанного эндпоинта.

YouTube Live, запись будет. Ссылка будет завтра))
  • 🔥 6
  • ❤ 1
Post #143 414
Ещё два пакета на pub.dev. И почему они плагины, а не «фичи из коробки»

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

Отсюда правило, которое мы проверяем каждым релизом: упрощать рутину, не забирая гибкость. Сегодня на pub.dev уехали два пакета — и они ровно про вторую половину этого правила.

dartway_telegram — интеграция с Telegram Mini Apps. dartway_shared_preferences — локальное хранилище с реактивными riverpod-провайдерами. Напрашивается: суньте в ядро, пусть будет «из коробки». Мы сделали наоборот — это плагины.

Что это значит на практике. Ядро фреймворка не знает слова «Telegram». Не знает про локальное хранилище. Приложение, которое не Mini App, не качает телеграмный SDK только чтобы запуститься. Нужен Telegram — плагин объявляется при старте и доступен отовсюду как dw.plugins.telegram. Нужно хранилище — dw.plugins.prefs. Не нужно ни то ни другое — в приложение не приезжает ни строчки.

И тот же шов открыт каждому разработчику. Telegram у нас — не привилегированная «фича фреймворка», а обычный плагин через публичный DwPlugin. Понадобится проекту аналитика, connectivity, пуши, какой-то свой вендор — разработчик пишет плагин точно так же и достаёт его как dw.plugins.<своё>. Ядро остаётся минимальным контрактом; всё опциональное живёт снаружи и подключается одинаково — и нашими руками, и руками любого, кто ставит пакет.

То же и с внешним видом. DartWay намеренно не поставляет дизайн-систему — ни одной кнопки. Дизайн — единственное, что любой серьёзный проект всё равно форкает под свой бренд; отдать его зависимостью значит обречь всех на спор про радиус кнопки. Поэтому UI-кит — это исходники в самом приложении (модель shadcn/ui): код принадлежит проекту, меняется как угодно, никто не спорит.

Вот что стоит за словами «фреймворк ничего не отнимает». Сложное — запуск, действия, права, реалтайм, CRUD — решено один раз и по-нормальному. Но интеграции — свои, хранилище — своё, UI — свой, модели — свои. Ни в одной точке нет двери, за которой «дальше только форк».

DartWay упрощает многое — и не ограничивает ни в чём.

Теперь это можно проверить на своём проекте:
https://pub.dev/packages/dartway_telegram
https://pub.dev/packages/dartway_shared_preferences
Dart packages dartway_telegram | Flutter package Telegram Mini App integration for DartWay apps: initialize the Telegram WebApp, read its safe-area insets and the Telegram user id. Optional by design.
  • 🔥 4
  • ❤ 1
Post #142 423
Ура! DartWay Flutter опубликован. Начинаю с того, что каждый Flutter-разработчик пишет заново в каждом проекте, — со скелета приложения.

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

Что даёт конкретно.

— Запуск одной строкой. DwAppRunner берёт на себя то, что настраивает каждое приложение и не любит настраивать никто: ProviderScope, нативный сплэш, инициализаторы по порядку, зону, которая ловит необработанные ошибки, а не теряет их.

— Защищённые действия. dw.action(...) — оборачивает действие пользователя: показывает подтверждение, гоняет loading-состояние, ловит ошибку, шлёт уведомление. Двойной тап не создаёт две записи — защита от повторного нажатия встроена. И это работает под любым виджетом, не только под кнопкой.

— Асинхронный рендеринг. dwBuildAsync рисует loading / error / data единообразно, а loading — это скелет, построенный из твоего же реального виджета, не спиннер.

— Ошибки с контекстом. Каждая ошибка несёт снимок состояния приложения: маршрут, смонтированные фичи, действие, платформа, версия. Не голый stack trace в минифицированном вебе, а «что делал пользователь, когда сломалось».

Как устроено. Приложение объявляет один амбиентный корень — dw — и обращается к нему отовсюду: dw.action, dw.notify, dw.confirm, dw.plugins.telegram. Одна точка входа, один автокомплит. То, что подключаешь опционально (Telegram, локальное хранилище), — плагины под dw.plugins, за которые платит только тот, кому они нужны.

Riverpod-native. DartWay — мнение, а не набор виджетов: Serverpod на сервере, Riverpod на клиенте, AsyncValue — тип, на котором построен весь async-контракт.

Полезен сам по себе. Пакет не тянет ни сервера, ни слоя данных — работает в любом Flutter+Riverpod приложении. В комплекте — запускаемый пример: скопировал, flutter run, читаешь сверху вниз.

За ним следом — ещё восемь пакетов, включая инструментарий под конкретные задачи и главное ядро для fullstack Dart разработки

Ссылка на pub.dev - https://pub.dev/packages/dartway_flutter
Напоминаю: в субботу в 14:00 пройдет публичное демо всех пакетов
Dart packages dartway_flutter | Flutter package The Flutter skeleton of a DartWay app: bootstrap runner, guarded UI actions, the AsyncValue rendering contract, notifications and error reporting. Riverpod-native.
  • ❤ 2
  • 🔥 2
  • 🎉 1
Post #141 360
Несколько месяцев я писал здесь про принципы. Пора показать целиком то, о чём речь: на этой неделе DartWay выходит на pub.dev, и я буду выкладывать его по пакету в день, с разбором каждого.

Сегодня — общая картина.

## Суть

Flutter-разработчик умеет делать фичи и экраны. Дальше начинается стена: сервер, база, миграции, эндпоинты, авторизация, права, реалтайм. Обычный ответ индустрии — «возьми Firebase/Supabase»: удобно, но чужая база, чужие модели, чужой язык и потолок ровно там, где начинается настоящая бизнес-логика.

DartWay отвечает иначе.

Единый декларативный слой данных от базы до виджета. На сервере фича описывается конфигом:

кто имеет право читать (accessFilter), кто — писать (allowSave), что считается валидным (validateSave), что должно случиться в той же транзакции (beforeSaveTransaction). Всё. Эндпоинтов не существует.

На клиенте эта же модель забирается одной строкой:

ref.watchModelList<Booking>() — типизированный живой список. Реалтайм-синхронизация, пагинация, фильтры, скелетные состояния загрузки — из коробки. Кто-то записал модель на сервере — виджет перестроился. Никаких сокетов руками, никаких инвалидаций кэша.

Фича целиком — от таблицы в базе до живого экрана — это примерно 40 строк конфига и виджет.

Формула: Serverpod даёт тебе бэкенд. DartWay убирает необходимость его писать.

## Структура: девять пакетов, три круга

Ядро (четыре пакета, версионируются вместе).
Серверная половина — модуль Serverpod: generic CRUD для любой модели с реалтайм-подписками, декларативные конфиги доступа и валидации, беспарольная авторизация по телефону, файловое хранилище (S3/MinIO), алерты об ошибках. Клиентская половина — типизированный слой данных поверх этого: watchModelList, сессии, переживающие перезапуск, обработка ошибок, которая отличает сетевой сбой от настоящей поломки.

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

Тут же — принцип, за который я держусь: фреймворк не поставляет дизайн-систему. Никаких DwButton и DwText. Дизайн-система — единственное, чем любой серьёзный проект в итоге владеет сам, и отдавать её зависимостью значит начать вечный спор про радиус скругления кнопки. UI-кит приезжает в твоё приложение исходником — и дальше он твой.

Обвязка.
CLI (dartway create — проект, который запускается, за считанные секунды), линты и чекер, которые машинно проверяют конвенции, опциональная интеграция с Telegram Mini Apps, мост в DartWay Studio.

## Три принципа, на которых всё держится

Фреймворк не владеет моделями приложения. Пользователь — это твой UserProfile, в твоей базе, с твоими полями и ролями. Не «расширь наш UserInfo», не форк модуля. Это то, обо что разбиваются готовые батарейки: чужую модель не расширить, а форк тащится через каждое обновление.

Secure by default. Модель, для которой не описан доступ, не отдаётся никому. Не «открыто, пока не закрыл» — а «закрыто, пока не открыл». Для generic CRUD это единственный честный дефолт: забыть закрыть можно, забыть открыть — нельзя.

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

## Дальше

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

А в субботу, 18 июля, в 14:00 МСК соберу на этом всём работающее приложение вживую — за 90 минут, с пустой папки: сервер, база, реалтайм, авторизация. Бесплатно, запись будет.
  • 🔥 5
  • ❤ 1
  • 🤡 1
Post #140 447
Тем временем Serverpod

Если честно, я не вижу особого смысла в заявленном функционале.

Разработка сейчас идет пока я мою посуду или занимаюсь в зале. Не очень понимаю, как hot reload улучшит мою жизнь в такой ситуации...
Post #139 466
Самое сложное в модуле — это гибкость

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

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

В качестве антипримера — модули Serverpod.

В Serverpod есть готовые модули аутентификации и чата. Выглядит подарком: подключил — и в проекте логин и мессенджер из коробки. Ровно то, что обещают все фреймворки «с батарейками».

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

Это не претензия к Serverpod — он отличный фундамент, и DartWay построен поверх него. Это ловушка, в которую попадает почти любой «готовый модуль»: чем больше функциональности зашито в чужие модели, тем быстрее инструмент из ускорителя превращается в тормоз. Причём стена обнаруживается не в день установки, а через месяц, когда переделывать уже дорого.

DartWay спроектирован от обратного принципа: фреймворк не должен владеть моделями приложения.

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

Отсюда формула DartWay: инструменты должны снимать рутину, не забирая гибкость. Всё сложное — авторизация, права, реалтайм, CRUD — решено один раз и по-нормальному. Но все модели остаются моделями приложения, вся логика — логикой приложения, и ни в одной точке нет двери, за которой «дальше только форк».

Через несколько дней DartWay выходит на pub.dev — это утверждение можно будет проверить на своём проекте.
  • 🔥 6
  • ❤ 2
Post #138 457
Вчера я написал, что строю DartWay в открытую. Прежде чем показывать код и фичи — стоит сказать, что это вообще такое и откуда взялось.

Больше трёх лет назад мы начали делать fullstack на Dart — не отдельные экраны, а продукты целиком: клиент, сервер, база, реалтайм, деплой. За эти годы, через изрядное количество боли, я пришёл к двум вещам.

Первое. Большинству разработчиков — даже сильных — не хватает опыта, чтобы грамотно спроектировать fullstack. Это отдельная компетенция: не «выучить ещё один фреймворк», а понимать, как протянуть данные от базы до виджета так, чтобы на втором десятке экранов это не начало рассыпаться. За месяц такому не научишься.

Второе — и оно оказалось важнее. Все самые сложные вещи в проектах одинаковы. Авторизация, права доступа, реалтайм-синхронизация, CRUD, пагинация, фильтры — из проекта в проект это буквально одна и та же задача. У каждой есть несколько разумных способов решения. Достаточно один раз выбрать хороший — и дальше переиспользовать везде, не изобретая заново и не наступая на те же грабли.

Так и появился DartWay.

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

А дальше покажу уже на конкретном коде — как в этом стеке фича живёт целиком, от сервера до живого списка на экране, в несколько десятков строк.
  • 🔥 8
  • ❤ 1
  • 🤮 1
  • 💩 1
  • 🤡 1
Post #137 460
Я долго строил этот канал про Flutter-разработку и fullstack Dart. У меня расписан контент-план на месяц вперёд, с разумными пропорциями: немного про Flutter, немного про Dart, виджеты, библиотеки, архитектурные решения.

Но последние недели я ощущаю, как всё это теряет актуальность буквально на глазах.

Не сами знания — их значимость для разработчика.

Я перешёл на написание кода исключительно через AI. И по постам коллег вижу: так уже работает огромное количество профессионалов.

Это меняет всё — в первую очередь то, какие компетенции важны, а какие нет.

Писать код руками скоро перестанут совсем. А главными компетенциями разработчика становятся:
— общая ИТ-экспертиза: от SQL и алгоритмов до конфигурации Docker;
— глубинное понимание своего стека и его возможностей;
— архитектурное видение;
— продуктовое мышление;
— и главное — умение строить процессы разработки через AI.

Поэтому вектор канала меняется. Здесь будет о профессии разработчика будущего, а не о конкретных инструментах Flutter и Dart.

Что это значит на практике:

1. Я строю DartWay — open-source fullstack-фреймворк на Dart — и теперь буду делать это полностью открыто: решения, код, метрики, ошибки. Настоящий build in public, без глянца.
2. Буду показывать, как выглядит процесс, где код пишут агенты, а разработчик проектирует, ставит ограничения и проверяет результат.
3. Flutter и Dart никуда не денутся — но через призму «как из этого собирается продукт», а не «ещё один виджет недели».

Если вам это близко — оставайтесь, дальше интереснее всего.

И расскажите в комментариях: вы уже пишете код через AI — или пока руками?
  • ❤ 8
  • 🔥 5
  • 👍 4
Post #136 462
Внезапно обнаружил, что Claude Code может не только делать таски, но и:
- докрутить идею продукта
- составить стратегию его продвижения
- вести бэклог фичей
- автоматически поддерживать актуальную документацию и скиллзы для самого себя
- генерить контент о продукте (и постить его в соцсетях...)

И это всё в одном репо...

AI открывает абсолютно другое измерение...
  • 🔥 4
  • ❤ 1
  • 🤔 1
Post #135 503
Serverpod: «the ultimate backend for Flutter» — как он устроен

В прошлый раз обещал регулярно делиться про fullstack на Dart. Начнём с фундамента — Serverpod. Авторы называют его «the ultimate backend for Flutter», и на нём уже три года стоят все наши продакшн-проекты.

Сначала пара слов, что это за проект. Serverpod основал в 2021 Viktor Lidholt — бывший разработчик Flutter-команды в Google; в команде из Стокгольма есть и экс-тимлид Minecraft. Это не заброшенный пет-проект: ребята подняли инвестиции (посевной раунд €2.7M в начале 2025, суммарно около $7M). Свежий стабильный релиз — Serverpod 3, а прямо сейчас в tech preview катят Serverpod 4.

—

Теперь как это устроено. Главная идея одна: описываешь модель и метод один раз — а типизированный клиент, сериализацию и связку с базой Serverpod генерирует сам.

На пальцах:

1. Пишешь endpoint — обычный класс на Dart с методом, например Future<String> hello(Session session, String name).
2. Запускаешь serverpod generate.
3. На стороне Flutter вызываешь client.example.hello('world') — как локальную типизированную функцию. Никакого http-клиента руками, никакого Map<String, dynamic>, никакой ручной сборки JSON.

С моделями данных та же история: описал в одном месте → она живёт и на сервере, и на клиенте, и в базе. Поменял поле — ломается компиляция там, где контракт разъехался, а не прод в три часа ночи.

И это не голый RPC. Из коробки идёт то, что обычно собираешь руками неделями:

— ORM и миграции к PostgreSQL
— аутентификация
— кеш (in-memory и Redis)
— realtime через streaming и websockets
— планировщик задач и загрузка файлов

—

Теперь честно — наш опыт за три года.

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

Минусы: готовые модули аутентификации и чатов оказались негибкими и нерасширяемыми. Под реальные требования продукта мы упёрлись в их рамки и в итоге отказались — сделали своё. Из коробки удобно ровно до момента, пока тебе хватает того, как это задумали авторы.

—

В следующем посте ветки разберу Serverpod 4 из tech preview: там завозят агентный движок — hot-reload всего стека и связка с AI-агентом через MCP. Отдельный разговор. 🙂

А вы что держите под бэкендом в мобильных проектах — свой API на Node/Python или что-то из Dart-экосистемы?
  • 🔥 5
  • ❤ 2
  • 👍 2
Post #134 343
Сколько ты реально работал?

Раньше всё было понятно. Сел за работу в 8, закончил в 12 — потратил 4 часа. А оценка — это просто попытка предсказать заранее, сколько времени уйдёт.

Пришёл AI — и работа стала выглядеть иначе.

Закинул задачу в чат, обсудил, поставил в работу. Между другими делами заходишь проверить, что там нагенерилось. Что-то поправил. Протестил. Выпустил.

Прошло полдня. Но сколько из них ты реально работал над задачей? 🤔 20 минут?

— — —

И как выставить это клиенту?

20 минут по ставке — не хватит даже на кофе.
Писать «полдня» — нечестно.

Правда где-то посередине. Только где именно — непонятно.

— — —

Ладно время. Есть вопрос неудобнее — про ценность.

Клиент и сам мог вкинуть текст задачи из трекера в Claude. И если ты ничего не корректировал — выходит, ты и не добавил ничего сверху?

Но ты же проверил. Убедился, что оно работает, а не просто выглядит рабочим.

И вот тут затык. Получается, отдать разработку ассистенту всё-таки нельзя — кто-то должен отвечать за результат. Но и продавать часы, которых не было, тоже странно.

— — —

Для себя я этот вопрос пока не закрыл. И, кажется, индустрия тоже.

💬 А вы за что берёте деньги с клиента в эпоху AI — за время, за результат или за то, что взяли ответственность на себя?
  • ❤ 1
  • 🔥 1
Post #133 404
После длительного перерыва я возвращаюсь к идее публичного релиза DartWay

Готовлю пакеты и example к публичному использованию, добавляю интересные фичи на каждый день

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

Поделитесь в комментариях - что хотели бы видеть в базовом проекте?
Что необходимо в каждом проекте и здорово иметь из коробки?
  • 🔥 4
  • ❤‍🔥 2
  • 👍 1
Post #132 495
ValueNotifier — недооценённый инструмент. И его потолок

Когда заходит разговор про state management, в ответ звучат три слова: Provider, Riverpod, BLoC. ValueNotifier как будто не считается за взрослое решение.

А зря. И одновременно — не зря. Разберём честно, без фанатизма.

Это встроенный в Flutter Listenable с одним значением. Меняешь .value — слушатели уведомляются. Оборачиваешь кусок UI в ValueListenableBuilder — и пересобирается только он.

final isSaving = ValueNotifier(false);

ValueListenableBuilder(
valueListenable: isSaving,
builder: (_, saving, __) => SaveButton(loading: saving),
);


— — —

✅ Где он реально хорош

1. Ноль зависимостей. Это Flutter из коробки. Не тащишь библиотеку ради одного флага.
2. Гранулярные ребилды. Перерисовывается только обёрнутый виджет, а не весь экран. Часто чище, чем setState.
3. Локальное состояние фичи. Тоггл, поле формы, шаг визарда, выбранная вкладка — то, что живёт внутри одной фичи и наружу не торчит.
4. Никакой магии. Явный контракт: вот значение, вот кто его слушает. Легко читать через полгода.

Именно поэтому он хорошо ложится на декомпозицию фич: маленький изолированный модуль наружу отдаёт пару ValueNotifier — и всё.

— — —

⚠️ Где подводит — и это важно знать заранее

1. Уведомление по ==, а не по факту изменения. Самые частые грабли — мутабельные объекты:

final items = ValueNotifier<List<Task>>([]);

items.value.add(task); // ничего не произойдёт — ссылка та же
items.value = [...items.value, task]; // сработает — новый список


Пока значения примитивные — всё ок. Как только внутри список или своя модель — надо дисциплинированно возвращать новый объект.

2. Нет производного состояния. Нужно собрать UI из двух-трёх источников — начинаются вложенные ValueListenableBuilder. Три уровня вложенности — и читается это уже хуже, чем то, от чего вы убегали.

3. Нет асинхронности из коробки. Loading / data / error вы строите руками. У Riverpod это AsyncValue бесплатно — и для экранов с загрузкой это реально экономит код и ошибки.

4. Нет экосистемы. Ни DI, ни скоупинга, ни autoDispose. Создал — сам не забудь dispose(). На одном экране — мелочь, на десятках — источник утечек.

5. Соблазн раздробить состояние. Десяток нотифаеров, сшитых колбэками между собой — это ровно та «фрагментированная каша», что и монструозный стейт, только с другой стороны.

— — —

С flutter_hooks — ещё проще

Хуки убирают главный рутинный минус — ручное создание и dispose. И тут есть два инструмента, которые часто путают:

— useState(0) — создаёт ValueNotifier и сразу подписывает виджет: поменял .value — хук-виджет пересобрался. Для состояния, которое рисует сам этот виджет.
— useValueNotifier(0) — только создаёт стабильный ValueNotifier между ребилдами, но НЕ подписывает. Когда нотифаер нужно передать вниз или слушать точечно (например, отдать в ValueListenableBuilder), не перерисовывая весь виджет.

Оба переживают ребилды и сами делают dispose. По хукам будет отдельный пост — там подробнее.

— — —

Где проходит потолок

Переходить на Riverpod/BLoC стоит, когда появляется хотя бы одно:
— состояние шарится между несколькими фичами;
— значение вычисляется из нескольких источников;
— это асинхронные данные с загрузкой и ошибками;
— сложный жизненный цикл и зависимости, которые руками уже не удержать.

— — —

Вывод

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

Поэтому вопрос не «какой стейт-менеджер правильный». Вопрос — видишь ли ты, где заканчивается зона комфорта простого решения. А чтобы это видеть, надо знать минимум два подхода и понимать цену каждого. Вот это и есть архитектурное решение, а не выбор библиотеки.

А вы используете ValueNotifier? В каких случаях?
  • 🔥 4
  • ❤ 3
Post #131 495
🤖 Авто-ревью на Claude: как настроили и на какие грабли наступили

Подключили автоматическое код-ревью (Anthropic Claude) на каждый PR в develop. Ниже — рецепт и нюансы, чтобы вы не потратили на это полдня, как мы 🙂

Что нужно один раз

Поставить GitHub App Claude на репо (/install-github-app из Claude Code или вручную).

Сгенерить долгоживущий OAuth-токен: claude setup-token (логин аккаунтом с активной подпиской Claude) → положить в секрет репо CLAUDE_CODE_OAUTH_TOKEN: gh secret set CLAUDE_CODE_OAUTH_TOKEN --repo <org>/<repo>

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

Добавить workflow .github/workflows/claude-review.yml.

Рабочий конфиг (в тексте промта есть плейсхолдер для добавления вводных по архитектуре вашего проекта)
name: Claude PR Review
on:
pull_request:
types: [opened, synchronize, ready_for_review, reopened]

permissions:
contents: read
pull-requests: write
issues: write
id-token: write # ← без этого не пройдёт OIDC-обмен токена

concurrency:
group: claude-review-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
review:
if: ${{ github.event.pull_request.head.repo.fork != true }}
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
track_progress: true # ← сводный комментарий
prompt: |
REPO: ${{ github.repository }}
PR NUMBER: ${{ github.event.pull_request.number }}
<инструкции ревью + что пропускать>
Для построчных замечаний используй mcp__github_inline_comment__create_inline_comment (confirmed: true).
Для сводки — gh pr comment. Публикуй только через GitHub-комментарии.
claude_args: |
--model claude-opus-4-8
--max-turns 50
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*)"


Грабли, на которые наступили (главное)

Workflow validation failed на каждом PR. Экшен требует, чтобы файл workflow был идентичен версии на default-ветке репо. У нас default = master, а файл лежал только на develop → падало всегда. Фикс: workflow должен быть на default-ветке.

Нет id-token: write → OIDC-обмен токена не проходит. Это разрешение обязательно.

401 Invalid bearer token. Токен в секрете был невалиден - скопирован с переносом строки. Проще всего просто перевыпустить токен claude setup-token и скопировать аккуратно.

Быстрая проверка токена вручную:
curl -s -o /dev/null -w "%{http_code}" https://api.anthropic.com/v1/messages \
-H "authorization: Bearer $TOKEN" -H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: oauth-2025-04-20" -H "content-type: application/json" \
-d '{"model":"claude-haiku-4-5-20251001","max_tokens":1,"messages":[{"role":"user","content":"hi"}]}'

200 = живой, 401 = бракованный.

Ошибка скрыта в логах. По умолчанию экшен маскирует вывод SDK («full output hidden for security») — настоящей ошибки не видно. На время отладки добавить show_full_output: true (репо приватный — в логи видит только команда), потом убрать.

error_max_turns. Дефолт --max-turns 10 мал: на большом PR Claude сжигает ходы на чтении сгенерённого/iOS-кода и не успевает написать ревью. Подняли до 50 + в промпте велели пропускать сгенерённые/платформенные файлы (tvolkova_client, **/generated/**, *.g.dart, *.pbxproj, локфайлы и т.п.).

Ревью отрабатывало, но не попадало в PR — результат лежал только в логе прогона.

Чтобы публиковалось:
track_progress: true → сводный комментарий;
в --allowedTools добавить mcp__github_inline_comment__create_inline_comment → построчные комментарии;
в промпте: «постить только через GitHub-комментарии, не выводить ревью текстом».

--allowedTools — это allow-list, так что туда же Bash(gh pr comm
  • 🔥 4
  • ❤ 2
  • 👍 1
Post #130 435
10 обновлений Flutter + Dart за полгода, которые стоит знать

Current Flutter version: 3.44 (18 мая 2026, с Google I/O). За полгода — два крупных релиза, 3.41 (февраль) и 3.44 (май), плюс хвост 3.38.

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

—

1. Agentic hot reload (3.44)
Главная фича релиза. Через Dart и Flutter MCP-сервер AI-агент сам находит запущенное приложение и делает hot reload после правки UI. Просишь агента поменять экран — и сразу видишь результат без ручных действий. Первый релиз, где AI-воркфлоу встроен в ядро, а не прикручен сбоку.

2. Dart и Flutter Agent Skills (3.44)
Пошаговые инструкции для AI-агентов под конкретные задачи — например, настройка интеграционных тестов или локализации. Если работаете через Cursor или похожие инструменты — агент перестаёт «угадывать», как делать типовые вещи.

3. Swift Package Manager по умолчанию (3.44)
На iOS и macOS SwiftPM теперь дефолтный, CLI мигрирует Xcode-проект автоматически. Плагины на CocoaPods пока работают через fallback с предупреждением — проверьте свои зависимости заранее.

4. Hybrid Composition++ на Android (3.44)
Решает старую боль Platform Views — компромисс между частотой кадров и качеством. Композитинг уходит на уровень OS через Vulkan и SurfaceControl: плавный скролл, нормальный ввод, рабочий SurfaceView. Пока opt-in через --enable-hcpp. Актуально всем, у кого в приложении нативные вьюхи — карты, вебвью.

5. Десятки тысяч устройств помимо телефонов (3.44)
Flutter официально работает в мультимедиа-системе Toyota RAV4 2026, а LG готовит webOS SDK для телевизоров (с hot reload, Riverpod, Firebase). Canonical стал ведущим мейнтейнером Flutter Desktop. Направление понятно: embedded и большие экраны — уже не экзотика.

6. Material и Cupertino заморожены в ядре (3.44)
Оба набора больше не правятся внутри фреймворка — это подготовка к переезду в отдельные пакеты material_ui и cupertino_ui со своим версионированием. На практике: обновления дизайн-системы смогут выходить отдельно от SDK. Если планируете миграцию на Material 3 — стоит учитывать сразу.

7. Dot shorthands (Dart 3.10 / Flutter 3.38)
Вместо MainAxisAlignment.center пишете просто .center — Dart выводит тип из контекста. Работает с enum-ами, конструкторами, статиками. Визуальный шум в widget-деревьях заметно падает.

8. GenUI на протоколе A2UI (3.44)
Вместо простыней markdown AI-агент собирает настоящий Flutter UI на лету. Пока эксперимент, но уже есть рабочие демо. Для тех, кто строит AI-native интерфейсы — направление, за которым стоит следить.

9. DevTools и Widget Previews быстрее (3.44)
DevTools перевели на WASM по умолчанию — стали отзывчивее. Widget Previews теперь опираются на Dart Analysis Server и съедают до 50% меньше памяти IDE. Мелочь, но именно такая, что длинные сессии становятся менее болезненными.

10. AGP 9 и встроенный Kotlin (3.44, Android)
Предупреждение для Android-команд: в AGP 9 Kotlin встроен, и ручное подключение Kotlin Gradle plugin может ломать билды. Если поддерживаете плагины — минимальный constraint теперь Flutter 3.44.

—

Главное наблюдение за полгода: Flutter перестал быть «просто фреймворком для виджетов». Два вектора очевидны: AI-native разработка (agentic hot reload, GenUI, Agent Skills) и выход за пределы телефонов (машины, телевизоры, десктоп). Кто не читает release notes — пропускает не мелкие правки, а смену направления.
  • 🔥 8
  • 🥰 4
Post #129 467
Запускаю 2-й поток DartWay Level Up 🚀

Курс про то, что остаётся за кадром рядовых туториалов: архитектурные решения и глубинное понимание.
Вас ждёт 4 вебинара и плотные ДЗ с обратной связью и код-ревью.

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

Если интересно, заполните анкету — спишемся для знакомства, и я расскажу обо всём подробнее.

👉 Ссылка на анкету - https://forms.gle/o4HbKfKVs3YarUhV6
Google Docs Заявка на участие в обучении For english - please, contact me directly @eu_novikov on Telegram DartWay Level Up - практический курс про то, что обычно остаётся за кадром туториалов: архитектурные решения и глубинное понимание, как устроены Flutter-приложения. 4 вебинара + плотные ДЗ…
  • ❤ 3
  • 🔥 1
Post #128 491
Как ищется работа Flutter-разработчиком в 2026 — цифры

Ситуация на рынке сейчас запутанная: новости противоречат друг другу, ощущения — статистике. Я постарался собрать разные данные в одну картину. Цифры — из источников, ремарки — мои.

—

🌍 Что происходит на глобальном рынке

Сокращения идут третий год: 264 тысячи уволенных в tech в 2023, 152 тысячи в 2024, 122 тысячи в 2025 (Layoffs.fyi). Вакансий для разработчиков на 33% меньше, чем до пандемии (Indeed Hiring Lab). Salesforce за весь финансовый 2026 год не нанял ни одного нового инженера — CEO объясняет это AI-инструментами. Amazon сократил 14 тысяч позиций и прямо назвал причиной эффективность от AI.

При этом общее число работающих разработчиков почти не изменилось: 3,26 млн в 2022 против 3,24 млн в 2024 (Бюро статистики труда США). А официальный прогноз на десять лет вперёд — рост занятости на 15%.

🤔 И как это понимать? Прогноз роста на 15% — при том, что крупнейшие компании сокращают людей и публично хвастаются, что наняли ноль инженеров. Похоже, никто не знает, куда идёт рынок — все ждут чуда от AI и боятся инвестировать в людей, пока нет ясности.

—

🇷🇺 Рынок России

Конкуренция. Вакансий в IT за 2025 год стало на 22% меньше — впервые с 2019-го. Резюме стало на четверть больше. На одну вакансию приходит 100–300 откликов. На джуниорские — до 500.

Структура спроса. 43% всех позиций рассчитаны на специалистов с опытом 1–3 года. Ещё 17% — без опыта. При этом аналитики пишут про дефицит опытных middle и senior разработчиков.

Сроки. Нормальный срок поиска работы сейчас — от 2 до 6 месяцев. Когда компания вас выбрала, процесс идёт быстро: 1–2 недели от первого контакта до оффера.

Деньги. Медианная зарплата middle мобильного разработчика — около 228 000 ₽ в месяц (Хабр Карьера).

🤔 Тут тоже не сходится. Если у джунов 500 человек на место, а опытных «не хватает» — выходит, после 1–3 лет опыта вас с руками отрывают? Верится с трудом. Подозреваю, что «дефицит сениоров» — это дефицит сениоров на те зарплаты, которые компании готовы платить.

—

🌍 Глобальный рынок: деньги и найм (remote)

Деньги. Middle: $105–140K в год. Senior: $150–205K (KORE1, апрель 2026). Надбавка за работу в Bay Area — всего 8–12%. Где вы живёте, почти не влияет на зарплату.

Как вас находят. Рекрутёры пишут прямо: LinkedIn показывает должности, а не навыки. Поэтому кандидатов ищут через GitHub — смотрят авторов Flutter-проектов и мейнтейнеров пакетов на pub.dev с активностью за последний год. Публичный код — это резюме, которое работает без вас.

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

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

—

Два вывода:
1. Ситуация абсолютно неопределённая — но это не специфика Flutter или вообще разработки. Судя по бесконечным постам в LinkedIn, ровно то же самое творится во многих других сферах. Так что дело не в том, что «Flutter умирает» или «джунов больше не берут». Колбасит весь рынок труда сразу.
2. Из-за AI рынок замыливается: AI-отклики, AI-рекрутеры и прочая автоматизация с обеих сторон. Сигнал тонет в шуме. И поэтому ещё большую ценность, чем раньше, приобретают альтернативные каналы — личный бренд разработчика, участие в некоммерческих и open-source проектах, ну и самозанятость: в форме стартапа или одного удачного приложения. Когда обычная воронка забита ботами, выигрывает тот, кого находят в обход неё.

—

Но это всё статистика, а у статистики, как видите, концы с концами сходятся плохо. Самое ценное — ваш реальный опыт. Искали работу в последний год? Нанимали сами? Расскажите в комментариях, как оно изнутри — сверим цифры с жизнью.
  • 🔥 4
  • ❤ 2
  • 👍 1
Post #127 412
Бэкенд на Dart — уже не экзотика

2–3 года назад Dart не рассматривался за пределами Flutter, а бэкенд-пакеты рассматривались скорее как упражнение, а не как реальный инструмент для продакшн-разработки.

Но я авантюрист, мне очень понравилась концепция Serverpod, и мы начали использовать его ещё 3 года назад — это была версия 1.1. С тех пор было много трудностей, но глобально я не пожалел ни разу.

Сейчас Dart становится всё более распространённым, и хотел бы отрекламировать его как язык для бэкенд и fullstack разработки.

Почему это имеет смысл:

1. Dart — классный язык. Строгая типизация, sound null safety, AOT-компиляция в нативный код. На сервере он чувствует себя ничуть не хуже, чем в мобильном приложении.

Поработав с ним, я с трудом представляю, чтобы когда-то снова захотел пробовать Python или JavaScript… И причин для этого не знаю.

2. Нет context-switching. Кажется мелочью, но использование единой экосистемы и управления пакетами очень сильно разгружает голову и упрощает работу с большим репозиторием и инфраструктурой.

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

3. Общая логика между клиентом и сервером. Например, модели данных: описали один раз — используете везде. Никакого дрейфа между тем, что возвращает API, и тем, что ожидает приложение. Никаких Map<String, dynamic>. Ошибка в контракте — это ошибка компиляции, а не runtime-краш в продакшне.

—

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

Dart Frog — противоположная философия. Минималистичный роутер, файловая маршрутизация как в Next.js, база — любая. Идеален для микросервисов и serverless. Но клиентские вызовы пишете руками.

Shelf — официальная базовая библиотека для веб-серверов на Dart. Низкоуровневая, зато без рамок — многое в экосистеме построено поверх неё.

Наш DartWay — фреймворк для fullstack Dart — сейчас базируется на Serverpod. Но в перспективе планируем уйти от него в пользу более лёгкого решения.

—

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

Тема большая, в один пост не уместить. Постараюсь регулярно делиться контентом про fullstack Dart — от архитектуры до конкретных решений из практики.
  • 🔥 7
  • ❤ 3
  • 👍 2
  • 🕊 1
Post #126 376
Дегенеративный AI

AI убивает программистов. Но не так, как об этом говорят.

Не отнимает работу. Не заменяет. Просто тихо атрофирует главный навык — способность погружаться в незнакомое и разбираться самому.

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

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

AI этот дискомфорт убирает. Копируешь стектрейс в чат — получаешь ответ. Баг починен. Но вы так и не поняли, почему он был. Один раз — ничего. Каждый день — атрофия.

— — —

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

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

AI ускоряет меня в моменте, но лишает практики - и это очень опасно.
  • 🔥 9
  • ❤ 3
  • 💯 2
Older posts →
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →