Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Junior: питання на співбесіді з теми «Екосистема Laravel»

Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.

3 питання

Прапорець функції (feature flag) - перемикач, який вмикає чи вимикає частину функціональності без деплою. Код нової можливості вже на продакшені, але бачать її лише ті, кому прапорець увімкнено.

Навіщо це потрібно:

  • поступовий запуск: спершу 5% користувачів, потім 50%, потім усі;
  • trunk-based розробка: незавершену функцію можна зливати в main, бо вона прихована прапорцем;
  • швидкий «вимикач»: якщо нова функція ламає продакшен, її вимикають без відкату коду;
  • A/B-тести й бета-доступ для окремих клієнтів.

Laravel Pennant - офіційний пакет для прапорців. Прапорець оголошують у сервіс-провайдері:

use App\Models\User;
use Illuminate\Support\Lottery;
use Laravel\Pennant\Feature;

Feature::define('new-checkout', fn (User $user) => match (true) {
    $user->isInternal() => true,
    $user->isHighTrafficCustomer() => false,
    default => Lottery::odds(1 / 10),
});

Замикання отримує скоп - за замовчуванням автентифікованого користувача - і повертає результат.

Перевірка в коді й шаблонах:

if (Feature::active('new-checkout')) {
    return $this->newCheckout($request);
}
@feature('new-checkout')
    <x-checkout.new />
@else
    <x-checkout.legacy />
@endfeature

Для маршрутів є middleware EnsureFeaturesAreActive, що повертає помилку, якщо прапорець вимкнено.

Важлива деталь: драйвер за замовчуванням - database. Pennant зберігає обчислене значення в таблиці features, тож користувач, якому одного разу «випало» true в лотереї, і далі бачитиме нову версію. Це робить досвід стабільним, але означає, що зміна визначення не впливає на вже збережені значення.

Чого не робити: не залишати прапорці назавжди. Кожен прапорець - це дві гілки коду, які треба підтримувати й тестувати. Після повного запуску прапорець і стара гілка видаляються.

Докладніше в документації: Pennant: оголошення можливостей

Socialite реалізує протокол OAuth для входу через сторонніх провайдерів: Google, GitHub, Facebook, GitLab, LinkedIn, Slack, X та інших.

Як проходить вхід:

  1. користувач натискає «Увійти через GitHub» - застосунок перенаправляє його на GitHub;
  2. GitHub питає користувача, чи дозволити доступ;
  3. GitHub повертає користувача на ваш callback-маршрут з одноразовим кодом;
  4. Socialite обмінює код на токен доступу й отримує профіль користувача;
  5. застосунок знаходить чи створює користувача і входить від його імені.

Налаштування - ключі застосунку провайдера в config/services.php:

'github' => [
    'client_id' => env('GITHUB_CLIENT_ID'),
    'client_secret' => env('GITHUB_CLIENT_SECRET'),
    'redirect' => '/auth/github/callback',
],

Два маршрути:

use Laravel\Socialite\Socialite;

Route::get('/auth/github/redirect', fn () => Socialite::driver('github')->redirect());

Route::get('/auth/github/callback', function () {
    $githubUser = Socialite::driver('github')->user();

    $user = User::updateOrCreate(
        ['github_id' => $githubUser->getId()],
        ['name' => $githubUser->getName(), 'email' => $githubUser->getEmail()],
    );

    Auth::login($user, remember: true);

    return redirect('/dashboard');
});

Що варто знати:

  • шукати користувача за ID провайдера (github_id), а не за email: email у профілі можна змінити, а ID стабільний;
  • email може бути відсутнім - деякі провайдери не повертають його без додаткового скопу або якщо користувач приховав пошту;
  • скопи визначають, до чого застосунок отримає доступ: ->scopes(['read:user']). Просіть мінімум;
  • параметр state Socialite перевіряє сам - це захист від CSRF у процесі OAuth. Для API без сесії є stateless(), але тоді захист доведеться забезпечити інакше;
  • тести: Socialite можна підмінити фейком і не ходити до справжнього провайдера.

Для кількох провайдерів зручно зберігати зв'язки в окремій таблиці social_accounts (provider, provider_id, user_id), а не додавати колонку в users для кожного провайдера.

Докладніше в документації: Socialite: автентифікація та збереження

Pulse - панель моніторингу продуктивності й використання застосунку. Вона показує агреговану картину за період: що повільне, що найчастіше використовується, де помилки.

Що показує Pulse (картки):

Картка Що видно
Сервери CPU, пам'ять, диск кожного сервера
Використання застосунку користувачі, що роблять найбільше запитів чи запускають найбільше завдань
Винятки найчастіші винятки й коли вони були востаннє
Черги пропускна здатність: поставлено, оброблено, невдалі
Повільні запити, завдання, SQL, вихідні HTTP що перевищує поріг (за замовчуванням 1000 мс)
Кеш влучання й промахи за ключами

Панель доступна за адресою /pulse, за замовчуванням лише в середовищі local. Для продакшену доступ відкривають через гейт viewPulse:

Gate::define('viewPulse', fn (User $user) => $user->isAdmin());

Чим відрізняється Telescope:

Pulse Telescope
що записує агреговані метрики кожен запит, запит до БД, завдання, лист окремо
питання, на яке відповідає «що загалом повільне й часто ламається?» «що саме сталося в цьому запиті?»
де використовувати продакшен переважно розробка й staging
навантаження помірне, з семплюванням значне на продакшені

Простіше кажучи: Pulse показує, де проблема (ендпойнт /reports повільний і викликається тисячу разів на годину), а Telescope - чому (у кожному запиті 300 SQL-запитів через N+1).

Чого Pulse не замінює:

  • зовнішній моніторинг доступності - якщо застосунок лежить, Pulse разом з ним;
  • трекер помилок (Sentry, Flare) з повними стеками й сповіщеннями;
  • централізовані логи для розслідувань.

Для серверних метрик на кожному сервері має працювати команда pulse:check під Supervisor.

Докладніше в документації: Laravel Pulse