Skip to content

Грабли и антипаттерны

Ошибки, которые чаще всего доезжают до прода. Формат: грабля → симптом → защита. Дополняет чеклисты объяснением «почему».

Конфигурация и окружение

ГрабляСимптомЗащита
env() вне config/Работает в dev, null в prod после config:cacheТолько config(), правило студии; composer audit привычки — grep по env( вне config/
Забытый php artisan optimize в деплоеПрод медленнее devoptimize (config+route+view+event cache) — обязательный шаг деплоя
APP_KEY потерян/перегенерированВсе шифрованные данные и куки невосстановимыКлюч в менеджере секретов; никогда key:generate на проде с данными
APP_DEBUG=true на продеStack traces с секретами наружуЧеклист деплоя; debug гейтится на APP_ENV
Значение с пробелом в .env без кавычекОбрезанное значение, тихоВсегда кавычки: MAIL_FROM_NAME="Мой сайт"
Изменил .env — «не применилось»Старые значенияПосле правки: config:clear (dev) / redeploy c optimize (prod)

Деньги и числа

ГрабляСимптомЗащита
float для денег19.99 + 0.01 = 20.000000000004, расхождение копеек в отчётахdecimal cast или integer в копейках + brick/money
Округление в разных местах по-разномуСумма позиций ≠ итог заказаОдна точка округления в домене (Money-объект), не в Blade
intdiv / проценты «на глаз»Комиссия площадки расходится с ожиданиями на копейкуТесты на денежную арифметику с граничными суммами

Eloquent и БД

ГрабляСимптомЗащита
N+1Страница делает 200 запросов->with() явно; query-detector в dev; N+1 — баг по стандарту
Model::all() / ->get() на большой таблицеOOM, таймаутыchunkById(), lazy(), пагинация
firstOrCreate под конкуренциейДубли записей при параллельных запросахУникальный индекс в БД (истина — в БД) + createOrFirst
Массовые update()/insert() в обход моделейНе сработали observers, события, activitylogОсознанно: либо цикл с моделями, либо явно пересчитать зависимое
whereIn с 10k+ IDМедленно, лимиты плейсхолдеровJOIN на временную таблицу / whereIntegerInRaw / чанки
paginate() + groupByНеверный totalПодзапрос или simplePaginate
Обычная пагинация на глубоких страницахOFFSET 100000 — деградацияcursorPaginate() для лент и API
Soft deletes + route binding404 на «удалённую» запись в админкеwithTrashed() в binding админских роутов
Забытый withoutGlobalScope в админкеАдмин не видит неактивные записиНе вешать global scope на «активность» — явный scope
Миграция change()/rename на проде с большой таблицейБлокировка таблицы на минутыСмотреть спецификацию миграций: CONCURRENTLY, отдельные шаги
Транзакция обняла внешний API-вызовДолгие блокировки, дедлокиВ транзакции — только БД; API/почта до или после (afterCommit)

Очереди

ГрабляСимптомЗащита
Деплой без queue:restartВоркеры выполняют старый код днямиqueue:restart — обязательный шаг деплоя
dispatch() внутри транзакции«ModelNotFound» в джобе: воркер быстрее коммита->afterCommit() или dispatchAfterResponse
Целая коллекция/массив данных в конструкторе джобаРаздутый payload, устаревшие данные при выполненииПередавать ID/модель (SerializesModels), данные читать в handle()
Нет $tries / failed()Бесконечные ретраи или тихая смертьПо стандарту студии — всегда указывать
Один воркер на всёТяжёлый импорт блокирует отправку писемОчереди по типам: notifications, heavy, default
Cache::flush() в кодеСнесли сессии, throttle, чужие кешиТолько теги: Cache::tags([...])->flush()

Дата и время

ГрабляСимптомЗащита
Мутабельный Carbon$start->addDays(3) изменил и $startCarbonImmutable через Date::use()
Смена APP_TIMEZONE с UTCСдвиги в расписаниях, сравнениях, DST-багиХранить UTC, конвертировать на выводе
Сравнение дат строками«2026-1-9» > «2026-10-1»Casts datetime/date, сравнение Carbon-методами
now() в запросах, кешируемых надолго«Сегодняшние» данные вчерашниеTTL кеша согласован с семантикой данных

HTTP, роутинг, безопасность периметра

ГрабляСимптомЗащита
Нет timeout на HTTP-клиентеВнешний API завис — ваши воркеры/запросы тожеtimeout()+connectTimeout() всегда
Забытый trustProxies за реверс-проксиurl() генерит http://, редиректы на http, неправильный IPОбязательная настройка под Caddy (стандарт студии)
Вебхук без проверки подписиПодделка платёжных событийПроверка подписи + идемпотентность (уникальный event_id)
Вебхук не идемпотентенДвойное начисление при повторной доставкеТаблица обработанных событий с unique
Валидация array.* без правила на сам arrayОбход валидации нестандартным payload`'items' => 'required
Файл валидируется только по расширениюЗалит php-файл с расширением .jpgmimes:+max: + хранение вне public + medialibrary
ID в публичных URLПеребор объектов, утечка объёмовslug/UUID по стандарту студии
back() без fallbackРедирект в никуда с пустым refererback(fallback: route('home'))

Кеш

ГрабляСимптомЗащита
Кеш без инвалидации при правке в админке«Я поменял, а на сайте старое»afterSaveCache::tags(...)->flush() — стандарт студии
Кеш-стампид (одновременный прогрев)Всплеск нагрузки при истечении популярного ключаCache::flexible() (SWR) или lock() вокруг прогрева
Кеширование объектов с замыканиями/ресурсамиОшибки сериализацииКешировать данные (массивы/DTO), не объекты с состоянием
В кеше — модель с загруженными связямиРаздутый Redis, устаревшие связиКешировать id/массивы, гидрировать по необходимости

Livewire / Filament

ГрабляСимптомЗащита
Модель целиком в public-свойствеСкрытые запросы на каждый запрос компонента, утечка скрытых полей в HTMLID + computed property, или DTO
->live() на каждом полеФорма шлёт запрос на каждый символlive(onBlur: true) / debounce
Тяжёлый запрос в методе, вызываемом при каждом рендереМедленная админка#[Computed] с кешированием / загрузка в mount
Загрузка файлов Livewire на проде за прокси422 на uploadПроверить лимиты body в Caddy/nginx и post_max_size PHP

Тесты

ГрабляСимптомЗащита
RefreshDatabase на рабочей БДПотеря всех данныхphpunit.xml с {project}_test — железное правило студии
Тесты зависят от порядкаFlaky: поодиночке зелёные, вместе падаютИзоляция; свежие фабрики в каждом тесте
Замоканное всёТесты зелёные, прод падаетМокать только внешнее (API, почту); БД — настоящая
sleep() в тестахМедленный CISleep::fake(), Queue::fake(), travel() для времени

Общий принцип

Большинство граблей — это расхождение между dev и prod: кеш конфига, очереди, прокси, объёмы данных. Лечится приближением dev к prod (Docker по стандарту студии) и обязательным чеклистом деплоя → Деплой и эксплуатация.

Внутренняя база знаний студии