Пробное собеседование
Как проходить
Это репетиция настоящей технической секции. Чтобы она была полезной:
- Засеките 90 минут и не отвлекайтесь. На реальном интервью нельзя «загуглить».
- Отвечайте вслух, даже на тестовые вопросы: представьте, что интервьюер спросил «почему?». Ещё лучше — попросите друга сыграть интервьюера и задавать уточняющие вопросы.
- Задачи с кодом решайте по алгоритму из урока про live coding: уточнить → примеры → идея → код → проверка → сложность. Комментируйте вслух.
- Не подсматривайте в уроки во время прохождения. Ошиблись — это и есть ценный результат: теперь вы знаете, что повторить.
Задания внизу страницы, разбитые на блоки:
| Блок | Время | Что проверяет |
|---|---|---|
| 1. Язык | 15 мин | типы, замыкания, атрибуты классов, генераторы, конкурентность |
| 2. Алгоритмы | 25 мин | словари и подсчёт, стек, сложность |
| 3. Работа с данными | 10 мин | агрегация, сортировка по нескольким ключам, Decimal |
| 4. SQL | 15 мин | JOIN, GROUP BY, оконные функции — на настоящей SQLite |
| 5. Веб и базы | 10 мин | HTTP, индексы, ORM, JWT, Docker |
| 6. Проектирование | 15 мин | очереди, повторы, идемпотентность |
Вопросы для устной части
Интервьюер часто начинает с разговора. Ответьте вслух на каждый за 1–2 минуты, записывая себя на диктофон, потом прослушайте:
- Расскажите о себе и о проекте, которым гордитесь. Какие технические решения вы там приняли и почему?
- Чем список отличается от кортежа, а множество — от словаря? Как устроен
dict? - Что такое декоратор? Напишите на бумаге декоратор, который логирует время выполнения функции.
- Что такое GIL? Когда использовать потоки, процессы и asyncio?
- Как вы тестируете код? Что такое фикстуры и моки? Когда мок вреден?
- Что такое индекс в базе данных? Почему запрос может не использовать индекс?
- Что такое транзакция и уровни изоляции?
- Как бы вы искали причину, если API начал отвечать в 5 раз медленнее после релиза?
- Как устроен ваш процесс работы с Git и код-ревью?
- Какие вопросы у вас к нам?
Ориентиры для вопроса 8 (поиск замедления)
Хороший ответ структурирован и опирается на данные:
- Подтвердить и локализовать: метрики (p95/p99 по эндпоинтам), когда началось — совпадает ли с релизом, все ли эндпоинты или один.
- Сравнить релиз: дифф изменений, новые зависимости, миграции (новый запрос без индекса, блокировки при миграции).
- Трассировка и логи: где тратится время — база, внешний API, сериализация, CPU.
- База: медленные запросы (
pg_stat_statements),EXPLAIN ANALYZE, N+1 (выросло число запросов на запрос). - Ресурсы: CPU, память, пул соединений, очередь воркеров.
- Действие: если влияние на пользователей большое — сначала откат, потом расследование. После — тест или алерт, чтобы не повторилось.
Самооценка
После прохождения оцените себя по каждому критерию от 1 до 4 — так же, как это делают интервьюеры:
| Критерий | 1 — слабо | 4 — сильно |
|---|---|---|
| Знание языка | путаю базовые понятия | объясняю «почему» и привожу примеры из практики |
| Решение задач | не довожу до рабочего решения | быстро нахожу эффективное, обосновываю сложность |
| Качество кода | неясные имена, дублирование | читаемо, идиоматично, крайние случаи учтены |
| Тестирование своего кода | не проверяю | сам нахожу и исправляю ошибки |
| Базы данных и веб | не уверен в SQL и HTTP | JOIN, индексы, транзакции, REST без запинок |
| Проектирование | не знаю, с чего начать | структурирую: требования, оценки, компоненты, компромиссы |
| Коммуникация | молчу или говорю сумбурно | рассуждаю вслух, уточняю, принимаю подсказки |
Что повторить по результатам
| Ошиблись в… | Повторите |
|---|---|
| хешируемости, копировании, атрибутах класса | модуль «Модель данных и память», урок «Топ вопросов по языку» |
| замыканиях и генераторах | уроки про области видимости, замыкания и генераторы; каверзный код |
| выборе потоков/процессов/asyncio | модуль «Конкурентность»; вопросы для middle |
| задачах на алгоритмы | модуль «Алгоритмы и структуры данных», live coding |
| SQL | урок «SQL и sqlite3» |
| вебе, ORM, Docker | модуль «Python в работе» |
| проектировании | урок «Основы system design» |
Повторите пробное интервью через 1–2 недели — сравните результаты. И помните: даже опытные разработчики проходят не каждое собеседование. Каждое интервью — тренировка, после которой вы готовы лучше.
Итог
- Пробное интервью полезно только в честных условиях: таймер, вслух, без подсказок.
- Оценивайте себя по тем же критериям, что и интервьюеры: знания, решение, код, проверка, базы и веб, проектирование, коммуникация.
- Слабые места → конкретные уроки курса → повторная попытка.
Практика решено 0 из 12
Блок 1. Язык. Что произойдёт при вызове d = {}; d[[1, 2]] = 'x'?
Блок 1. Что выведет код?
def counter():
count = 0
def inc():
nonlocal count
count += 1
return count
return inc
a, b = counter(), counter()
a(); a()
print(a(), b())
Блок 1. Что выведет код?
class A:
x = []
def add(self, v):
self.x = self.x + [v]
a, b = A(), A()
a.add(1); b.add(2)
print(A.x, a.x, b.x)
Блок 1. Что верно про генераторы?
Блок 1. Программа считает хеши SHA-256 для 10 000 файлов, читая их с медленного сетевого диска. Профилирование показало, что 90% времени — ожидание чтения. Что даст наибольший выигрыш с минимальными изменениями?
Блок 2. Алгоритмы. Верните k самых частых слов текста (слова — последовательности букв, регистр не важен;
ё считается отдельной буквой). При равной частоте — в алфавитном порядке. Сложность O(n log k) или O(n log n).
Какие тесты проверяют код (3)
assert top_words("Мама мыла раму. Раму мыла МАМА, а папа — нет!", 3) == ["мама", "мыла", "раму"]
assert top_words("b a c b a", 2) == ["a", "b"] and top_words("", 3) == [] and top_words("one, two; one 2 two 3 one", 5) == ["one", "two"]
import random
r = random.Random(7)
vocab = [f"w{chr(97 + i)}{chr(97 + j)}" for i in range(26) for j in range(26)]
text = " ".join(r.choice(vocab) for _ in range(30000))
res = top_words(text, 5)
from collections import Counter
c = Counter(text.split())
assert res == [w for w, _ in sorted(c.items(), key=lambda x: (-x[1], x[0]))[:5]]
import re
from collections import Counter
def top_words(text, k):
counts = Counter(re.findall(r"[^\W\d_]+", text.lower()))
return [w for w, _ in sorted(counts.items(), key=lambda item: (-item[1], item[0]))[:k]]
Блок 2. Проверьте, является ли строка правильной скобочной последовательностью из ()[]{};
другие символы игнорируйте. Время O(n).
Какие тесты проверяют код (2)
assert is_balanced("f(a[1], {b: (2)})") and is_balanced("") and is_balanced("нет скобок")
assert not is_balanced("(]") and not is_balanced(")(") and not is_balanced("([)]") and not is_balanced("((")
def is_balanced(s):
pairs = {")": "(", "]": "[", "}": "{"}
stack = []
for ch in s:
if ch in "([{":
stack.append(ch)
elif ch in pairs:
if not stack or stack.pop() != pairs[ch]:
return False
return not stack
Блок 3. Работа с данными. Дан список заказов — словарей {"user": str, "amount": число, "status": str}.
Напишите report(orders), возвращающую словарь user → {"paid": сумма оплаченных, "count": число оплаченных}
только для пользователей с хотя бы одним заказом в статусе "paid", отсортированный (как dict) по убыванию суммы,
при равенстве — по имени. Суммы считайте точно: amount может быть строкой вроде "19.99" — используйте Decimal.
Какие тесты проверяют код (1)
from decimal import Decimal
orders = [
{"user": "anna", "amount": "19.99", "status": "paid"},
{"user": "boris", "amount": 100, "status": "cancelled"},
{"user": "anna", "amount": "0.01", "status": "paid"},
{"user": "vera", "amount": 20, "status": "paid"},
{"user": "gosha", "amount": "5.10", "status": "paid"},
{"user": "gosha", "amount": "0.20", "status": "paid"},
]
r = report(orders)
assert list(r) == ["anna", "vera", "gosha"], f"Порядок: {list(r)}"
assert r["anna"] == {"paid": Decimal("20.00"), "count": 2} and r["gosha"]["paid"] == Decimal("5.30")
assert "boris" not in r and report([]) == {}
from collections import defaultdict
from decimal import Decimal
def report(orders):
totals = defaultdict(lambda: {"paid": Decimal(0), "count": 0})
for o in orders:
if o["status"] != "paid":
continue
row = totals[o["user"]]
row["paid"] += Decimal(str(o["amount"]))
row["count"] += 1
ordered = sorted(totals.items(), key=lambda item: (-item[1]["paid"], item[0]))
return dict(ordered)
Блок 4. SQL. В базе есть таблицы users(id, name) и orders(id, user_id, amount, created) (дата — строка YYYY-MM-DD).
Напишите best_month(conn): для каждого пользователя с заказами найдите месяц (YYYY-MM) с максимальной
суммой заказов и верните список (name, month, total), отсортированный по имени. При равенстве сумм берите более ранний месяц.
Решите одним запросом с оконной функцией (ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...)).
Какие тесты проверяют код (2)
import sqlite3
conn = sqlite3.connect(":memory:")
conn.executescript("""
CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT);
CREATE TABLE orders (id INTEGER PRIMARY KEY, user_id INTEGER, amount INTEGER, created TEXT);
INSERT INTO users VALUES (1, 'Аня'), (2, 'Борис'), (3, 'Вера');
INSERT INTO orders (user_id, amount, created) VALUES
(1, 100, '2026-01-05'), (1, 300, '2026-01-20'), (1, 350, '2026-02-01'),
(2, 50, '2026-03-01'), (2, 50, '2026-01-15'),
(1, 10, '2026-03-03');
""")
assert best_month(conn) == [("Аня", "2026-01", 400), ("Борис", "2026-01", 50)]
import inspect; assert "OVER" in inspect.getsource(best_month).upper(), "Используйте оконную функцию"
def best_month(conn):
return conn.execute("""
WITH monthly AS (
SELECT u.name, substr(o.created, 1, 7) AS month, SUM(o.amount) AS total
FROM orders o JOIN users u ON u.id = o.user_id
GROUP BY u.id, month
),
ranked AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY name ORDER BY total DESC, month) AS rn
FROM monthly
)
SELECT name, month, total FROM ranked WHERE rn = 1 ORDER BY name
""").fetchall()
Блок 5. Веб и базы. Верно или нет?
| верно | неверно | |
|---|---|---|
| PUT и DELETE идемпотентны, POST — нет | ||
| Внешний ключ в PostgreSQL автоматически получает индекс | ||
| 401 означает «не аутентифицирован», 403 — «аутентифицирован, но нет прав» | ||
selectinload в SQLAlchemy решает проблему N+1 вторым запросом с IN |
||
| Данные из payload JWT зашифрованы и их нельзя прочитать без секрета | ||
| В Dockerfile зависимости лучше ставить до копирования всего кода |
Блок 6. Проектирование. Сервис уведомлений отправляет письма через внешний почтовый API, который иногда отвечает 503 и иногда принимает письмо, но не успевает ответить (таймаут). Как не потерять письма и не отправить дубликаты?
Блок 6. Какой HTTP-код ответа сервер вернёт клиенту, превысившему лимит запросов (rate limiting)? Введите число.
Войдите, чтобы отмечать пройденные уроки.