FEDOR BORSHEV
24.5K subscribers
36 photos
1 video
4 files
673 links
Рассказываю, как руководить программистами

[email protected] / borshev.com

Реклама не продаётся
Download Telegram
А еще на VC вышла моя статья о том, как правильно готовить гитхаб, чтобы людям не приходилось переключаться между 5 разными средствами коллаборации — https://vc.ru/services/60710-github-kak-edinstvennoe-sredstvo-obshcheniya

Если на работе вас сейчас достает Асана\Битрикс\Жира и слек с телеграмом, почитайте по ссылке как надо было.
Python: никогда не использовать unittest

В стандартной библиотеке питона лежит модуль unittest — набор инструментов для написания тестов. В комлпекте Django лежит даже надстройка над unittest, которая умеет ходить в API и заворачивать тесты в транзакции.

Так вот — никогда не пытайтесь использовать эту библиотеку, даже на маленьких проектах и даже чтобы попробовать. Unittest — ОЧЕНЬ плохая библиотека.

Начнем с того, что unittest — это порт древнего Junit, кажется вообще первого инструмента для тестирования, которое придумало человечество еще в 90-х годах. От Java в нем осталось совершенно ненужное ООП и наркоманские ассерты, вроде self.assertEqual(a, 'b') вместо assert a == 'b'.

А еще:
— unittest не умеет нормально распараллеливать тесты (вроде бы есть nose, но он умер). Когда на проекте появляется больше 500 тестов, это становится большой проблемой.
— unittest не позволяет переиспользовать фикстуры. Только через наследование, из-за которого вы очень быстро перестаете понимать, что у вас вообще происходит.
— В unittest очень неудобно отключать тест большими кусками — у вас нет возможности пометить набор тестов, скажем как требующий elasticsearch, и прогонять их только в средах, где elasticsearch доступен — только по именам тестовых классов
— У unittest очень плохой генератор тестов.

Возьмите лучше pytest. Да порог входа чуть выше — функциональное программирование понятно не с первого раза. Но если вы собираетесь построить проект с управляемыми тестами, то замену вы вряд ли найдете.

Кстати, каждый тесткейс на unittest — это тесткейс и на pytest, так что можете взять его прямо сейчас.
Чем опытнее программист, тем проще код он пишет

Как отличить код новичка от кода опытного синьора? Код у синьора обычно проще и понятнее, чем код новичка, который решает ту же задачу. Код у крутого синьора понятен настолько, что гляда на код бизнес-логику может осознать человек, который знает английский язык, но ничего не понимает в программировании.

Я говорю не о цикломатической сложности — дело скорее в читаемости. У новичка код как будто из фильма про хакеров: неинтутивные названия переменных (o вместо order), сложные методы, излишние абстрактные классы и генераторы, «лазанья» и т.д.

Хотите стать синьором — пишите проще. Представьте, что ваш код будет читать QA, который не сильно глубоко знает ваш язык, и сделайте так, чтобы он вас понял.
Вопрос: были ли у вас проблемы с внимательностью у разработчиков? Как отлавливаете это на собеседовании?

Я знаю, что существуют тесты на внимательность для бухгалтеров — им дают бумажку с двумя колонками длинных цифр и просят найти отличия. Разработчиков тестировать таким образом кажется странным: сверять цифры — это задача машины.

Я проверяю внимательность новых ребят точно таким же способом, как проверяю проактивность, усидчивость, умение управлять своим временем, понимать коллег, разбираться в бизнес-контексте и читать документацию — я просто предлагаю им пару недель поработать в моей команде. Работает лучше любых тестов и вопросов про крышки люков или форму пожарного ведра.

А вообще хочется разобраться поглубже — какие проблемы невнимательность вызывает в бизнесе? Возможно проблема не в разработчиках? К примеру, если вам кажется, что из-за невнимательности говно часто попадает в релиз, то наверное у вас плохие тесты или проблемы с QA. Если невнимательность приводит к тому, что программисты не соблюдают требования, прописанные в задачах, то может быть вы просто мало говорите со своей командой?

Другие вопросы — #вопрос. Задать свой — @fedor_borshev
Стали бы мы делать эту задачу, если бы компании оставалось жить две недели?

А месяц?

