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

Архитектура MVC и слои приложения

Тест показывает, как удобный короткий контроллер превращается в узел, который невозможно повторно использовать или проверить отдельно. Нужно распределять HTTP, прикладные сценарии, работу с данными и доменные правила между ясными границами.

Отвечено: 0 из 30
⏱ --:--
0%
💡 Инструкция: Выберите один ответ из пяти. Для каждого фрагмента назовите его ответственность и зависимость, прежде чем выбирать слой. Время — 85 минут.
Вопрос 1 из 30
Что должен делать тонкий контроллер?
PHP
final class OrderController
{
    public function __construct(private PlaceOrder $placeOrder) {}

    public function create(ServerRequest $request): Response
    {
        $input = CreateOrderInput::fromRequest($request);
        $result = $this->placeOrder->execute($input);
        return JsonResponse::created($result);
    }
}
Вопрос 2 из 30
Почему возврат массива данных вместо немедленного echo полезен?
PHP
$data = $presenter->order($order);
return new JsonResponse($data, 200, ['Cache-Control' => 'private']);
Вопрос 3 из 30
Где проверять формат email из JSON?
PHP
$payload = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
$input = RegistrationInput::fromArray($payload);
$violations = $validator->validate($input);
Вопрос 4 из 30
Какой архитектурный дефект сильнее всего затруднит развитие этого обработчика?
PHPКонтроллер оформления покупки
final class PurchaseController
{
    public function __construct(private PDO $pdo) {}

    public function buy(ServerRequest $request): Response
    {
        $productId = (int) $request->getParsedBody()['product_id'];

        $this->pdo->beginTransaction();
        $stmt = $this->pdo->prepare(
            'UPDATE stock SET quantity = quantity - 1 WHERE product_id = ?'
        );
        $stmt->execute([$productId]);
        mail('warehouse@example.test', 'Purchase', (string) $productId);
        $this->pdo->commit();

        return new JsonResponse(['ok' => true]);
    }
}
Вопрос 5 из 30
Как обрабатывать NotFound из сервиса?
Вопрос 6 из 30
Что представляет application service?
PHP
final class PlaceOrder
{
    public function __construct(
        private OrderRepository $orders,
        private PaymentGateway $payments,
    ) {}

    public function execute(PlaceOrderCommand $command): OrderResult
    {
        $order = Order::place($command->items);
        $this->payments->authorize($order->total());
        $this->orders->save($order);
        return OrderResult::fromOrder($order);
    }
}
Вопрос 7 из 30
Почему сервис не должен читать $_POST?
PHP
final class RegisterUser
{
    public function execute(): User
    {
        $email = (string) ($_POST['email'] ?? '');
        return $this->users->register($email);
    }
}
Вопрос 8 из 30
Где разместить транзакционную границу создания заказа?
PHP
return $transaction->run(function () use ($command): OrderResult {
    $order = Order::place($command->items);
    $this->orders->save($order);
    $this->outbox->add(OrderPlaced::from($order));
    return OrderResult::fromOrder($order);
});
Вопрос 9 из 30
Что вернуть из PlaceOrder?
Вопрос 10 из 30
Почему прямой new Mailer внутри метода вреден?
Вопрос 11 из 30
Что должен возвращать UserRepository::find?
PHP
interface UserRepository
{
    public function find(UserId $id): ?User;
}
Вопрос 12 из 30
Почему интерфейс Repository не обязан иметь универсальные save/delete/findAll для всех сущностей?
PHP
interface OrderRepository
{
    public function nextIdentity(): OrderId;
    public function save(Order $order): void;
    public function get(OrderId $id): Order;
}
Вопрос 13 из 30
Где должен жить SQL?
PHP
final class PdoOrderRepository implements OrderRepository
{
    public function get(OrderId $id): Order
    {
        $stmt = $this->pdo->prepare('SELECT * FROM orders WHERE id = :id');
        $stmt->execute(['id' => $id->value]);
        return $this->hydrate($stmt->fetch(PDO::FETCH_ASSOC));
    }
}
Вопрос 14 из 30
Что такое N+1 на границе репозитория?
Вопрос 15 из 30
Почему метод save(User $u): void может быть честнее возврата bool?
Вопрос 16 из 30
Где проверять, что баланс не уходит ниже нуля?
PHP
final class Account
{
    public function withdraw(Money $amount): void
    {
        if ($amount->isGreaterThan($this->balance)) {
            throw new InsufficientFunds();
        }
        $this->balance = $this->balance->minus($amount);
    }
}
Вопрос 17 из 30
Что даёт value object Email?
PHP
final readonly class Email
{
    public function __construct(public string $value)
    {
        if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
            throw new InvalidArgumentException('Некорректный email');
        }
    }
}
Вопрос 18 из 30
Почему доменная сущность не должна наследоваться от Controller?
PHP
final class Order extends Controller
{
    public function total(): Money { /* ... */ }
}
Вопрос 19 из 30
Что такое aggregate boundary?
Вопрос 20 из 30
Когда доменное событие полезно?
Вопрос 21 из 30
Как тестировать service без базы?
PHP
$orders = new InMemoryOrderRepository();
$payments = new FakePaymentGateway();
$service = new PlaceOrder($orders, $payments);
$result = $service->execute($command);
assert($orders->contains($result->orderId));
Вопрос 22 из 30
Как тестировать репозиторий?
PHP
$repository = new PdoOrderRepository($testDatabase);
$repository->save($order);
$loaded = $repository->get($order->id());
assert($loaded->equals($order));
Вопрос 23 из 30
Почему мокировать все классы опасно?
PHP
$repository = $this->createMock(OrderRepository::class);
$logger = $this->createMock(LoggerInterface::class);
$clock = $this->createMock(Clock::class);
$events = $this->createMock(EventBus::class);
Вопрос 24 из 30
Что включить в trace сценария?
Вопрос 25 из 30
Как поймать нарушение границы?
Вопрос 26 из 30
Где проверять доступ к конкретному заказу?
PHP
$order = $orders->get($orderId);
if (!$policy->mayView($currentUser, $order)) {
    throw new AccessDenied();
}
Вопрос 27 из 30
Почему outbox полезен?
PHP
$transaction->run(function () use ($order): void {
    $this->orders->save($order);
    $this->outbox->add(OrderPlaced::from($order));
});
Вопрос 28 из 30
Где собирать реальные реализации интерфейсов?
Вопрос 29 из 30
Как мигрировать толстый legacy-контроллер?
Вопрос 30 из 30
Какая метрика помогает увидеть нарушение слоёв в работе?

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

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

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

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