Обновить

Как объяснить вайбкодеру, что “работает” — не значит “сделано нормально”

Уровень сложностиПростой
Время на прочтение7 мин
Охват и читатели8.1K
Всего голосов 19: ↑18 и ↓1+20
Комментарии19

Комментарии 19

Полезно, спасибо!

Прям в точку. У нас была похожая история — генерили через Claude эндпоинты для файлового хранилища, всё выглядело чисто, линтер доволен, тесты проходят. Потом senior посмотрел и нашёл именно path traversal — почти один в один как в статье. Самое обидное, что код был «уверенный», без единого намёка на то что там проблема.

С тех пор правило простое: LLM пишет черновик, человек с контекстом смотрит граничные случаи. Особенно всё что касается авторизации и файлов. Без этого — рулетка.

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

Именно поэтому я уверен что разработчиков всех не поувольняют . Вернее, может какие нибудь ретивые оптимизаторы из менеджемента и поувольняют - но потом им придётся этих разработчиков нанимать обратно )).

Кстати, пример про копирайтинг с наушниками плохой. Говорю как меломан со стажем. И в донейросетевую эпоху рекламные тексты звукового оборудования все как один гарантировали кристально чистый звук - от дешманского оборудования за копейки до лампового хайенда собранного девственницами на склоне горы Фудзи. Так что тут мимо ).

Эх, согласен про наушники, это скорее первое, что у меня было в поле внимания, поэтому про них и сделал)

Хороший пример.

Отличная статья. Самое обидное, что заказчики часто видят только «работает» и им сложно донести, что под капотом легаси, которое через месяц развалится. Сейчас реально стало тяжелее объяснять разницу между «накидал на коленке» и архитектурным подходом. Вайб-кодинг - это круто для прототипа, но убивает продукт на дистанции, когда начинаются реальные баги.

Сейчас реально стало тяжелее объяснять разницу между «накидал на коленке» и архитектурным подходом.

Это заказчикам довольно быстро объяснят хакеры, которые будут ломать такие поделки пачками и использовать для "заработка". Вот пару раз попадет заказчик на деньги тогда и задумается.

Что мешает мифос как валидатор направить?

Код сопротивляется изменениям.

Чем меньше думали как сделать архитектуру гибкой тем больше сопротивляется.

Неверующих можно отправить в clean architecture, в самом начале графики роста стоимости новой строки кода от роста кодовой базы/количества накопленных изменений. Они катастрофические.

https://habr.com/ru/companies/vk/articles/801393

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

Но на стадии MVP задача другая: дёшево проверить, есть ли у идеи спрос.

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

Проблема не в плохом коде AI-MVP, а в том, что временную проверку спроса начинают считать готовым продуктом.

Вопрос, который был задан в заголовке статьи примерно эквивалентен следующему вопросу:
Как разубедить AI-леммингов в том, что Андрей Карпатый - "AI-Бог", и слово его "Истина"?

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

А что делает живой копирайтер? Он пишет конкретику, которую можно проверить: сколько часов держит зарядка, за сколько секунд коннектится, что слышно, а что нет. И — самое важное — он называет недостаток. 

Хахахахахахахаххахахахахахах. Ххахаах. Ха-ха. Нет.

ну ок, согласен, я не копирайтер, не мне судить))

Независимый обзорщик, возможно, укажет на недостатки.

Возможно и нейросеть найдет ошибки в коде. "в русалок верю, в домовых"

А наивный ответ на «напиши простой аналог lru_cache»:

Хз, кто вам там что пишет без вытеснения
Простейшая реализация на OrderedDict:
pythonfrom collections import OrderedDict
from functools import wraps


def lru_cache(maxsize=128):
    def decorator(func):
        cache = OrderedDict()

        @wraps(func)
        def wrapper(*args, **kwargs):
            key = (args, tuple(sorted(kwargs.items())))
            if key in cache:
                cache.move_to_end(key)       # отметить как недавно использованный
                return cache[key]
            result = func(*args, **kwargs)
            cache[key] = result
            if maxsize is not None and len(cache) > maxsize:
                cache.popitem(last=False)     # выкинуть самый старый
            return result

        return wrapper
    return decorator
Использование:
python@lru_cache(maxsize=2)
def slow_square(n):
    print(f"вычисляю {n}")
    return n * n

slow_square(2)  # вычисляю 2
slow_square(2)  # из кеша
slow_square(3)  # вычисляю 3
slow_square(4)  # вычисляю 4 — теперь 2 вытеснен
slow_square(2)  # вычисляю 2 (снова)
Ключевые моменты этой реализации:
OrderedDict поддерживает порядок вставки, а move_to_end позволяет дёшево обновлять «свежесть» элемента — это и есть суть LRU. При переполнении popitem(last=False) удаляет самый давно использованный.
Формирование ключа (args, tuple(sorted(kwargs.items()))) — упрощённое. Настоящий functools.lru_cache использует _make_key, который аккуратнее обрабатывает порядок аргументов и типы. Здесь есть ограничение: все аргументы должны быть хешируемыми (как и в оригинале).
Если хочется ближе к оригиналу — добавить статистику и метод сброса:
pythonfrom collections import OrderedDict
from functools import wraps


def lru_cache(maxsize=128):
    def decorator(func):
        cache = OrderedDict()
        hits = misses = 0

        @wraps(func)
        def wrapper(*args, **kwargs):
            nonlocal hits, misses
            key = (args, tuple(sorted(kwargs.items())))
            if key in cache:
                cache.move_to_end(key)
                hits += 1
                return cache[key]
            misses += 1
            result = func(*args, **kwargs)
            cache[key] = result
            if maxsize is not None and len(cache) > maxsize:
                cache.popitem(last=False)
            return result

        def cache_info():
            return {"hits": hits, "misses": misses,
                    "maxsize": maxsize, "currsize": len(cache)}

        def cache_clear():
            nonlocal hits, misses
            cache.clear()
            hits = misses = 0

        wrapper.cache_info = cache_info
        wrapper.cache_clear = cache_clear
        return wrapper
    return decorator
Стоит иметь в виду: настоящий functools.lru_cache написан на C, потокобезопасен (блокировка вокруг обновления кеша) и использует кольцевой двусвязный список вместо OrderedDict. Для учебных целей и однопоточного кода версия выше эквивалентна по поведению; для многопоточности нужно обернуть доступ к cache в threading.Lock.

«Ты просто не ставишь пять линий после вишни — вот и не выигрываешь!» ©

нейтральный чат на «сделай безопасное имя файла»

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

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

Точняк!
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации