
Есть у меня один знакомый. Преподаватель. Примерно, раз в месяц принимает экзамены у студентов, с курсов повышения квалификации. Студенты решают задания на компьютерах, а он ходит между ними, вопросы задает и двойки ставит.
Вот только ходить приходится с бумажными ведомостями. Ведомости эти, постоянно падают на пол, студенты в них подглянуть норовят. Если в ведомости надо что-то исправить, то приходится зачеркивать и грязь разводить. А затем, результаты экзамена надо внести в компьютер.
И настолько эта возня с бумагой его достала, что знакомый решил:
"Хватит это терпеть! Говорят, в соседнем дворе бабушка сама написала себе приложение для продажи недвижимости (находясь под воздействием). А я что? Лысый что ли?!
Вон, даже курсы по вайбкодингу продаются! Напишу сам себе электронную ведомость!
Может ведь обы��ный человек написать любую программу.
Ну не будут же врать в Интернете."
А вот и нет.
Никакого знакомого нет
Это я сам.
Большими языковыми моделями, в работе, пользуюсь постоянно. Правда специфика работы такая, что 90% программ, написанных за последние годы, умещаются в пол экрана. В основном - скрипты анализа логов, снятие дампов в нужный момент, запуск трассировки когда все стало плохо, простейшие мониторинги (на коленке) и т.д.
Иногда, даже специально придумываю, чтобы эдакое побольше написать руками. Расширение для PostgreSQL - было настоящей отдушиной.
И вот тут мир LLM я открыл для себя с лучшей стороны. Моментально перестаешь "красноглазить", запоминать 100500 параметров каждой команды, или вспоминать: "А как это на ...таком языке... сделать?".
Спросил - получил готовый ответ. И он работает. Вот прям реально работает.
Но как было написано выше, есть еще преподавательская деятельность.
А там они - бумажные ведомости.
Нужно войди в зону комфорта
К идее вайбкодинга я относился осторожно. С одной стороны, примерно понимаю как работают LLM и каких сюрпризов от них ожидать.
С другой стороны, "вайбанутые" бегают кругами по всему Интернету и орут, что если ты не станешь как мы сегодня, то завтра уже опоздаешь.
Поэтому, разработку приложения для выставления оценок - воспринял как вызов. Хотел сам для себя понять, на сколько сейчас реально разработать нужное приложение под лозунгом: "Ни капли в рот, ни буквы в код!".
Допустим, проснувшись с утра, я осознал себя преподавателем ВУЗа. Вместо показа голых коленок (за "пятерку"), студентка установила мне Cursor и подключила к нему Claude.
Иностранный студент (за "тройку автоматом") оплатил со своей карты 20$ за месяц подписки.
Нужное делайте, не нужное - не делайте
Позволю себе дать один совет: делайте реально нужное (вам) приложение. Иначе вы попадете в ловушку "вау-эффекта" от первых шагов разработки.
Читал тут, как один человек разработал за день приложение по переводу из одних единиц измерения в другие. И на этом опыте делал выводы, что всё, программисты не нужны!
Мил человек, оно тебе зачем? Ежедневно из сантиметры в килограммы переводишь? Нет? А вот когда будешь ежедневно, то вдруг окажется, что немного неудобно. Надо поправить интерфейс. Начнешь править, а там как поедет одно за другим...
Расслабьтесь и откиньтесь на спинку кресла
Для понимания уровня сложности приложения (очень кратко):
создаем экзамен (указываем суммарный балл прохождения)
добавляем в него студентов
указываем список вопросов на экзамен
на закладке "Оценки" тыкаем в студента и за каждый вопрос ставим оценку от 2 до 5 и можно написать комментарий
у студента на экзамене еще можно задать IP машины за которой он сидит
можно назначить дату пересдачи экзамена
Основные заморочки с отборами студентов в окне оценок. Нам надо видеть кто прошел, кому задать доп. вопрос, кому и на какую дату назначена пересдача и сколько человек на эту дату уже есть.
Весь процесс разработки я не буду описывать. Многие пробовали и знают, что это такое. Кто не пробовал - советую самому попробовать, а не полагат��ся на чужое мнение.
Началось все так, что я аж крякнул от удивления. Минут за 40, этот дурень сделал мне первую версию приложения, и запустил его на эмуляторе. Причем, Android SDK уже был, я просто сказал ему, чтобы не вздумал качать, а использовал текущий.
Ну че ты начинаешь? Все хорошо же было.
Первое, что я понял: на текущем этапе, юрист не сможет сделать себе приложение типа "СоветникМинус".
Пока вы делаете приложение уровня "покажи мне котика из интернета", еще можно общаться на естественном языке. Но как только приложение должно делать что-то реальное - вы не сможете избежать терминов из программирования и особенностей языка (платформы) разработки.
Чтобы все было расставлено как надо, правильно нажималось\отжималось\показывалось, мне пришлось применять слова: Activity, ToggleButton, Text, ToolBar... и т.д.
По другому, "Он" просто не понимал.
Исправления одних ошибок генерируют другие.
"Вот новость!", воскликнет адепт, "надо было сказать, что не меняй эту часть.".
Сказал.
Все получилось гораздо хитрее: я запретил ему менять окно оценок, потом сказал исправить ошибку. Для исправления ошибки, "AIноагент" изменил структуру базы данных, и данные в одной из колонок, списка оценок, просто перестали показываться.
Нет, колонка там была (только пустая). Он действительно не тронул указанное окно.
Заметил я это уже на экзамене.
Ну я-то куда полез, я же читать не умею
А потом я полез в код.
Вся логика приложения в одном файле MainActivity.
Там все в кучу. И composable-функции и большая часть логики.
Нет, он конечно применил эдакий MVC (разделил данные от активностей и то благодаря использованию Room), но никаким структурным мышлением там и близко не отдает.
Отлично используются различные паттерны и фремворки типа Room (как уже было сказано), хотя я бы предпочел sqldelight.
Но когда у тебя в приложении 4 вкладки в нижнем меню, то наверное логично не пихать это все в один модуль, а разбить каждую вкладку минимум на 2 логических блока: view и функциональность (а уж сколько под этим будет реальных классов...).
Еще немало удивило, что все формы ввода экзаменов, студентов, вопросов, оценок - это кастомные AlertDiaolg'и. И да, весь их код тоже в MainActivity.
Как бы ладно, но это не по человечески что ли.. Ах, да...
Получается, чтобы разработанное приложение было нормально структурированным - эту структуру надо описать самому (удачи той самой ��абушке и хорошей погоды в "её" доме).
Настал тот день
И вот день экзамена. Специально не стал брать, доставшие до печенок, бумажные ведомости, взял только телефон и заветное приложение на нём.
Выставил первую оценку, написал комментарии, по ответам студента. Все отлично. Пару раз ткнул в разные фильтры. И оценка пропала. Совсем. Полностью. Вместе с комментариями.
Хорошо, что я выставил только одну оценку и помнил за что завалил несчастного. Внёс данные снова.
После чего, на протяжении всего экзамена, дрожащими пальцами делал скриншоты каждой выставленной оценки.
А кто же это сделал...
Пришлось потратить немало усилий чтобы понять, что произошло.
Сначала думал самое очевидное, что этот умник, в момент фильтрации списка, делает какую-то DML операцию. Но нет, тут он придерживается паттернов и фреймворков, что спасает.
Оказалось вот что:
Так как я не знаю IP машины студента, пока он физически за нее не сядет, то эти самые IP вношу "по ходу", открывая форму "Экзамена" и указывая там IP-адрес студенту.
А так как, таблица оценок связана с экзаменом внешним ключом, то у нее установлено onUpdate = ForeignKey.CASCADE. После перезаписи экзамена - все оценки затираются.
Но это не видно сразу, т.к. список оценок не получает уведомление об изменении данных.
И кажется, что оценки пропали после применения фильтра.
Достаточно было заменить, в описании внешнего ключа, onUpdate = ForeignKey.NO_ACTION и оценки перестали пропадать (да, тут не обрабатывается ситуация когда студента можно убрать из экзамена, но его запрещено убирать, если есть оценки).
Если бы я сам писал приложение, то вообще отказался бы от внешних ключей и всю целостность данных обеспечивал в коде, а не полагался на СУБД.
Что по времени
Чистого времени "вайбанутой" разработки у меня ушло, примерно, 6 часов. Делал по вечерам, в течении недели.
Если делать самому, то (в силу привычки) сделал бы:
на Java с xml-лейаутами - часов за 8
на Kotlin + Compose - часов за 10
Какие мысли по итогу
За много лет, имею опыт программирования от микроконтроллеров AVR (до того, как они стали Arduino - эдаким 1С, в мире электроники), до разработки тиражных приложений на том же 1С. Ну и много чего там в промежутке, между низким уровнем и lowcode.
Для себя понял следующее: пока ты находишься на "низком уровне": прошивки устройств, интеграции с оборудованием, собственная ORM (бывало и такое)... - оно или работает или нет (в 99,99% случаев). Практически всегда видно, где произошла ошибка и в чем ее причина.
А вот как только логика разработки поднимается на прикладной уровень (или не дай бог уровень "денег"), то количество ошибок и сложность их поиска\исправления стремиться в бесконечность. Эти ошибки не так очевидны, они выявляются не сразу, а их исправление требует немало времени на исследование (как бы не сломать, что ни будь другое своим исправлением).
Именно поэтому, мы слышим дикие вопли с "Вайбанутовских болот", как там все прекрасно. Но при этом, не видим "Кембрийского взрыва" приложений в "сторах". Ко мне постоянно обращаются знакомые с вопросами можно ли разработать приложение, которое "..." и дальше описывают функциональность, нужную ну... 1-2 людям из миллиона.
��сть огромный, скрытый пласт, крайне-узкоспециализированных приложений. Программисты не хотят за них браться, т.к. денег там нет. А пользователи, пока, не могут это сделать сами. Как в октябре 1917 - "верхи не могут, а низы не хотят".
Для себя я решил, что "Вайбонизм" победит, когда наступит эра индивидуальных приложений. Когда вместо того, чтобы изучать чужое приложение, человек сделает его себе сам. Лично под себя. С перламутровыми кнопками и дизайном стиля "Циклоп" (смотреть на это можно только прищурившись одним глазом). А пока этого нет - увольте.
Скоро не будет людей, будет один ИИ
Можно ли "вайбкодингом" разработать большое и сложное приложение. Да можно.
Только для этого придется разбить структуру приложения на отдельные блоки и описать связь между ними.
И кто же на такое способен...? Ответ: "архитектор ПО", т.е. человек из высшей иерархии IT-специалистов. А тем временем, нам предлагают отказаться от джунов-мидлов, заменить их на ИИ. "Мы научим вас как! Деньги нести вот сюда..."
Этим самым, выбивается нижний пласт пирамиды профессионального роста. Откуда возьмется "архитектор" если он не был джуном?
Безусловно, ИИ повлиял и еще повлияет на процесс разработки. Но речь в статье была про "сейчас". И может показаться, что следом за этой фразой, я предлагаю...
Срочно всем вайбануться!
По моему мнению, курсы вайбкодинга, сейчас, сродни курсам "Научим вас правильно искать в Интернете, начала 2000-х" (олды помнят).
Сам помню как объяснял тогда, своему другу (фрезеровщику по образованию), как правильно писать запросы в поисковике, чтобы найти нужное. Он все никак не мог найти, что хотел, а я находил очень быстро.
У вас, или ваших знакомых, сейчас есть проблема с составлением поисковых запросов? Уверен, что нет.
Вайбкодинг - это инструмент, пользоваться которым, можно научиться очень быстро (а скоро и не надо будет учиться совсем).
Если вы понимаете как разрабатывать приложения, то с ним или без него - вы приложение сделаете.
Если не понимаете, то пока - это все мошеннические сказки бабушки, из соседнего подъезда.
А вот когда бубушка сама сможет сделать себе приложение, то вайбкодер ты или нет - роли играть не будет.
P.S. Так как своего телеграмм-канала нет, то здесь может быть ваш (нет).
Комментарии (21)

