Общая структура процесса
Процесс найма в большинстве технологических компаний состоит из нескольких стандартных этапов. Каждый этап фильтрует кандидатов и оценивает разные аспекты.
Воронка найма
Резюме (100%)
└─ Скрининг рекрутером (30-40%)
└─ Техническое интервью (15-20%)
└─ System Design (8-12%)
└─ Behavioral (5-8%)
└─ Offer (3-5%)
Этап 1: Подача резюме и скрининг
Что происходит
Рекрутер или ATS (Applicant Tracking System) просматривает резюме и отбирает кандидатов по ключевым критериям.
На что смотрят
| Критерий | Вес |
|---|---|
| Релевантный опыт | Высокий |
| Технологический стек | Средний |
| Образование | Низкий-средний |
| Проекты и достижения | Высокий |
| Рекомендации | Средний |
Частые ошибки
- Резюме на 5 страниц (оптимально: 1-2 страницы)
- Список технологий без контекста
- Отсутствие измеримых результатов
- Описание обязанностей вместо достижений
Этап 2: Скрининг с рекрутером
Обычно 20-30 минутный звонок. Рекрутер оценивает:
- Мотивацию кандидата
- Соответствие уровню позиции
- Зарплатные ожидания
- Доступность (когда может начать)
- Базовое понимание технологий
Совет: Подготовьте короткую самопрезентацию на 2-3 минуты. Структура: кто вы, что делаете сейчас, почему ищете, что хотите.
Этап 3: Техническое интервью
Формат
Обычно 45-60 минут. Могут быть алгоритмические задачи, задачи на проектирование кода или live coding.
Пример: задача на проектирование кода
<?php
declare(strict_types=1);
/**
* Task: Design a rate limiter for an API
*
* Requirements:
* - Limit requests per user per time window
* - Support configurable limits
* - Thread-safe (concurrent requests)
* - Efficient memory usage
*/
interface RateLimiter
{
/**
* Check if a request is allowed for a given identifier.
* Returns true if allowed, false if rate limit exceeded.
*/
public function isAllowed(string $identifier): bool;
/**
* Get remaining requests for a given identifier.
*/
public function getRemaining(string $identifier): int;
}
/**
* Sliding window rate limiter implementation.
* Provides smooth rate limiting without burst issues.
*/
final class SlidingWindowRateLimiter implements RateLimiter
{
public function __construct(
private readonly \Redis $redis,
private readonly int $maxRequests,
private readonly int $windowSeconds,
) {}
public function isAllowed(string $identifier): bool
{
$key = sprintf('rate_limit:%s', $identifier);
$now = microtime(true);
$windowStart = $now - $this->windowSeconds;
// Use Redis sorted set for sliding window
$pipe = $this->redis->multi(\Redis::PIPELINE);
// Remove expired entries
$pipe->zRemRangeByScore($key, '-inf', (string) $windowStart);
// Count current entries in window
$pipe->zCard($key);
// Add current request
$pipe->zAdd($key, $now, sprintf('%s:%f', $identifier, $now));
// Set TTL for automatic cleanup
$pipe->expire($key, $this->windowSeconds);
$results = $pipe->exec();
$currentCount = $results[1];
return $currentCount < $this->maxRequests;
}
public function getRemaining(string $identifier): int
{
$key = sprintf('rate_limit:%s', $identifier);
$now = microtime(true);
$windowStart = $now - $this->windowSeconds;
// Clean up and count
$this->redis->zRemRangeByScore($key, '-inf', (string) $windowStart);
$currentCount = $this->redis->zCard($key);
return max(0, $this->maxRequests - $currentCount);
}
}
- Чистота кода: именование, структура, SOLID
- Понимание trade-offs: почему выбран этот алгоритм
- Edge cases: что если Redis недоступен? что если время рассинхронизировано?
- Тестируемость: можно ли этот код протестировать
Этап 4: System Design интервью
Формат
45-60 минут. Открытая задача на проектирование системы. Нет единственно правильного ответа.
Типичные задачи
- Спроектируйте URL shortener
- Спроектируйте систему уведомлений
- Спроектируйте ленту новостей (News Feed)
- Спроектируйте систему чата
Структура ответа
- Уточнение требований (5-7 минут)
- Высокоуровневый дизайн (10-15 минут)
- Детализация компонентов (15-20 минут)
- Обсуждение trade-offs и масштабирования (10-15 минут)
<?php
declare(strict_types=1);
/**
* Example: High-level design sketch for URL Shortener
* This is how you might think about components during an interview
*/
// Step 1: Define the API contract
final class UrlShortenerController
{
public function __construct(
private readonly UrlShortenerService $service,
) {}
/**
* POST /api/urls
* Create a short URL
*/
public function shorten(Request $request): JsonResponse
{
$command = new ShortenUrlCommand(
originalUrl: $request->get('url'),
userId: $request->getUserId(),
customAlias: $request->get('alias'), // optional
ttlDays: $request->get('ttl', 365),
);
$result = $this->service->shorten($command);
return new JsonResponse([
'short_url' => $result->getShortUrl(),
'original_url' => $result->getOriginalUrl(),
'expires_at' => $result->getExpiresAt()->format('c'),
], 201);
}
/**
* GET /{code}
* Redirect to original URL
*/
public function redirect(string $code): RedirectResponse
{
$url = $this->service->resolve($code);
if ($url === null) {
throw new NotFoundException('Short URL not found');
}
// Track analytics asynchronously
$this->service->trackClick($code);
return new RedirectResponse($url, 301);
}
}
// Step 2: Service layer with key decisions documented
final class UrlShortenerService
{
/**
* Key design decisions to discuss:
* 1. ID generation: Base62 encoding of auto-increment vs random
* 2. Storage: SQL for metadata, cache for hot URLs
* 3. Analytics: async via message queue (not blocking redirect)
* 4. Custom aliases: separate table with uniqueness constraint
*/
public function __construct(
private readonly UrlRepository $repository,
private readonly CacheInterface $cache,
private readonly MessageQueue $queue,
private readonly IdGenerator $idGenerator,
) {}
}
Формат
30-45 минут. Вопросы о прошлом опыте, конфликтах, лидерстве, неудачах.
Метод STAR
- Situation -- опишите ситуацию
- Task -- какая была задача
- Action -- что вы сделали
- Result -- какой был результат
Типичные вопросы
| Категория | Пример вопроса |
|---|---|
| Конфликты | Расскажите о разногласиях с коллегой по техническому решению |
| Лидерство | Как вы влияли на техническое решение без формальной власти |
| Неудачи | Расскажите о проекте, который не удался |
| Сложности | Самая сложная техническая проблема, которую вы решали |
| Рост | Как вы изучали новую технологию под давлением дедлайна |
Этап 6: Принятие решения и оффер
Как принимается решение
После всех интервью обычно проходит hiring committee -- встреча интервьюеров:
- Каждый интервьюер дает оценку: Strong Hire, Hire, Lean Hire, Lean No Hire, No Hire
- Обсуждаются сильные и слабые стороны кандидата
- Принимается коллегиальное решение
- Определяется уровень (grading)
Компоненты оффера
| Компонент | Описание |
|---|---|
| Базовая зарплата | Фиксированная ежемесячная оплата |
| Бонус | Годовой, квартальный или по результатам |
| Акции/опционы | RSU, ISO, ESOP |
| Бенефиты | Страховка, обучение, оборудование |
| Signing bonus | Единоразовая выплата при выходе |
Таймлайн процесса
Неделя 1: Подача резюме + скрининг рекрутером
Неделя 2: Техническое интервью
Неделя 3: System Design + Behavioral
Неделя 4: Hiring committee + решение
Неделя 5: Оффер + переговоры
Совет: Процесс может занять от 2 до 8 недель в зависимости от компании. В стартапах обычно быстрее, в корпорациях -- дольше.
Подготовка к каждому этапу
Чек-лист
- Резюме: количественные результаты, чистая структура
- Скрининг: подготовить самопрезентацию, изучить компанию
- Техническое: практика на LeetCode/Codewars, чистый код
- System Design: изучить паттерны, практиковать на бумаге
- Behavioral: подготовить 5-7 историй по методу STAR
- Оффер: изучить рынок зарплат, подготовить аргументы
Выводы
Процесс найма -- это двустороннее оценивание. Компания оценивает вас, но и вы оцениваете компанию. Подготовка к каждому этапу повышает вашу уверенность и показывает профессионализм.