Кажется этот вопрос стоит задавать про каждую задачу на планировании каждого спринта. И если ответ оба раза отрицательный, то такую задачу стоит выкинуть даже из беклога.
Презентация — неотъемлемая часть работы

Много ребята спрашивает, как работает практика видеопрезентаций по каждой задаче, которую мы ввели несколько месяцев назад.

Отвечаю — работает прекрасно: в 99% случаев, когда исполнитель приложил видео или скриншот к задаче, она не возвращениям обратно со словами «ничего не работает».

Презентация работы — это неотъемлемая и равноправная часть самой работы. Недавно мы, к примеру запускали новый калькулятор доставки. У нас он сложный — тарифы зависят от срочности, особенностей товара (к примеру гипсокартоновый профиль не увезешь на Портере), необходимости поднимать, носить, разгружать товар и ещё кучи параметров.

С задачей мы справились — все эти параметры начали сводиться к одному единственному числу — стоимости доставки. Но переписка с бизнесом по поводу крайних случаев затихла только тогда, когда внизу, по специальному GET-параметру мы вывели полную расшифровку: доставка стоит X рублей, потому что в заказе есть вот такой-то габаритный товар, общий объём корзины такой-то, а ещё вот надбавка за срочность.

Если бы мы сделали такую расшифровку в самом начале задачи, то запустились бы как минимум на неделю быстрее. Мораль — думайте о презентации работы в самом начале: тогда и в ожидания заказчика попадёте с большей вероятностью, и сама сдача пройдет быстрее.
Вопрос: как программисту начать отвечать за результат? Не просто выполнять задачи, но и предлагать своё видение?

Если вы, получая новую задачу, каждый раз начнете просто озвучивать свое мнение о том, как правильно ее было бы поставить, обычный менеджер скорее всего начнет защищаться, и конструктивного диалога не получится.

Реальный пример:
— Давай сделаем рассылку писем через мейлджет? Будем сами рассылать по нашей клиентской базе, сделаем сервис отписки и т.д.
— Но ведь у мейлджета уже есть инструменты не только для транзакционных, но и для маркетинговых писем. Это как раз то, что нам нужно! Давай их заюзаем?
— Ну, а зачем нам от него зависеть? А если мы провайдера сменим? Давай лучше про следующую задачу поговорим.

Сделали предложение, задав плохой вопрос. Получили плохой ответ, и итоге в спринт уходит плохая задача.

Чтобы принести пользу — задавайте открытые вопросы:
— Давай сделаем рассылку писем через мейлжет? Будем сами рассылать по нашей клиентской базе, сделаем сервис отписки и т.д.
— Скажи, а чего нам не хватило в стоковой функциональности мейлджета? Почему ты решил усложнить?
— Мы хотим по расписанию отправлять дайджест из самых популярных товаров за неделю, а руками каждый раз их лень верстать. На шаблонах мейлджета такое сделать невозможно.
— А что если мы скриптом сверстаем 5 писем на месяц вперед, разошлём силами мейлджета, а если письмо докажет свою эффективность, то будем думать, как автоматизировать?
— Давай!

Задали открытые вопросы, поучаствовали в диалоге, принесли пользу: не делаем глупую задачу.

Отвечая на ваш вопрос — просто побольше участвуйте в обсуждениях, но всегда начинайте с вопросов, а не с предложений.
Сначала процесс, потом автоматизация

Когда ко мне приходят за новой фичей на проектах для внутреннего пользования, я всегда задаю важный вопрос — какой процесс мы автоматизируем?

Если в ответ мне описывают процесс, то все хорошо. К примеру люди сами автоматизировали себя на гугл-доках, или хотя бы в состоянии описать что они делают, типа «сейчас я ношу счета в бухгалтерию лично, а хочу кидать электронные». В таком случае смело продолжаем обсуждение.

Если процесса нет, и его клятвенно обещают запустить вместе с релизом — это проблема. Сможем ли мы мотивировать участников процесса работать по-новому? Достаточно ли они увидят ценности в новом процессе? Нужен ли этот процесс бизнесу, если мы до сих пор без него живем?

Пока люди сами не протопчут себе дорожку — никакие указатели направления не заработают.
Как резать фичи на основе экспериментов

На сайте бюро вышел мой совет о том, как резать фичи на основе экспериментов — 
https://bureau.ru/soviet/20190425/

