MidПрактика15 min

Подходы к решению

Top-down vs bottom-up подходы, как начинать System Design интервью, как уточнять требования и вести диалог

Два основных подхода

Существует два фундаментальных подхода к проектированию систем на интервью: сверху вниз (top-down) и снизу вверх (bottom-up). Каждый имеет свои сильные стороны.

Top-Down (сверху вниз)

Начинаете с общей картины и постепенно детализируете.

Бизнес-требования
  └─ Функциональные требования
       └─ Высокоуровневая архитектура
            └─ Компоненты
                 └─ Детали реализации

Когда использовать: для большинства System Design задач. Это наиболее естественный и понятный для интервьюера подход.

Bottom-Up (снизу вверх)

Начинаете с конкретных технических решений и собираете систему.

Структура данных
  └─ API конкретного сервиса
       └─ Взаимодействие сервисов
            └─ Общая архитектура
                 └─ Соответствие требованиям

Когда использовать: когда у задачи есть очевидный ключевой компонент (например, алгоритм ранжирования для ленты новостей).

Как начинать: первые 5 минут

Первые 5 минут определяют качество всего интервью. Вот проверенный алгоритм.

Шаг 1: Переформулируйте задачу

<?php

declare(strict_types=1);

/**
 * Interviewer says: "Design a URL shortener"
 *
 * Your restatement:
 * "I will design a service that converts long URLs into short,
 * unique identifiers, and redirects users from short URLs to originals.
 * The system should handle high read traffic with low latency.
 * Let me clarify the requirements."
 */
### Шаг 2: Задайте уточняющие вопросы

Группируйте вопросы по категориям.

<?php

declare(strict_types=1);

/**
 * Structured approach to clarifying questions
 */
final class RequirementQuestions
{
    /**
     * Category 1: Users and Scale
     * - How many URLs shortened per day?
     * - How many redirects per day?
     * - What's the read/write ratio?
     */
    public function getUserScaleQuestions(): array
    {
        return [
            'How many new short URLs per day?' => '100M writes/day',
            'How many redirects per day?' => '10B reads/day',
            'Read/write ratio?' => '100:1 (read-heavy)',
            'Geographic distribution?' => 'Global users',
        ];
    }

    /**
     * Category 2: Functional Requirements
     * - Custom aliases allowed?
     * - Expiration policy?
     * - Analytics needed?
     */
    public function getFunctionalQuestions(): array
    {
        return [
            'Custom aliases?' => 'Yes, optional',
            'URL expiration?' => 'Default 5 years, configurable',
            'Analytics (click count, geography)?' => 'Basic analytics',
            'API or web interface or both?' => 'API primary',
        ];
    }

    /**
     * Category 3: Non-Functional Requirements
     * - Latency target?
     * - Availability target?
     * - Consistency requirements?
     */
    public function getNonFunctionalQuestions(): array
    {
        return [
            'Redirect latency target?' => '<100ms p99',
            'Availability?' => '99.99%',
            'URL uniqueness guarantee?' => 'Must be globally unique',
            'Can short URL be reused after expiry?' => 'No, never reused',
        ];
    }
}
### Шаг 3: Определите приоритеты

После получения ответов, явно расставьте приоритеты:

"Исходя из требований, основные приоритеты:

  1. Низкая задержка редиректа (read path)
  2. Высокая доступность
  3. Глобальная уникальность URL
  4. Аналитика -- второстепенна, может быть eventual consistent"

Искусство уточнения требований

Хорошие вопросы vs плохие

Плохой вопрос Хороший вопрос
"Какую базу данных использовать?" "Какой объем данных мы ожидаем?"
"Нужен ли Kubernetes?" "Какая ожидаемая нагрузка?"
"Сколько серверов?" "Какая допустимая задержка?"
"Нужен ли кэш?" "Какое соотношение чтение/запись?"

Техника "сужения воронки"

<?php

declare(strict_types=1);

/**
 * Funnel technique for requirement gathering
 *
 * Start broad, then narrow down
 */

// Level 1: Business context
// "What's the primary use case for this system?"
// Answer: "Short URLs for marketing campaigns and social media"

// Level 2: User behavior
// "Who creates URLs? End users or only our marketing team?"
// Answer: "Both, but 90% are from API integrations"

// Level 3: Scale
// "What's the expected daily volume?"
// Answer: "100M new URLs, 10B redirects per day"

// Level 4: Constraints
// "Any latency or availability requirements?"
// Answer: "Redirect must be <100ms, 99.99% uptime"

// Now you can make informed decisions:
final class DesignDecisions
{
    /**
     * Based on requirements:
     * - 100:1 read/write ratio -> heavy caching strategy
     * - <100ms redirect -> cache hot URLs in memory
     * - 99.99% uptime -> multi-region deployment
     * - 100M writes/day -> ~1200 writes/sec average
     * - 10B reads/day -> ~115K reads/sec average
     */
    public function summarize(): array
    {
        return [
            'architecture' => 'Read-optimized with aggressive caching',
            'storage' => 'Distributed KV store (DynamoDB/Cassandra)',
            'caching' => 'Multi-tier: CDN + Redis + Application cache',
            'id_generation' => 'Base62 encoding of distributed counter',
            'deployment' => 'Multi-region active-active',
        ];
    }
}
## Ведение диалога с интервьюером

