Сегодня у меня было собеседование, которое закончилось через 14 минут.
Вакансия
Сбербанк, вакансия внутри SberOS - их собственной операционной системы на базе Debian, позиционируют как независимую разработку без привязки к сторонним поставщикам. Искали Python-разработчика в UI-команду - то есть не бэкенд, а именно интерфейсы для этой ОС: десктопные пакеты с QML, покрытие кода тестами, развитие SDK, поиск узких мест, патчинг опенсорсных решений.
Из требований запомнились самые характерные: Python от 3 лет, Linux на уровне системного администратора (желательно Debian), пакетирование, git и GitFlow, PyQt6/PySide и Qt6/QML, D-Bus, pytest, SOLID/DRY/KISS/YAGNI. Плюсом - CI/CD и отдельным блоком опыт с генеративными моделями (GigaChat, Kandinsky).
Я - веб-разработчик. Из этого списка на практике не трогал вообще ничего системного: ни Debian-пакетирование, ни D-Bus, ни десктопный Qt/QML. Только Python как язык и общие принципы разработки.
Подготовка за 2,5 часа
Разрыв между требованиями и моим опытом был очевиден, так что я не пытался выучить всё “по книжке”, а прошёлся по каждому незнакомому пункту точечно - устроил себе интенсивный ликбез.
Начал с теории без привязки к незнакомому стеку - SOLID/DRY/KISS/YAGNI и паттерны, вспомнил, где похожее видел в своём опыте, в частности в Django. Дальше освежил GitFlow - ветки main/develop/feature/release/hotfix и зачем такая схема нужна для версионных релизов. Самым чужеродным оказалось Debian-пакетирование: разобрался, что такое .deb-пакет, чем dpkg отличается от apt, из чего состоит структура debian/. Потом PyQt6/PySide и QML - ключевая часть вакансии, раз позиция в UI-команде: разобрался, как Python-бэкенд общается с интерфейсом через Property, Signal и Slot, и даже написал маленький калькулятор в качестве примера. После этого D-Bus - механизм межпроцессного взаимодействия в Linux, разница между system bus и session bus. Потом systemd - юниты, команды start/stop/enable/disable, политики перезапуска, journalctl. Под конец прошёлся компактнее по HTTP/REST (это я и так знаю по вебу), CI/CD на уровне принципа и по ИИ-блоку - там у меня реально было преимущество, я использую ИИ-инструменты, в частности Claude Code, в повседневной работе.
В итоге получилась неплохая карта местности: я понимал каждый термин, мог объяснить механизм своими словами и привести аналогию. Не хватало практики руками - рассказать, как работает, я мог, а вот сесть и написать рабочий .deb-пакет прямо сейчас - нет.
Как всё началось
Стартовало стандартно, с вопроса про опыт. Тут всё прошло гладко - рассказал, чем занимаюсь, какие задачи решал.
А дальше разговор свернул не в QML и не в D-Bus, которые я готовил, а в базовые каверзные вопросы по Python, которые я не трогал уже давно.
Задача первая
Показали код и попросили сказать, что выведется на каждой строчке:
def function(test_list: list = []):
test_list.append(1)
print(test_list)
test_list = []
function()
function(test_list)
function()
print(test_list)
Суть в том, что значение по умолчанию ([]) создаётся один раз, в момент объявления функции, а не при каждом вызове. Если аргумент не передавать явно, функция каждый раз работает с одним и тем же списком, который копит данные между вызовами. А если передать свой список явно - она работает уже с ним, и это отдельный, независимый объект.
Эту особенность языка я попросту не трогал уже много лет. В повседневной работе с изменяемыми значениями по умолчанию почти не сталкиваешься - линтеры и проверка кода коллегами обычно ловят такое ещё на этапе написания. Само правило “не используй изменяемый объект как значение по умолчанию” я, видимо, выполнял на автомате, не задумываясь почему. А когда дошло до того, чтобы объяснить механизм вслух и предсказать конкретный вывод под давлением - оказалось, что деталей в голове не хватает.
Задача вторая
Дальше показали вариацию того же кода:
def function(test_list: tuple = []):
test_list.append(1)
print(test_list)
Формально добавили только аннотацию типа - : tuple вместо : list. Но в скобках всё ещё стоит [], реальный объект по умолчанию как был списком, так и остался. Аннотации типов в Python не влияют на поведение кода во время выполнения программы - это подсказка для человека и для IDE, а не проверка, которую язык применяет сам.
Я на этом моменте тоже поплыл - интуитивно предположил, что раз в коде написано tuple, то поведение как-то изменится. Про то, что аннотация ничего не меняет при запуске, я, видимо, тоже давно не задумывался - каверзных задач по Python не решал долго, и такие тонкости успели стереться.
В итоге ошибся в предсказаниях по обеим задачам, во всех строчках вывода =)
Что я вынес в моменте
14 минут - неприятное число. Оно бьёт по самооценке сильнее, чем должно. Была пара минут, когда в голове крутилось что-то вроде “значит, я вообще не разработчик” - и это, конечно, слишком большой вывод из одного разговора в один конкретный день. Но в моменте так не ощущается. Обидно, когда готовился 2,5 часа, разобрал целый пласт незнакомых системных технологий, а подвели детали именно там, где, казалось бы, должен быть уверен - в языке, на котором пишешь каждый день.
И отдельная горькая ирония: всю подготовку потратил на темы, которые даже не спросили. QML, D-Bus, systemd, Debian-пакетирование ни разу не всплыли за эти 14 минут. Спросили именно то, к чему я не готовился специально, потому что казалось “и так знаю”.
Я не эксперт в том, как вообще устроены такие собеседования изнутри, но подозреваю, что это довольно частая история - не только у меня.
Что забираю из этого и план
Живое собеседование - это ещё и про стресс и скорость мышления под давлением, отдельный навык, который тренируется отдельно от знаний как таковых. Конкретно эти пробелы понятные и решаемые - не фундаментальное незнание языка, а детали, которые давно не всплывали в практике. Быстрый провал не всегда значит некомпетентность в целом - иногда это просто нестыковка вакансии с опытом плюс пара точечных дыр, которые закрываются целенаправленной практикой. И на будущее - база языка, на котором работаешь каждый день, стоит того же внимания при подготовке, что и новый незнакомый стек, даже если кажется “это я и так знаю”.
План простой: закрыть именно такие ловушки языка практикой руками - изменяемые значения по умолчанию, is против ==, замыкания в циклах, nonlocal/global, и вообще пройтись по классическим каверзным вопросам, которые любят спрашивать на собеседованиях. Беру код, сначала предсказываю вывод сам, потом проверяю запуском, если ошибся - разбираю, почему, пока объяснение не сложится в голове до конца, а не просто “запомню правильный ответ”.
Не идеальный день, но с понятным списком того, что тренировать дальше.
По традиции, всем дочитавшим - чтобы на собеседовании спрашивали именно то, к чему вы готовились, а не то, что казалось “и так знаю”. Как-то так. 😌