Robastik
16.12.2025 06:49За много лет, имею опыт программирования
и сравниваю с руководством разработкой, в чем опыта нет.

fedignat Автор
16.12.2025 06:49Ну как вам сказать, он есть.
Только я бы поделил этот опыт на 2 части:
1. "Руководство людьми" - у меня получился наихудший результат за всю историю руководства. Много раз предлагали должности начальника ... - отказывался.
2. Постановка задач, написание тех.проектов - поверьте, опыт есть. И, вполне себе, положительный.

rsashka
16.12.2025 06:49Вайбкодинг - это про эмоции от процесса программирования, а не про программирования без соответствующих знаний (все равно, что кухарке начать управлять страной). LLM это просто инструмент и не более того и если за программирование берется человек без нужных знаний и опыта, результат вполне очевиден.

fedignat Автор
16.12.2025 06:49В точку. Как и с фразой про "кухарку и государство", которая в оригинале звучит так:
"Мы знаем, что любой чернорабочий и любая кухарка не способны сейчас же вступить в управление государством... Мы требуем, чтобы обучение делу государственного управления велось сознательными рабочими и солдатами и чтобы начато было оно немедленно "
Т.е. чтобы управлять государством надо сначала долго учиться государственному управлению, а потом приобретать опыт.
Просто сейчас такой информационный фон вокруг вайбкодинга, что складывается ощущение: "Да там делать ничего не надо, только сиди себе и командуй, а он сам за тебя все сделает.".
На счет эмоций - они сначала прям "вау". Но в какой-то момент начинаешь понимать, что это что-то сродни "автокомплиту" (очень утрировано). Просто обычный инструмент. И проблем он подкидывает изрядно.

