Привет всем.

Расскажу про свой личный опыт разработки через Qwen 3.6 Plus и Qwen ClI. И да, статья полностью написана человеком.

Это небольшой pet-проект, сделанный в момент, когда Qwen 3.6 Plus был бесплатным с лимитом в 1000 запросов в день. Проект представляет из себя фронтенд вымышленного интернет-магазина по продаже микрокомпьютеров.

Цель была протестировать возможности Qwen. На весь проект у меня ушло 4 дня по 2-3 часа.

День 1. Планирование

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

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

  1. «Архитектор». Проектирует, разбивает проект на шаги, создает документацию для других агентов;

  2. «Кодер». Собственно пишет код;

  3. «Тестировщик». Пишет тесты;

  4. «Ревьюер». Проводит ревью «Кодера»;

  5. Контент-мейкер». Делает тексты-заглушки для сайта.

Я сам выбрал стек - Typescript, Next, React, Zustand, Chakra, Jest.

Далее в чате я набрал промпт, где собственными словами описал то, что хочу получить и попросил сделать уточняющий промпт для роли «Архитектора».

Обработав этот промпт, «Архитектор» сделал несколько md-файлов:

  1. architecture - описание архитектуры проекта;

  2. components - подробное описание компонентов;

  3. data-flow - взаимосвязь компонентов через mermaid-диаграммы;

  4. implementation - план реализации с поэтапной разбивкой (всего получилось 17 этапов)

Эти файлы пришлось переделать несколько раз. В первом варианте «Архитектор» сам начал писать код, а после уточнения роли еще и попытался прятать код в комментариях.

Далее я добавил mcp для работы с файловой системой и через «Архитектора» сделал скиллы для всего стека.

День 2. Подготовка

На второй день я вручную добавил информацию о товарах и картинки (с bananaPi).

Также я решил, что оставлю за собой всю работу с git и буду самостоятельно проверять каждый коммит (в итоге «Ревьюером» я воспользовался лишь один раз).

В этот день свою работу начал «Кодер», который установил все необходимые зависимости, сделал парсинг md-файлов, сторы Zustand и базовый layout.

День 3. Основной функционал

В этот день через «Кодера» был завершен весь основной функционал:

  1. компоненты товаров;

  2. главная страница;

  3. страница товара;

  4. страница избранного;

  5. страница корзины;

  6. страница контактов;

  7. страница «о компании»;

  8. 404;

«Тестировщик» написал все тесты, а «Контент-мейкер» тексты-заглушки.

После каждого этапа я вручную и тщательно проводил ревью, а также вручную тестировал результаты работы. Я убедился в том, что с агентами нужно постоянно вести «диалог» и спрашивать почему они пришли к тому или иному решению, можно ли сделать лучше.

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

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

Рис.1 Корзина
Рис.1 Корзина
Рис.2 Избранное
Рис.2 Избранное

День 4. Дополнительные фичи и полировка.

В этот день я решил посмотреть как «Кодер» работает с 3D (Three.js). В hero-section главной страницы я попробовал добавить 3D-модель микрокомпьютера. Однако результаты оказались посредственными (видимо общие модели пока плохо работают 3D графикой) и пришлось довольствоваться обычным SVG.

Также были добавлены некоторые фишки и завершено ручное тестирование.

Рис.3 Каталог на главной странице
Рис.3 Каталог на главной странице

Итог. За 4 дня работы удалось сделать вполне нормальный фронт для Интернет-магазина. Еще год назад я крайне скептически относился к возможностям ИИ в кодинге, однако нейросети в этом плане удивительно быстро развиваются. В своем проекте я фактически совместил роли техлида и ручного тестировщика. Всю остальную работу выполнили агенты (ручные правки — примерно 15%).

Главное, что я усвоил, программирование при при помощи ИИ — это нахождение баланса между скоростью и пониманием проекта, что с агентами нужно быть в постоянном диалоге.

Жаль, что Alibaba закрыла бесплатный доступ к облаку.

Весь проект

Значит будем пробовать локальные модели :-)