Там я описываю подход из классических книг по менеджменту, который позволяет не инвестировать дорогущее время разработки непонятно куда.
Вопрос: я — менеджер с небольшими знаниями программирования. Как мне начать новый проект? К примеру я придумал идею нового мега-сервиса, накидываю на бумажке план, а потом приходится заниматься скучной фигней: структурой БД, архитектурой кода — ведь исполнителей пока нет. На этом я и перегораю.

Разделю ответ на два — расскажу о внутреннем настрое (хотя нет, лучше просто дам ссылку на курс Тимура Зарудного о долговременных начинаниях) и дам лайфках.

Лайфхак: не пишите код, если вам скучно. А лучше вообще не начинайте новые проекты с кода. Особенно, если вы в этом не профессионал, и не хотите делать программирование своей профессией. Придумайте, как проверить вашу идею без кода. Возьмите готовый бекенд вроде FireBase, накидайте интерфейс в Retool, сверстайте сайт на Тильде, возьмите какую-нибудь Headless CMS если надо.

В общем не думайте про код, думайте про максимально быстрый прототип. Когда у вас на руках появится провернная идея с прототипом, вы легко сможете привлечь профессионалов, которые напишут код за вас. Ну а потом всего 10 лет поработаете по 12 часов в день без выходных, и там уже до IPO недалеко.

Другие вопросы — #вопрос. Задать свой — @fedor_borshev.
#работамечты

Аналитик к нам в ГдеМатериал

Работа аналитика в нашей компании построена вокруг проверки гипотез — никто не будет просить вас «выгрузить данные по продажам за 2018 год». К вам будут приходить стейкхолдеры с гипотезами и задавать вопросы, к примеру «что, если бы в нашей скоринговой модели для назначения поставщика появился параметр fail rate?», или «что будет, если мы жестко ограничим доставку по регионам?».

Если вы начнете приходить к стейкхолдерам со своими гипотезами — мы выдадим вам столько ответственности, сколько понадобится для их проверки, и приложим все возможные усилия, чтобы вы стали крутым продакт-менеджером.

Любой аспект нашей деятельности мы покрываем цифрами. Если вам не хватит данных — поможет команда разработки во главе со мной. Данные храним в PostgreSQL и Google Big Query, все БД объединены в единое информационное пространство — мы легко делаем джоины между данными по посещаемости сайта и отгрузкам товаров.

Работа удаленная, график свободный.

Если вы умеете соблюдать дедлайны и знаете SQL на отлично — напишите Саше Хлебниковой на [email protected].

Если вы джуниор — тоже напишите, возьмем на стажировку и научим.
Вопрос: как ты думаешь, CTO — это рост из тим-лида или тех-лида?

Я знаю крутых представителей обоих лагерей — и профессиональных программистов и профессиональных управленцев. Смело могу утверждать, что хорошие CTO выходят с обоих сторон.

Дело в том, что к приходу на C-level у людей появляется очень важный навык — нанимать других людей, которые компенсируют их слабые стороны. Скажем, я пришёл со стороны программистов, и весьма слаб в управлении продуктом и дизайне. Я вполне это понимаю, поэтому привлекаю в компанию людей, которые делают это лучше меня. Если бы я пришёл из мира управления, и был бы, скажем, не силен в программировании — я бы просто нанимал более крутых технарей, чем я.

Вообще, в подборе людей самая сложная задача у CEO — он вообще должен нанимать исключительно людей, сильнее себя :-)

Возвращаясь к вопросу — есть компании, которым лучше подходят выходцы из разных лагерей. К примеру технологичный стартап лучше начинать с CTO-программистом, чем с CTO-управленцем. В банке или страховой компании, думаю, наоборот.

Другие вопросы — #вопрос. Задать свой — @fedor_borshev
Пулл-реквесты меньше 500 строк

У нас в ГдеМатериале есть правило — пулл-реквест не должен быть больше 500 строк.

Во-первых, смотреть длинный ПР — сложно: нужно выделять на это время в календаре, осознавать задачу, которую решал автор. Маленький ПР, который делает одну понятную вещь, можно посмотреть практически на бегу, а значит разработчики друг друга не ждут.

Во-вторых, мерджить большой ПР — опасно: чем больше нового кода, тем больше возможных ошибок. Если код декомпозировать на много маленьких пулл-реквестов и мерджить их по одному, то осознать и локализовать проблемы становится гораздо легче.

