PHP PHP  ·  30 вопросов  ·  ~85 мин  ·  ⏱ Таймер 25:00  ·  Сложный  ·  👥 1 прошёл

Рефакторинг и аварии старого PHP-проекта

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

Отвечено: 0 из 30
⏱ --:--
0%
💡 Инструкция: Выберите один ответ из пяти. Не ищите самое красивое переписывание: выбирайте следующий безопасный шаг с проверяемым результатом. Время — 85 минут.
Вопрос 1 из 30
С чего начинать изменение критичного метода без тестов?
PHP
final class LegacyTotalTest extends TestCase
{
    public function testLegacyTotalForKnownOrder(): void
    {
        $result = legacyTotal(['price' => 100, 'discount' => 10]);
        self::assertSame(90, $result);
    }
}
Вопрос 2 из 30
Что такое seam?
PHP
interface Clock { public function now(): DateTimeImmutable; }

final class LegacyClock implements Clock
{
    public function now(): DateTimeImmutable { return new DateTimeImmutable('now'); }
}
Вопрос 3 из 30
Почему global state мешает диагностике?
PHP
$taxRate = 0.20;
function total(float $price): float
{
    global $taxRate;
    return $price * (1 + $taxRate);
}
Вопрос 4 из 30
Нужно ли сохранять баг в characterization test?
Вопрос 5 из 30
Что подозрительно?
Вопрос 6 из 30
Что такое strangler pattern?
PHP
if ($newCheckout->supports($request)) {
    return $newCheckout->handle($request);
}
return $legacyApplication->handle($request);
Вопрос 7 из 30
Зачем feature flag?
PHP
if ($flags->enabled('new_pricing', $user->id)) {
    return $newPricing->calculate($cart);
}
return $legacyPricing->calculate($cart);
Вопрос 8 из 30
Как заменить прямой mail()?
PHP
interface Mailer { public function send(Message $message): void; }

final class NativeMailAdapter implements Mailer
{
    public function send(Message $message): void
    {
        mail($message->to, $message->subject, $message->body);
    }
}
Вопрос 9 из 30
Что такое expand/contract для схемы?
Вопрос 10 из 30
Почему dual write опасна без контроля?
Вопрос 11 из 30
Что сделать первым при 500 только у части запросов?
PHP
$requestId = $_SERVER['HTTP_X_REQUEST_ID'] ?? bin2hex(random_bytes(8));
$logger->error('HTTP 500', [
    'request_id' => $requestId,
    'route' => $routeName,
    'release' => getenv('APP_RELEASE'),
]);
Вопрос 12 из 30
Почему grep по слову ERROR недостаточен?
PHP
$logger->info('checkout.started', ['request_id' => $requestId]);
$logger->warning('payment.slow', ['request_id' => $requestId, 'elapsed_ms' => 2400]);
$logger->error('checkout.failed', ['request_id' => $requestId]);
Вопрос 13 из 30
Что включить в структурированный лог?
PHP
$logger->info('order.completed', [
    'event' => 'order.completed',
    'request_id' => $requestId,
    'release' => $release,
    'duration_ms' => $durationMs,
    'result' => 'success',
]);
Вопрос 14 из 30
Как несинхронные часы мешают расследованию?
Вопрос 15 из 30
Почему повторяющаяся ошибка после deploy требует сравнить версии?
Вопрос 16 из 30
Что такое canary?
PHP
$bucket = crc32($userId) % 100;
$handler = $bucket < 5 ? $newHandler : $stableHandler;
$response = $handler->handle($request);
$metrics->observe('checkout_errors', $response->status >= 500, ['variant' => $bucket < 5 ? 'canary' : 'stable']);
Вопрос 17 из 30
Почему rollback кода может быть невозможен после разрушительной миграции?
PHP
$pdo->exec('ALTER TABLE orders DROP COLUMN legacy_status');

function loadLegacyOrder(PDO $pdo, int $id): array
{
    $stmt = $pdo->prepare('SELECT id, legacy_status FROM orders WHERE id = ?');
    $stmt->execute([$id]);
    return $stmt->fetch(PDO::FETCH_ASSOC);
}
Вопрос 18 из 30
Что должен проверять health check?
PHP
$ready = $database->ping()
    && $cache->ping()
    && $migrations->isCurrent();
http_response_code($ready ? 200 : 503);
Вопрос 19 из 30
Как обновлять PHP-FPM/worker атомарнее?
Вопрос 20 из 30
Какая метрика остановит rollout?
Вопрос 21 из 30
Что такое минимальный воспроизводимый пример?
PHP
$input = ['quantity' => 0, 'coupon' => 'X'];
$result = legacyCheckout($input, new FrozenClock('2026-07-14T10:00:00Z'));
var_dump($result);
Вопрос 22 из 30
Как сравнить старую и новую реализацию без влияния на пользователя?
PHP
$oldResult = $legacyCalculator->calculate($input);
$newResult = $newCalculator->calculate($input);
if ($oldResult !== $newResult) {
    $logger->warning('shadow_mismatch', compact('oldResult', 'newResult'));
}
return $oldResult;
Вопрос 23 из 30
Что такое fault injection?
PHP
$database = new FaultInjectingDatabase(
    inner: $realDatabase,
    failAfterWrites: 1,
);
$service->execute($command);
Вопрос 24 из 30
Почему копия базы с десятью строками может скрыть проблему?
Вопрос 25 из 30
Как отличать гипотезу от факта?
Вопрос 26 из 30
Что приоритетнее во время активного инцидента?
PHP
$flags->disable('new_checkout');
$traffic->routeTo($stableRelease);
$incident->record('mitigation_applied', ['release' => $stableRelease]);
Вопрос 27 из 30
Когда нужно ротировать секрет?
PHP
$newSecret = $secrets->createVersion('payment-api');
$deploy->useSecretVersion($newSecret->version);
$secrets->revokeVersion($oldVersion);
Вопрос 28 из 30
Что такое blameless postmortem?
PHP
$postmortem = [
    'impact' => $impact,
    'timeline' => $timeline,
    'contributing_factors' => $factors,
    'actions' => $preventiveActions,
];
Вопрос 29 из 30
Почему нельзя сразу чистить повреждённый сервер?
Вопрос 30 из 30
Какое действие сильнее «добавить инструкцию быть внимательнее»?

Ответьте на все 30 вопросов, чтобы получить результат

🔗 Встроить тест на свой сайт (iframe) ▼

Скопируйте код и вставьте в любое место на вашем сайте:

Также доступна прямая ссылка на embed-страницу