Sobakaa
16.12.2025 06:49Ничего нового. Различные ноу-код инструменты предлагаются годами. Я уж молчу про обфускаторы sql, где, не смотря на обещания, приходится знать и sql и псевдоязык очередной его убийцы.

MAXH0
16.12.2025 06:49Вейкбординг сейчас - это быть бесплатным бета-тестером для копроратов. Ну и еще обучающей моделью. Пока дают бесплатный сыр - его можно пользовать. Только Вас заставят платить по гамбургскому счету - вам потребуется оптимизировать процесс. И тут придется оптимизировать запросы и цепочки обработки запросов/генерации, подбирать модели по цене/качеству.
Кстати, многие кто сокращают на волне AI демпинга, потом, когда придется платить реальную цену, уже будут выбирать - кремниевая нейросеть или белковая обойдется дешевле и в каких задачах.
НО сейчас учиться вейкбордингу, возможно, и не стоит. Потому что всё слишком динамично меняется. Но держать руку на пульсе точно стоит. С другой стороны всегда можно перейти от творцов в пользователи и пользоваться готовым сервисом и настроенными генераторами.

akhmelev
16.12.2025 06:49Как же удивительны все эти рассуждения. И не надоедает же. Подлодка джавовая уже больше года вещает взахлёб аи аи аи...
Чтобы понять инструмент посмотрим под капот. Ембеддинги после многоголовой фокусировки тупо генерируют следующее слово. Это же просто экстраполяция в гиперпространстве. Что мы про нее знаем? Чем точнее опорные точки, тем точнее результат.
Поэтому надо тупо: очень точно и очень подробно в терминах выбранного стека технологий дать ТЗ со всеми ожиданиями и ограничениями. И будет шанс за одну-две итерации получить нужное решение. Причем вторая это не продолжение чата а рестарт с уточнениями. Помним про экстраполяцию, экстраполяция экстраполяции до добра не доведет. В другом чате на этот код строим тесты, в третьем просим ревью. Это уже совсем не вайб, а реально работа примерно как у тимлида.
Наступает момент когда запросы таковы, что тесты будут сходиться с генерацией а в ревью нет того с чем можно однозначно согласиться. Можно считать, что наконец-то пошла польза, все что до этого момента - бирюльки, игрушки, вайб, короче трата времени. Итак, получилась разновидность программирования. Всего лишь. На простых задачах буст по времени будет. На сложных, без декомпозиции будет ад. Ну или если угодно вайб.