А еще декомпозиция хороша сама по себе — пусть лучше у тебя не примут немного кода в начале спринта, чем много и в конце.
Избавиться от состояния

Состояние приложения — это загруженные файлы, данные в базе и кеше, временные файлы. Состояние — это всегда неудобно: его приходится перетаскивать с места на место вместе с кодовой базой, обслуживать демоны, которые его хранят, если это файлы — как-то их раздавать.

Чем меньше в вашей инфраструктуре состояния — тем лучше. Идеальный вариант для небольших проектов — отдавать работу с состоянием профессионалам: хранить файлы в облачных бакетах, базу — в managed базах данных.

Так вы упрощаете свою инфраструктуру, и особенно — локальный деплой на машину разработчика. Представьте, что у вас есть бекенд большого сайта с картинками, который складывает файлы на ту же машину, где работает. Чтобы воссоздать рабочую среду локально, придется все эти файлы скачивать на машину разработчика — уныло, особенно если их 10 гигабайт.

А вот если файлы хранятся в облаке, то достаточно прописать read-only доступ к ним в docker-compose.yml, и все будет доступно на той же машине, на которой запускают бекенд. Так любой фронтендер сможет поднять у себя сайт со всеми картинками и отлаживать верстку локально, или, скажем, тестировать производительность в CI.
#гитхаб анонсировал package registry — реестр внутренних пакетов организации. Фактически это полная замена gemfury, о котором я писал в прошлом году, и немножко замена docker hub (реестр контейнеров тоже есть).

Кроме докера, есть поддержка JS, Java, Ruby и .NET, другие, думаю, тоже скоро подвезут.

Киллер-фича лично для меня — возможность управлять доступом из одного места: открываешь доступ к проекту на гитхабе и сразу же вместе с этим открывается доступ к публикации артефактов.

Анонс тут, записываться на бета-тестирование тут.
Вопрос: что делать с задачами, которые прилетают посреди спринта? Бизнес всегда очень убедительно объясняет, что они важнее, чем то, что мы делаем сейчас. Все бросать?

Сходу бросать все точно не стоит. Рабочее время ваших исполнителей — это святое: ни один человек не может принять за другого человека решение, чем тот будет заниматься прямо сейчас. Вы же не станете решать за коллег, когда им идти в кафе или ложиться спать? Время на задачи — точно такое же личное время, как и время на сон.

Однако, неприкосновенность времени программистов — слабый аргумент для бизнеса: в конце концов деньги в вашей компании зарабатывают те, кто ставит задачи, а не те, кто их делает. Ваша задача, как руководителя — сделать так, чтобы разговоры о необходимости все бросить возникали как можно реже.

Разберитесь, почему важные и срочные задачи чаще всего прилетают посреди спринта? Если большинство таких задач — ошибки, поработайте над качеством: наймите QA, расправьтесь с техдолгом, напишите побольше автотестов.

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

Если посреди спринта прилетают сложные и важные задачи, которые приносят много денег — разберитесь, почему эти задачи не появляются к началу спринта. Может быть у вас не синхронизированы производственные циклы, и, скажем, дизайнеры забыли, когда начинается спринт у программистов?

Другие вопросы — #вопрос. Задать свой — @fedor_borshev.
Начинаем проект на Django: собственные точки входа

Уверен, что это правило актуально не только для Django, но и для любого фреймворка — всегда используйте собственные базовые точки входа.

К примеру, ваш фреймворк предоставляет базовую модель — сделайте собственную копию и наследуйтесь от нее. То же самое с базовыми вьюхами, базовыми пермишенами и базовым всем. Минимум для Django — базовая модель, базовый ModelAdmin и базовый вьюсет DRF. Для базовой модели рекомендую выбрать что-нибудь из django-behaviors.

На старте собственные точки входа не стоят почти ничего, и при этом здорово помогают, когда ваш проект дорастает до сложных требований, ради которых приходится модифицировать или вообще выкидывать нижележащий фреймворк. Канончиный пример — Инстаграм, который в 2011 году выкинул Django ORM.

Кастомные точки входа стоит сделать в начале проекта еще и для того, чтобы ваши программисты их постоянно видели — так они с большей вероятностью начнут рассматривать модификацию базовых точек входа как опцию в своих архитектурных решениях.
Как донести HADI до руководства