Техника "Think Out Loud"

Проговаривайте свои мысли. Интервьюер не читает мысли.

<?php

declare(strict_types=1);

/**
 * Example of thinking out loud during interview
 */

// "For ID generation, I see three options:
//
// Option 1: Auto-increment in database
//   + Simple
//   - Single point of failure
//   - Predictable (security concern)
//
// Option 2: UUID
//   + Distributed, no coordination
//   - Too long for short URL (36 chars)
//
// Option 3: Base62 encoding of distributed counter
//   + Short (7 chars for 3.5 trillion combinations)
//   + Unpredictable with random offset
//   - Needs counter service
//
// I'll go with Option 3 because we need short URLs
// and can tolerate the complexity of a counter service."

final class Base62Encoder
{
    private const ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

    public function encode(int $number): string
    {
        if ($number === 0) {
            return self::ALPHABET[0];
        }

        $result = '';
        while ($number > 0) {
            $result = self::ALPHABET[$number % 62] . $result;
            $number = intdiv($number, 62);
        }

        return $result;
    }

    public function decode(string $code): int
    {
        $number = 0;
        $length = strlen($code);

        for ($i = 0; $i < $length; $i++) {
            $number = $number * 62 + strpos(self::ALPHABET, $code[$i]);
        }

        return $number;
    }
}

// 7 characters in base62 = 62^7 = 3,521,614,606,208 combinations
// At 100M/day, this lasts ~96 years
### Реагирование на подсказки

Интервьюер часто дает подсказки. Умение их распознавать -- важный навык.

Типы подсказок:

  • "А что будет, если..." -- вас подталкивают рассмотреть edge case
  • "Давайте предположим, что..." -- вас направляют к конкретному сценарию
  • "Есть ли альтернативы?" -- текущее решение не оптимально
  • "Как это будет работать при 10x нагрузке?" -- нужно обсудить масштабирование

Работа с "застреванием"

Если вы не знаете ответ:

  1. Признайте: "Я не работал с этим напрямую, но вот мои рассуждения..."
  2. Рассуждайте: примените общие принципы к конкретной проблеме
  3. Спросите: "Можете дать подсказку в каком направлении думать?"

Практические шаблоны

Шаблон для начала любой задачи

<?php

declare(strict_types=1);

/**
 * Template for starting any system design problem
 */
final class SystemDesignTemplate
{
    public function start(string $problem): void
    {
        // 1. Restate the problem
        $this->restate($problem);

        // 2. Clarify requirements
        $this->clarifyFunctional();
        $this->clarifyNonFunctional();
        $this->clarifyScale();

        // 3. State assumptions
        $this->stateAssumptions();

        // 4. Identify core entities
        $this->identifyEntities();

        // 5. Draw high-level architecture
        $this->drawArchitecture();

        // 6. Deep dive into 2-3 components
        $this->deepDive();

        // 7. Discuss trade-offs
        $this->discussTradeoffs();
    }

    /**
     * Always state your assumptions explicitly.
     * This shows maturity and prevents misunderstandings.
     */
    private function stateAssumptions(): void
    {
        // "Let me state my assumptions:
        // 1. We optimize for read performance over write
        // 2. Eventual consistency is acceptable for analytics
        // 3. We can use cloud infrastructure (AWS/GCP)
        // 4. Budget is not the primary constraint
        //
        // Does this align with your expectations?"
    }
}
### Шаблон для обсуждения trade-offs

Каждое решение описывайте через плюсы, минусы и обоснование выбора.

<?php

declare(strict_types=1);

/**
 * Trade-off analysis template
 */
final readonly class TradeoffAnalysis
{
    /**
     * @param array<string> $pros
     * @param array<string> $cons
     */
    public function __construct(
        public string $option,
        public array $pros,
        public array $cons,
        public string $verdict,
    ) {}
}

// Example usage during interview:
$options = [
    new TradeoffAnalysis(
        option: 'SQL Database (PostgreSQL)',
        pros: [
            'Strong consistency guarantees',
            'ACID transactions',
            'Rich query capabilities',
            'Well-understood operational model',
        ],
        cons: [
            'Harder to scale horizontally',
            'Schema changes can be expensive',
            'Write throughput limited by single master',
        ],
        verdict: 'Good for user profiles and metadata',
    ),
    new TradeoffAnalysis(
        option: 'NoSQL (Cassandra)',
        pros: [
            'Linear horizontal scaling',
            'High write throughput',
            'No single point of failure',
            'Tunable consistency',
        ],
        cons: [
            'No joins or complex queries',
            'Eventual consistency by default',
            'Operational complexity',
        ],
        verdict: 'Good for messages and time-series data',
    ),
];
## Чек-лист для практики
  • Потренируйтесь проговаривать мысли вслух
  • Подготовьте шаблон уточняющих вопросов
  • Практикуйте оценку нагрузки (back-of-the-envelope)
  • Научитесь рисовать архитектуру за 5 минут
  • Подготовьте 3-5 trade-off анализов для типичных решений

Выводы

Структурированный подход к решению System Design задач -- это навык, который тренируется. Начинайте с top-down подхода, всегда уточняйте требования и думайте вслух. Помните: интервьюер оценивает процесс вашего мышления, а не только финальный результат.