Bardakan
16.12.2025 06:49А вот как только логика разработки поднимается на прикладной уровень (или не дай бог уровень "денег"), то количество ошибок и сложность их поиска\исправления стремиться в бесконечность.
у вас есть чат и логи работы с ним. Вы могли их просмотреть и поискать в какой момент возникла ошибка. Вы их игнорировали? Cursor вообще хранит историю чата между запусками.
А еще есть git, в котором можно просмотреть историю изменений и найти комит в котором произошла ошибка. Вы его не добавляли в проект?Нет, колонка там была (только пустая). Он действительно не тронул указанное окно.Заметил я это уже на экзамене.
А было ли тестирование проекта?
Выглядит так, как будто это целиком и полностью ваш фейл, который вы решили спихнуть на LLM. Ок, но зачем писать статью об этом, обзываясь обидными словами?
panzerfaust
16.12.2025 06:49Выглядит так, как будто это целиком и полностью ваш фейл, который вы решили спихнуть на LLM
Вайбкодеры: просто следуй вайбу, просто напиши что хочешь получить, больше не нужно учить эти ваши ЯВУ и алгосики, лучший язык программирования - английский
Также вайбкодеры: ну это, у тебя вайб не тот, промпт не тот, модель не та, надо было QWERTY-сервер подключить и ASDFFGH-протокол заимплементить, MONET.md у тебя кривой какой-то, 5 секунд назад вышла новая нейронка SickFuck 4.20 и она рвет все бенчмарки

Bardakan
16.12.2025 06:49Хейтеры вайбкодинга: я установил курсор, написал в нем дословно "сделай за меня всю работу" - не получилось, написал "протестируй приложение" - не получилось, написал "исправь ошибки в проекте" - тоже не получилось. Вывод: все нейронки - фигня, вайбкодинг - фигня, крупные ИИ компании - мошенники, продающие воздух и взвинчивающие цены на комплектующие. И еще напишу статью об этом на хабре, причем не буду указывать ни конкретную модель, ни конкретные промпты - и так сойдет.

panzerfaust
16.12.2025 06:49написал в нем дословно "сделай за меня всю работу"
Но ведь это именно то, что проповедуют свидетели Святого Преподобного Карпатия. Иначе придется признать, что нужно шарить сразу в бизнесе-аналитике, программировании и архитектуре, чтобы получать нормальное ПО, а не фуфло. О чем автор и пишет.

Bardakan
16.12.2025 06:49Это всего лишь две крайности людей: одни считают, что нейросеть сделает за них всю работу, другие - что нейросеть не умеет вообще ничего

fedignat Автор
16.12.2025 06:49у вас есть чат и логи работы с ним. Вы могли их просмотреть и поискать в какой момент возникла ошибка.
Какая ошибка? Ошибок нет. Я ровно про это и пишу, что когда ломается не тип данных, а логика приложения, то никакой компилятор вам ошибку не скажет. Все было прекрасно.
А еще есть git, в котором можно просмотреть историю изменений и найти комит в котором произошла ошибка. Вы его не добавляли в проект?
Есть. Какой комит там искать? По метке "Я специально здесь сделал ошибку?"
А было ли тестирование проекта?
Было. Как ручное, так и автоматическое (попросил создать тесты).
Вручную я прошел весь путь использоваения приложения и выявил то, что мне неудобно. Выявил ошибки, потом попросил их исправить. И так несколько итераций.
Причем, специально указывал, что не трогай функционал, который меня полностью устраивает.Выглядит так, как будто это целиком и полностью ваш фейл, который вы решили спихнуть на LLM.
Не целиком и не полностью. Я всеми силами пытался сделать рабочее приложение. Ровно такое какое мне нужно, с нужным интерфейсом и функционалом. А не "уфф... ну хоть так получилось сгенерировать...".
Ок, но зачем писать статью об этом, обзываясь обидными словами?
Обидные слова относятся не к людям, которые используют ИИ в своей работе. Я сам использую. Они относятся к тем, кто на волне ажиатажа, пытается впарить людям (за деньги или с умыслом) свои курсы и\или способ мышления, что "оно сделает все за вас, расслабьтесь".
Отвечая на ваш комментарий, я внезапно понял главную "филосовскую" проблему LLM - они не боятся (подозреваю, что это передается и фанатичным адептам вайбкодинга).
Если откинуть совсем бестолкового "джуна", то человек, уже с небольшим опытом, крайне осторожно будет относиться к изменениям в структуре базы данных. А LLM - не боится.
Он менял ее структуру как хотел, не думая о переносе или обновлении старых данных. Да, можно было сказать, что давай сделай совместимость с прошлой структурой. Но ведь оно обязательно вылезет в чем-то другом.Подозреваю, что у вас нет желания полезть внутрь ядра вашей системы и исправлять там что-то "размахивая лопатой". Вы будете делать это очень аккуратно, продумывая каждое действие. А "Он" - нет. Для ИИ - это просто код. Не более.