Вышел мой совет о том, как продавать руководству идею продуктовых экспериментов — https://bureau.ru/soviet/20190516/
Вопрос: как увольнять людей без драмы и внутренней боли?

Вообще конечно лучше не нанимать людей, которых приходится увольнять :-)

Если серьезно, то в хороших командах процесс увольнения — неявный, драмы уж точно никакой нет. Дело в том, что если сотрудник перестаёт справляться со своими обязанностями, то у него их просто забирают — коллеги перестают приходить с вопросами и задачами. Если у человека совсем не остаётся обязанностей, он сам чувствует, что перестает покрывать зарплату, и уходит.

Если увольнение все-таки не случается естественным путем, руководителю приходится его форсировать. Прежде, чем инициировать разговор об увольнении, подготовьтесь — вдруг в вашей команде уже есть вакансии, которые лучше подходят увольняемому человеку?

Идеально, когда расставание происходит без сжигания мостов. Важно сделать так, чтобы люди, которые уже работали с вами и разделяют ваши ценности, всегда были готовы к вам вернуться. Посредственный программист через год может стать хорошим техническим писателем, плохой дизайнер — менеджером.

Если не нашли что предложить, тогда остается только разговор. Самый лучший формат для такого разговора я подслушал у Байрама Аннакова — встречаемся с сотрудником и предлагаем ему выбор: или уйти прямо сейчас, забрав зарплату за месяц вперед, или поработать еще месяц и показать руководителю, что он ошибается. Если человек выбирает первый вариант — он точно не ваш.

Другие ответы — #вопрос. Задать вопрос — @fedor_borshev
Не копить изменения

Вроде бы простое правило, но соблюдается плохо, особенно в маленьких командах: никогда не копите изменения на стейджинге. Когда вы неделю пилите код, напилили 3000 строк и разом выкладываете это в прод, это почти всегда оканчивается проблемами и хотфиксами в мастере.

Дело в том, что даже самый полный набор автотестов и самый внимательный QA не защитят вас от банальной фигни — неполноты ваших представлений об окружающем мире. В момент публикации случается все что угодно, кроме того, что вы предусмотрели: ваш код под нагрузкой роняет приложение, третья из пяти скопившихся миграций падает на боевой базе, люди вместо данных забивают фигню в формы (и не в том количестве, что вы ожидали), падает метеорит и т.д.

Чтобы избежать острой боли при публикации, соблюдайте принцип прогрессивного джипега: пусть ваша задача будет всегда готова на 100%, но проработана она может быть и на 1%.

Растяните один релиз на 10 маленьких, но зато каждый день. 10 пулл-реквестов для одной задачи — это вполне нормально.

Публикуя по нескольку релизов в день, перед обещанным запуском задачи вы точно не получите никаких сюрпризов — ведь ваш финальный релиз будет содержать всего лишь включение нужного фиче-флага.
settings.local.py

Ещё один антипаттерн, который я часто встречаю в проектах Django (да, мне приносят их на ревью: напишите на [email protected], чтобы я посмотрел ваш) — это несколько файлов settings.py для разных сред. Чем это вызвано, в общем-то понятно: думаю авторы джанги до сих пор краснеют от своей идеи хранить настройки в гигантском питоньем файле.

Но раз уж от settings.py мы никуда не денемся, давайте хотя бы попробуем его сделать более понятным. Представьте, что ваше приложение крутится в трёх местах: прод, стейджинг и машина фронтендера. Во всех — разные настройки доступа к БД, на дев-машинах могут быть отключены какие-то фичи и и.д. Если вы заведете settings.prod.py и settings.dev.py то, вам придётся заводить два разных докер-образа для этих целей, либо писать код, который в зависимости от среды будет определять нужный файл настроек. А правильно определять среду — весьма интересная задача, учитывая то, что делать это придётся изнутри изолированного контейнера.

Решать проблему разных настроек нужно при помощи третьего правила 12-факторного приложения — переменных окружения. Вся конфигурация вроде доступов к базе и фиче-флагов должна храниться в переменных окружения. Так вы сможете запускать одну и ту же кодовую базу через один контейнер в удобной конфигурации в любой среде — ведь переменные окружения так приятно хранить в docker-compose.py или в настройках UWSGI если вы олдфаг.

Для Джанго существует пакет django-environ: просто поставьте его и забудьте про settings.local.py.