Тема
Качество кода — принципы
SOLID в Laravel
- SRP: Service/Controller/Model — одна ответственность. 300+ строк → разбивай
- OCP: вместо
if ($type === 'x')— стратегии/полиморфизм (Enum с методами, interface + implementations) - DI: constructor injection, никогда
app()/resolve()внутри методов - Один публичный метод = одно действие:
OrderService::place(), неOrderService::handle($action)
Типизация
declare(strict_types=1)в ВСЕХ PHP-файлах бэкенда- Типизация параметров и return — всегда
- Readonly DTOs (
app/DTOs/) для передачи данных между слоями — не ассоциативные массивы - PHP 8 constructor property promotion
Явность > магия
- Нет
Model::$with—->with()в запросе - Нет global scopes, меняющих поведение незаметно (кроме SoftDeletes / MultiTenancy)
- Нет observer'ов с бизнес-логикой — событие + listener с явным вызовом сервиса
- Макросы только когда pain-point документирован в ADR
Производительность
- N+1 — это баг.
->with()/->withCount()обязательны - Filament Listing —
EagerLoadingв Resource - Массовые операции —
chunk()илиlazy(), не->get()на таблицах >1000 записей - Индексы добавлять ДО релиза, не «когда замедлится»
- Query log в dev:
mcp__laravel-boost__database-queryс EXPLAIN
Error handling
- Никогда
try { ... } catch (\Exception $e) { return null; }— логируй или пробрасывай - Domain exceptions:
OrganizationNotFoundException extends DomainException - Handler в
bootstrap/app.php— единая точка рендеринга API/HTML ошибок throw_if()/throw_unless()вместо вложенныхif
Именование (английский, осмысленный)
| Что | Правило | Пример |
|---|---|---|
| Методы | Глаголы | publish(), calculateDistance() |
| Boolean | is*/has*/can* | isPublished(), hasAwards() |
| Коллекции | Множественное | $organizations, не $orgs |
| Константы | SCREAMING_SNAKE_CASE | MAX_RETRY_COUNT |
Сокращения — только для локальных переменных внутри замыкания.
Комментарии
- Объясняй «почему», не «что»
- TODO/FIXME — только с task-id:
// TODO(#112): revert slug после expired paid_until - PHPDoc обязателен для: служебных методов (Service, Action), интерфейсов,
@return Collection<int, Model>
Восстановление данных (catalog)
При потере данных:
php artisan migrate --force→php artisan db:seed --force- Восстановить координаты:
UPDATE organizations SET address_structured = jsonb_set(jsonb_set(COALESCE(address_structured, '{}')::jsonb, '{lat}', to_jsonb(ST_Y(coordinates))), '{lon}', to_jsonb(ST_X(coordinates))) WHERE coordinates IS NOT NULL scout:flush+scout:import