Комментарии (11)


  1. martelle
    25.04.2026 17:21

    Here are the real problems I found in a quick pass. Ordered roughly by impact.

    High impact

    1. SSR is broken — entire page is empty until hydration. src/app/ClientShell.tsx:35-37 returns null until hydrated === true. Since ClientShell wraps {children} in the root layout, every server-rendered HTML response is an empty

    . You lose SEO, lose initial paint, and break crawlers — for a product catalog this is the worst of both worlds (SSG pages built but never sent to the client). Fix: render the tree on the server too, and only guard the truly client-only bits (theme class, drawer state).

    1. /api/order trusts client-supplied totals. src/app/api/order/route.ts:21-66 validates types but never recomputes subtotal, deliveryCost, or total from the catalog. A client can POST { items: […], total: 0 } and pass
      validation. Even as a mock, the shape of this API teaches the wrong pattern. Fix: look up prices server-side from getAllProducts() and ignore the client’s totals.

    2. Quantity is added by a loop instead of passed in. src/app/product/[slug]/ProductPageClient.tsx:38-40:
      for (let i = 0; i < quantity; i++) { addItem(productData);
      }
      cartStore.addItem already takes a quantity argument (cartStore.ts:37). The loop triggers N store updates / N re-renders for one user action. Fix: addItem(product, quantity).

    3. mounted flag in ProductPageClient is wrong. ProductPageClient.tsx:23-29 uses useState(() => typeof window !== “undefined”). The lazy initializer runs once per render on each environment: false on the server, true on the very
      first client render. That mismatch is exactly what causes hydration warnings — the standard fix is useState(false) + useEffect(() => setMounted(true), []). Right now you may be papering over a hydration error rather than avoiding it.

    Medium

    1. Double error toast on contact form failure. ContactForm.tsx:83-87 toasts “Ошибка отправки”, but the page-level handleSubmit (contact/page.tsx:27-33) already toasted “Ошибка валидации” with the field list. User sees two toasts. Pick one layer to own error UI.

    2. cartStore.migrate mutates its input and returns the wrong type. cartStore.ts:118-127 casts persistedState to Record<string, unknown>, mutates it, and returns it as unknown. The signature should be (state, version) => CartState. Mutating persistedState is also brittle — return a new object.

    3. Hardcoded 5 for delivery cost in two places. cartStore.ts:107 (getDeliveryCost) and cart/CartPageClient.tsx:139 (). They will drift. Single source of truth.

    4. Module-level products cache never invalidates. lib/products.ts:20 keeps the parsed Markdown in memory forever per server instance. Fine for prod SSG, but in next dev you’ll edit a .md file and not see the change without a
      server restart unless clearProductsCache is called.

    5. Redundant store calls re-run on every state change. cart/CartPageClient.tsx:31-33:
      const subtotal = useCartStore((state) => state.getSubtotal()); The selector recomputes for every change anywhere in the store (delivery toggles, etc.), and Zustand re-renders only because the result is shallow-equal. Works for primitives, dangerous if you ever return an object. Cleaner: const items = useCartStore(s => s.items) and compute subtotal locally with useMemo.

    Minor

    • package.json name is “pinapple-pi-2.0” (missing a p) — directory and project name are pineapple-pi-2.0.

    • Three files use eslint-disable react-hooks/set-state-in-effect (ClientShell.tsx, Header.tsx, CookieBanner.tsx). The pattern they’re disabling — setState inside useEffect to mark “hydrated” — is the same SSR anti-pattern as #1; the lint rule is telling you something real.

    • src/app/favicon.ico and metadata.icons.icon: “/favicon.svg” both exist; Next will auto-pick favicon.ico for / while metadata insists on .svg. Pick one.

    • ProductCard.tsx:58-68 wraps a

    • marked token cast in lib/markdown.ts:109 (as import(“marked”).Tokens.List & { items: … }) — fragile if marked changes shapes. Use the official Tokens.ListItem type.

    The top three (SSR, server-side price trust, quantity loop) are the ones I’d fix first. Want me to patch any of them?


  1. martelle
    25.04.2026 17:21

    >За 4 дня работы удалось сделать вполне нормальный фронт для Интернет-магазина

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


    1. Dhwtj
      25.04.2026 17:21

      Фронт нормально они научились не так и давно.


    1. Retro_tactic Автор
      25.04.2026 17:21

      Ну так посмотрите код, ссылку на репо я оставил и после этого уже можете говорить, что под капотом "не очень". Я так понимаю ревью вы тоже провели нейросетью.


      1. Retro_tactic Автор
        25.04.2026 17:21

        Я не говорю, что нейросети сейчас могут во все и всех заменят. Еще год назад я был крайним скептиком насчет них, но они развиваются и в плане кодинга достаточно быстро.


  1. Dhwtj
    25.04.2026 17:21

    А не пытались сравнить с написанием одним LLM, есть ли смысл в этой своре агентов?

    Метрики. Время создания, стоимость, качество, вмешательство человека

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


    1. Retro_tactic Автор
      25.04.2026 17:21

      LLM была одна - Qwen3.6 Plus, просто несколько ролей, с которыми я работал последовательно. Время создания я указал в статье. Вмешательство от меня было не сильно большим (15% правок). Скорей это немного утомительно - постоянно проводить ревью.


    1. CadMan
      25.04.2026 17:21

      Есть большая необходимость назначать роли и использовать субагентов.

      Субагент работает только в своём контекстном окне и строго по своим правилам. Делая ревью таким образом, он находит массу ошибок после условного субагента кодера.


  1. r3code
    25.04.2026 17:21

    Параграф Цитата Удалить Параграф Цитата Удалить а откуда новость про закрытие доступа? Вы через что подключались? Почему именно cli, а не готовая Lingma IDE от Alibaba?


    1. Retro_tactic Автор
      25.04.2026 17:21

      Цель была протестировать Qwen в кодинге, а не IDE. Поэтому я выбрал наиболее простой инструмент. Информация о закрытии доступа - с официального github, да и в самой cli теперь соответствующие сообщение появляется. Закрытие для бесплатного доступа, конечно же.


  1. imintsev
    25.04.2026 17:21

    Так Qwen CLI больше не работает через OAuth. Только через токены, а это дорого.