Bardakan
16.12.2025 06:49Какая ошибка? Ошибок нет. Я ровно про это и пишу, что когда ломается не тип данных, а логика приложения, то никакой компилятор вам ошибку не скажет. Все было прекрасно.
когда я хотя бы минимально проверяю за ИИ, то у меня таких проблем нет. Почему вы не стали так делать - не понятно
Есть. Какой комит там искать? По метке "Я специально здесь сделал ошибку?"
вы выше писали, что ии изменил вам данные. Вы не можете найти в git файлы, относящиеся к бд, и отследить историю их изменений? А также у вас перед комитом в git отображается список измененных файлов - список вы тоже не смотрели?
Причем, специально указывал, что не трогай функционал, который меня полностью устраивает.
есть сразу несколько особенностей нейросетей, которые могут влиять на это. Я тоже не нашел способа как "железно" заставить нейросеть соблюдать определенные правила. Даже рекомендуемые cursorrules периодически отваливаются.
Подозреваю, что у вас нет желания полезть внутрь ядра вашей системы и исправлять там что-то "размахивая лопатой". Вы будете делать это очень аккуратно, продумывая каждое действие.
предпочитаю баланс. Например, в моей работе ИИ неплохо экономит время при создании новых экранов для iOS проекта, но при этом упорно не понимает, как работать с "safe area" ("зарезервированные" системой области экрана). Также он неплохо генерит шаблонный код по команде "сделай то-то по аналогии"

fedignat Автор
16.12.2025 06:49Я прекрасно понимаю о чем вы пишите.
У вас мышление (как у меня и многих здесь, присутствующих) "сломано" годами опыта.
При вайб-разработке, вы наверняка говорите (условно): "В этом классе добавь метод который делает... Добавь экран на котором...".Вы идёте от подсистем\блоков\модулей приложения. Оперируете особенностями языка и архитектуры. В таком подходе вопросов нет.
А вот когда у вас почти готовое приложение и ты ему просто говоришь, что колонку из списка в первом окне убери и сделай такую же во втором (там придется LEFT JOIN в запрос добавить, т.к. второй список строится по другой таблице). Вот тут может быть что угодно. Вплоть до добавления дублирующей колонки во вторую таблицу БД. А то и удаления ее из первой (вместе с данными).
Если идти в своих командах от интерфейса\функциоала, то, что там будет меняться внутри кода\структуры - одному ИИ известно. А количество изменений (при таком подходе) может быть очень большое. Успустишь что-то - 100%.
Неокрепшим умам, пропагандируют "легкость" и "вайб", но за этой легкостью вида: "поменяй ширину поля ввода", может внутри потянуться такое, что разгребать потом можно неделями.

shaggyone
16.12.2025 06:49У вас, или ваших знакомых, сейчас есть проблема с составлением поисковых запросов? Уверен, что нет.
Справедливости ради, проблем с составлением запросов нет. Зато есть проблемы, что по однозначно составленному запросу находится всё кроме того, что искал. Проблема не новая, последние лет дцать ухудшается.

ponikrf
16.12.2025 06:49Недавно в топ кода моего вайбкодинка попала строчка
timer: NodeJS.Timeout | false = trueОбожаю потом нейросети спрашивать за такой генерированный код)

geornit25
16.12.2025 06:49Можно ли "вайбкодингом" разработать большое и сложное приложение. Да можно.
Только для этого придется разбить структуру приложения на отдельные блоки и описать связь между ними.
И кто же на такое способен...? Ответ: "архитектор ПО", т.е. человек из высшей иерархии IT-специалистов.
Да, тут автор верно подметил. На данный момент, ИИ не способен принимать осознанные архитектурные решения. Если четко не указать нужную структуру программы, требуемые технологические решения, используемые фрейворки, то в итоге можно получить настоящий "винегрет" из кода, который даже может будет работать, но это не точно.
Для себя выработал такой подход:
Держать контекст выполнения запроса настолько маленьким, насколько это возможно. Если нужно что-то исправить, то делать это в отдельном запросе, потому что пару раз попросите исправить ошибку и всё - контект размоется и ИИ потеряет нить рассуждения.
В кодовой базе иметь некий Markdown файл, где бы хранилось описание программы, текущее состояние разработки, какая часть функционала реализована, а какая нет, используемые технологии, ссылки на документацию (например в отдельных Markdown файлах), описание важных частей кода и т.д. В начале можно попросить ИИ создать такой файл и потом обновлять его. Это позволит ИИ оставаться сфокусированным на задаче и не терять нить рассуждений между запросами.
Ну и всегда иметь перед глазами написанный код, чтобы понять когда ИИ пошел не туда куда надо и оперативно исправить ситуацию.

Pusk1
16.12.2025 06:49У меня родной Русский. Могу писать на немецком и Английском. Пробовал писать по испански. Меня не особо понимают. Слишколм много ошибок и не так быстро, как я ожидал.
Условый вайбкодинг тоже требует определённых навыков. Управление контекстом, установка и использование MCP, разные роли для разных агентов, в код всё же нужно поглядывать, навыки применения TDD.
Сам люблю почитать код, но всё чаще замечаю, что вычитавыаю внимательно лишь изменения в ключевых частях, а с остальным просто соглашаюсь и запускаю тест. Для продуктовых экспериментов этого достаточно, а до красивого продового состояния есть кому довести.

