Комментарии 19
Полезно, спасибо!
Прям в точку. У нас была похожая история — генерили через Claude эндпоинты для файлового хранилища, всё выглядело чисто, линтер доволен, тесты проходят. Потом senior посмотрел и нашёл именно path traversal — почти один в один как в статье. Самое обидное, что код был «уверенный», без единого намёка на то что там проблема.
С тех пор правило простое: LLM пишет черновик, человек с контекстом смотрит граничные случаи. Особенно всё что касается авторизации и файлов. Без этого — рулетка.
Это всё не новость. Для того чтобы делать реально сложные проекты с помощью ЛЛМ надо разбираться в теме, архитектуре пприложений, особенностях стека итд.
Именно поэтому я уверен что разработчиков всех не поувольняют . Вернее, может какие нибудь ретивые оптимизаторы из менеджемента и поувольняют - но потом им придётся этих разработчиков нанимать обратно )).
Кстати, пример про копирайтинг с наушниками плохой. Говорю как меломан со стажем. И в донейросетевую эпоху рекламные тексты звукового оборудования все как один гарантировали кристально чистый звук - от дешманского оборудования за копейки до лампового хайенда собранного девственницами на склоне горы Фудзи. Так что тут мимо ).
Хороший пример.
Отличная статья. Самое обидное, что заказчики часто видят только «работает» и им сложно донести, что под капотом легаси, которое через месяц развалится. Сейчас реально стало тяжелее объяснять разницу между «накидал на коленке» и архитектурным подходом. Вайб-кодинг - это круто для прототипа, но убивает продукт на дистанции, когда начинаются реальные баги.
Сейчас реально стало тяжелее объяснять разницу между «накидал на коленке» и архитектурным подходом.
Это заказчикам довольно быстро объяснят хакеры, которые будут ломать такие поделки пачками и использовать для "заработка". Вот пару раз попадет заказчик на деньги тогда и задумается.
Код сопротивляется изменениям.
Чем меньше думали как сделать архитектуру гибкой тем больше сопротивляется.
Неверующих можно отправить в clean architecture, в самом начале графики роста стоимости новой строки кода от роста кодовой базы/количества накопленных изменений. Они катастрофические.
Важно разделять, если вайбкодингом заменяют нормальную разработку в живом продукте: да это на грани добра и зла.
Но на стадии 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.нейтральный чат на «сделай безопасное имя файла»
Ну это так не работает. Из расплывчатых описаний получается ерунда. Чем чётче описана задача, тем лучше будет результат. Вайб кодинг это все ещё про программирование, а не телепатию.


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