alex_lol
16.12.2025 06:49О чем статья? Что ИИ пока ещё не может вам написать Ютуб? С этим даже "вайбанутые" (к которым я себя причисляю) соглашаются. О том, что писать программы с помощью ИИ не получится на данный момент человеку без минимальной компетенции в IT? - с этим тоже никто не спорит.
Но вот про это хочу:
Если вы понимаете как разрабатывать приложения, то с ним или без него - вы приложение сделаете.
Не верно. Вот пример - Про ИИ, который «ничего не умеет»
Если кому лень открывать статью, то кратко: задача для анонимного веб-чата написать блокировщик собеседников. Код сюда же привожу:
Скрытый текст
// ==UserScript== // @name Chatroulett WebRTC Blocker // @namespace http://tampermonkey.net/ // @version 1.2 // @description Мгновенная блокировка нежелательных WebRTC соединений для chatroulett.ru // @author Your Name // @match https://chatroulett.ru/* // @grant none // @run-at document-start // ==/UserScript== (function() { 'use strict'; // Инициализация черного списка const STORAGE_KEY = 'webrtc_blacklist'; const RECENT_IPS_KEY = 'webrtc_recent_ips'; // Функция для получения актуального черного списка const getBlacklist = () => JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]'); // Разделенные списки исключений const EXCLUDED_DOMAINS = [ 'chatroulett.ru', 'api.chatroulett.ru', 'webrtc.chatroulett.ru' ]; const EXCLUDED_IP_RANGES = [ '0.0.0.0/8', // Текущая сеть '10.0.0.0/8', // Частная сеть '100.64.0.0/10', // CGNAT '127.0.0.0/8', // Loopback '169.254.0.0/16', // Link-local '172.16.0.0/12', // Частная сеть '192.0.0.0/24', // Зарезервировано IANA '192.0.2.0/24', // TEST-NET-1 '192.168.0.0/16', // Частная сеть '198.18.0.0/15', // Тестовые сети '198.51.100.0/24', // TEST-NET-2 '203.0.113.0/24', // TEST-NET-3 '224.0.0.0/4', // Multicast '240.0.0.0/4', // Зарезервировано '255.255.255.255/32', // Broadcast '7.0.0.0/8', // Министерство обороны США '26.0.0.0/8', // Министерство обороны США '28.0.0.0/8', // Министерство обороны США '14.0.0.0/8', // Китай (публичная сеть, но часто используется для NAT) // подсеть хостинга видеочата '93.189.228.0/22' ]; // Функция для преобразования IP в число const ipToNumber = (ip) => { const parts = ip.split('.'); if (parts.length !== 4) return 0; let result = 0; for (let i = 0; i < 4; i++) { const part = parseInt(parts[i], 10); if (isNaN(part) || part < 0 || part > 255) return 0; result += part * Math.pow(256, 3 - i); } return result; }; // Функция проверки диапазона в CIDR нотации const isIPInRangeCIDR = (ip, cidr) => { const [network, prefix] = cidr.split('/'); const prefixLength = parseInt(prefix, 10); const ipNum = ipToNumber(ip); const networkNum = ipToNumber(network); const mask = ~((1 << (32 - prefixLength)) - 1) >>> 0; return (ipNum & mask) === (networkNum & mask); }; // Улучшенная функция проверки валидности IP const isValidIP = (ip) => { if (typeof ip !== 'string' || ip.trim() === '') { return false; } if (/[^0-9a-fA-F.:]/.test(ip)) { return false; } // IPv4 const ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; if (ipv4Regex.test(ip)) { return true; } // IPv6 (упрощенная проверка) const ipv6Regex = /^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/; const ipv6ShortRegex = /^((?:[0-9a-fA-F]{1,4}(?::[0-9a-fA-F]{1,4})*)?)::((?:[0-9a-fA-F]{1,4}(?::[0-9a-fA-F]{1,4})*)?)$/; if (ipv6Regex.test(ip) || ipv6ShortRegex.test(ip)) { return true; } return false; }; // Улучшенная функция проверки исключений const isExcluded = (value) => { // Проверка специальных адресов if (value === '0.0.0.0' || value === '::' || value === '0000:0000:0000:0000:0000:0000:0000:0000' || value === '255.255.255.255' || value.startsWith('192.0.2.') || value.startsWith('198.51.100.') || value.startsWith('203.0.113.') || value.startsWith('169.254.') ) { return true; } // Проверка доменов if (!isValidIP(value)) { return EXCLUDED_DOMAINS.some(domain => value.includes(domain)); } // Проверка CIDR диапазонов for (const cidr of EXCLUDED_IP_RANGES) { if (isIPInRangeCIDR(value, cidr)) { return true; } } return false; }; // Функция для сохранения черного списка const saveBlacklist = (blacklist) => { localStorage.setItem(STORAGE_KEY, JSON.stringify(blacklist)); }; // Функция для добавления IP в список последних const addToRecentIPs = (ip) => { if (!isValidIP(ip) || isExcluded(ip)) { return; } let recentIPs = JSON.parse(localStorage.getItem(RECENT_IPS_KEY) || '[]'); recentIPs = recentIPs.filter(existingIp => existingIp !== ip); recentIPs.push(ip); if (recentIPs.length > 10) { recentIPs = recentIPs.slice(-10); } localStorage.setItem(RECENT_IPS_KEY, JSON.stringify(recentIPs)); }; // Функция для принудительной очистки черного списка от исключенных IP const forceCleanBlacklist = () => { let blacklist = getBlacklist(); const originalLength = blacklist.length; const cleanedBlacklist = blacklist.filter(ip => { if (isExcluded(ip)) { return false; } return isValidIP(ip); }); if (cleanedBlacklist.length !== originalLength) { saveBlacklist(cleanedBlacklist); } return cleanedBlacklist; }; // Функция для отображения сообщения const showMessage = (text, backgroundColor = 'red', textColor = 'white') => { document.querySelectorAll('.blocker-message').forEach(msg => msg.remove()); const message = document.createElement('div'); message.className = 'blocker-message'; Object.assign(message.style, { position: 'fixed', bottom: '20px', left: '20px', padding: '15px 25px', backgroundColor: backgroundColor, color: textColor, borderRadius: '5px', fontSize: '18px', fontWeight: 'bold', zIndex: 10000, boxShadow: '0 4px 8px rgba(0,0,0,0.3)', transition: 'opacity 0.5s ease-out' }); message.textContent = text; document.body.appendChild(message); setTimeout(() => { message.style.opacity = '0'; setTimeout(() => { if (message.parentNode) { message.parentNode.removeChild(message); } }, 500); }, backgroundColor === 'orange' ? 6000 : 6000); }; // Функция для извлечения IP из ICE кандидата const extractIPFromCandidate = (candidate) => { const regex = /([0-9]{1,3}(\.[0-9]{1,3}){3})/; const match = candidate.match(regex); return match ? match[0] : null; }; // Функция для извлечения IPv4 из IPv6 адресов const extractIPv4FromIPv6 = (ipv6) => { const ipv4MappedRegex = /^::ffff:(\d+\.\d+\.\d+\.\d+)$/; const mappedMatch = ipv6.match(ipv4MappedRegex); if (mappedMatch) return mappedMatch[1]; const ipv4CompatRegex = /^::(\d+\.\d+\.\d+\.\d+)$/; const compatMatch = ipv6.match(ipv4CompatRegex); if (compatMatch) return compatMatch[1]; const nat64Regex = /^64:ff9b::(\d+\.\d+\.\d+\.\d+)$/; const nat64Match = ipv6.match(nat64Regex); if (nat64Match) return nat64Match[1]; return null; }; // Функция проверки блокировки IP const shouldBlockIP = (ip) => { if (!ip || typeof ip !== 'string') { return false; } // Сначала проверяем исключения if (isExcluded(ip)) { return false; } const blacklist = getBlacklist(); if (!ip.includes(':')) { return blacklist.includes(ip); } const extractedIPv4 = extractIPv4FromIPv6(ip); if (extractedIPv4) { return blacklist.includes(extractedIPv4); } return false; }; // Функция для поиска и клика по кнопке ДАЛЬШЕ const clickNextButton = () => { // Основной селектор для кнопки ДАЛЬШЕ на chatroulett.ru const nextButton = document.querySelector('button.btn.btn-primary.btn-lg.d-block.w-100.fs-2.px-0.py-3.py-lg-5'); if (nextButton) { // Сначала снимаем disabled если есть if (nextButton.disabled) { nextButton.disabled = false; } nextButton.click(); return true; } // Альтернативные селекторы для кнопки ДАЛЬШЕ const alternativeSelectors = [ 'button[class*="next"]', 'button[class*="primary"]', '.next-btn', '[class*="next"]' ]; for (const selector of alternativeSelectors) { const button = document.querySelector(selector); if (button) { if (button.disabled) { button.disabled = false; } button.click(); return true; } } return false; }; // Наблюдатель за кнопкой ДАЛЬШЕ - снимает disabled если он появляется const observeNextButton = () => { const observer = new MutationObserver((mutations) => { const nextButton = document.querySelector('button.btn.btn-primary.btn-lg.d-block.w-100.fs-2.px-0.py-3.py-lg-5'); if (nextButton && nextButton.disabled) { nextButton.disabled = false; } // Также проверяем альтернативные кнопки const alternativeButtons = document.querySelectorAll('button[class*="next"], button[class*="primary"]'); alternativeButtons.forEach(button => { if (button.disabled) { button.disabled = false; } }); }); // Начинаем наблюдение за изменениями атрибутов и поддерева observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['disabled', 'class'] }); return observer; }; // Функция анализа SDP const analyzeSDP = (sdp) => { const foundIPs = new Set(); if (!sdp) return foundIPs; const ipv4Regex = /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/g; const matches = sdp.match(ipv4Regex); if (matches) { matches.forEach(ip => { if (isValidIP(ip) && !isExcluded(ip)) { foundIPs.add(ip); } }); } return foundIPs; }; // Создание кнопки блокировки const createButton = () => { const banButton = document.createElement('button'); Object.assign(banButton.style, { position: 'fixed', top: '50px', left: '45px', width: '120px', height: '120px', borderRadius: '50%', backgroundColor: 'red', color: 'white', border: 'none', cursor: 'pointer', zIndex: 9999, fontSize: '12px', fontWeight: 'bold', boxShadow: '0 4px 8px rgba(0,0,0,0.3)' }); banButton.textContent = 'BAN'; banButton.title = 'Заблокировать текущего собеседника'; document.body.appendChild(banButton); return banButton; }; // Основная функция инициализации const init = () => { console.log('Chatroulett WebRTC Blocker initialized'); // Принудительно очищаем черный список от исключенных IP forceCleanBlacklist(); const banButton = createButton(); let activeConnections = []; let nextButtonObserver = null; // Запускаем наблюдатель за кнопкой ДАЛЬШЕ nextButtonObserver = observeNextButton(); // Перехват RTCPeerConnection const OriginalRTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection; if (OriginalRTCPeerConnection) { const createBlockedError = (ip) => { const error = new Error(`Connection blocked: IP ${ip} in blacklist`); error.name = 'BlockedConnectionError'; return error; }; window.RTCPeerConnection = function(...args) { const pc = new OriginalRTCPeerConnection(...args); // Перехват setRemoteDescription const originalSetRemoteDescription = pc.setRemoteDescription.bind(pc); pc.setRemoteDescription = function(description) { if (description && description.sdp) { const foundIPs = analyzeSDP(description.sdp); for (const ip of foundIPs) { if (shouldBlockIP(ip)) { showMessage('Блокировка: ' + ip, 'orange', 'white'); pc.close(); setTimeout(clickNextButton, 100); return Promise.reject(createBlockedError(ip)); } } } return originalSetRemoteDescription(description); }; // Перехват addIceCandidate const originalAddIceCandidate = pc.addIceCandidate.bind(pc); pc.addIceCandidate = function(candidate) { if (candidate && candidate.candidate) { const ip = extractIPFromCandidate(candidate.candidate); if (ip && shouldBlockIP(ip)) { showMessage('Блокировка: ' + ip, 'orange', 'white'); pc.close(); setTimeout(clickNextButton, 100); return Promise.reject(createBlockedError(ip)); } } return originalAddIceCandidate(candidate); }; // Отслеживание активных соединений pc.addEventListener('connectionstatechange', () => { if (['closed', 'disconnected', 'failed'].includes(pc.connectionState)) { const index = activeConnections.indexOf(pc); if (index !== -1) activeConnections.splice(index, 1); } }); activeConnections.push(pc); return pc; }; // Копируем прототип Object.setPrototypeOf(window.RTCPeerConnection, OriginalRTCPeerConnection); window.RTCPeerConnection.prototype = OriginalRTCPeerConnection.prototype; } // Обработчик клика по кнопке блокировки banButton.addEventListener('click', () => { let currentBlacklist = getBlacklist(); let foundIPs = new Set(); let alreadyBlockedIPs = new Set(); let newBlockedIPs = []; // Массив для новых заблокированных IP // Анализ активных соединений for (const pc of activeConnections) { try { if (pc.remoteDescription && pc.remoteDescription.sdp) { const sdpIPs = analyzeSDP(pc.remoteDescription.sdp); sdpIPs.forEach(ip => { if (shouldBlockIP(ip)) { alreadyBlockedIPs.add(ip); } else if (!isExcluded(ip)) { foundIPs.add(ip); } }); } } catch (e) { // Игнорируем ошибки анализа } } // Добавление новых IP в черный список let addedCount = 0; if (foundIPs.size > 0) { foundIPs.forEach(ip => { if (!currentBlacklist.includes(ip)) { currentBlacklist.push(ip); newBlockedIPs.push(ip); // Добавляем IP в массив addedCount++; addToRecentIPs(ip); } }); if (addedCount > 0) { saveBlacklist(currentBlacklist); // Показываем IP через запятую if (newBlockedIPs.length <= 3) { // Если IP мало, показываем все showMessage(`Добавлено ${addedCount} IP: ${newBlockedIPs.join(', ')}`, 'green', 'white'); } else { // Если IP много, показываем количество и первые несколько showMessage(`Добавлено ${addedCount} IP: ${newBlockedIPs.slice(0, 3).join(', ')}...`, 'green', 'white'); } // Закрываем все соединения activeConnections.forEach(pc => pc.close()); activeConnections = []; } } // Обработка уже заблокированных IP if (alreadyBlockedIPs.size > 0 && addedCount === 0) { const blockedList = Array.from(alreadyBlockedIPs); if (blockedList.length <= 3) { showMessage(`Уже в списке блокировки: ${blockedList.join(', ')}`, 'orange', 'white'); } else { showMessage(`Уже в списке блокировки: ${blockedList.slice(0, 3).join(', ')}...`, 'orange', 'white'); } activeConnections.forEach(pc => pc.close()); activeConnections = []; } // Переход к следующему собеседнику clickNextButton(); }); }; // Запуск инициализации if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { setTimeout(init, 1000); } })();Я backend-программист, я ничего не знаю про современный JS, а уж тем более про технологию webRTC, я ничего не смыслю в этих ваших IP, сетях, масках, не умею извлекать IP из ICE кандидата - я не имел опыта в разработке с этим (джсоны гоняю). ИИ написал мне этот код и он работает. Более того, пример из статьи - это умышленно подогнанный скрипт именно под озвученный в статье веб-чат, ИИ писал мне это решение немного для другого, но похожего сайта. Более того, с помощью ИИ можно указанный скрипт за полчаса адаптировать для любого подобного веб-видео-чата.
Потратил около 8 часов на это. Теперь вопрос: сколько бы я потратил времени на создание подобного, с учётом того, что я не умею писать на современном JS, ничего не зная про технологию webRTC?
Этим самым, выбивается нижний пласт пирамиды профессионального роста. Откуда возьмется "архитектор" если он не был джуном?
Люди 200 лет назад копали землю палками-копалками, а потом появился ТРАКТОР. Они тоже задавали такой вопрос:
Этим самым, выбивается нижний пласт пирамиды профессионального роста землекопов. Откуда возьмется главный эксперт по работе с мотыгой, если он не копал землю палкой-копалкой?
А они скоро будут больше не нужны. Нравится вам это или нет.
P.S. 1: Предвкушая истерику в стиле "аррря вон там ИИ лишний пробел поставил / не так код написал" сразу скажу - это демонстрация работающего решения от ИИ.
Это пример кода от ИИ для человека, который не знает указанную выше технологию и сам бы подобное не написал без длительного углубленного чтения мануалов, которое бы вылилось в чёрт знает сколько времени.
Если не устраивает чистота кода или алгоритмы - скормите код ИИ и он сделает рефакторинг.P.S. 2: Сливайте карму дальше, ставьте минусы (как обычно), других же аргументов у вас просто нет и вы это прекрасно понимаете, что эта машина в ближайшие 5-10 лет оставит вас на профессиональной обочине истории.
Kgstranget
Все очень верно.