Pain Driven Development

Антон 🐺 Назаров
11 min readMar 21, 2019

--

Каждый клиент моей кофейни должен знать, где ставить ударение в слове “латте”.

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

Даже в свежей IT области имеют место извечное утаивание и наебалово. Работу айтишник может поменять за месяц, это все знают. Но неудобную правду продолжают пытаться скрывать. Удобную же правду с удовольствием публикуют. Так и живут, трясясь, что кто-то узнает, чем конкретно приходится заниматься.

Я совсем не бунтарь-максималист, но верю, что корнем любых выгораний и синдромов самозванца является ложь. Ложь всем вокруг и себе в частности. Поэтому искренне расскажу, чем довелось заниматься год. Джун поберегись, а синьор улыбнись.

мой стандартный день день

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

Обычно структура такова: ТАМ (онсайт) сидят разработчики и тестировщики, которых нанял напрямую клиент. Они по большей части индусы. ЗДЕСЬ (оффшор) сидит команда, которую наняли подчищать индусские каки.

Модульность

Выносим модуль, закрываем интерфейсами, общие сущности кладем в shared модуль… Говорено уже 100 раз. А у нас в одном проекте два приложения. Как тебе такое, Маск?

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

на любой чендж гоняются тесты обоих проектов

Иногда вдруг абстракция оказывается говном и не позволяет реализовать фичу. Например, две класса конформят протоколу. А тут нужно впихнуть в метод параметр, класс которого есть только в одном таргете.

Я делал ужасные вещи. Объявлял в протоколе Any, а потом даункастил к нужному типу в реализации. Полюбил respondsToSelector и performSelector. Использовал директивы препроцессора бесчисленное количество раз.

И хоть я буду гореть за это в аду, мне удалось развить способность решать задачи максимально грубо и быстро, точечно меняя код. Гипертрофированный KISS, который запрещает тебе идти любым НЕ самым коротким и уродливым путем. Можно даже идти сквозь стены и по головам, главное чтобы “завтра было сделано”.

Алло, очень много дел, все давай пока

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

Известно, что онсайт менеджеры получают бонусы за сторипоинты, сожженные за спринт. Наступил как-то дедлайн важной фичи, мердж в мастер. Гитлаб не позволяет назначать аппрувером автора PR, поэтому Аран попросил русского разраба создать PR вместо себя. И аппрувнул его.

Русские исполнили план перехват и понаоставляли замечаний. Аран недолго думая приказал открывшему PR фиксить комментарии. На резонный вопрос “А хуль не сам?” оправдался “Нет времени, надо бежать на следующий митинг”.

Несколько комментариев были на отсутствие тестов, ибо Аран проповедует подход “похуй на тесты, главное заделивирить”. Но тут русские уперлись рогом: “не будем мерджить без тестов”. На что было отвечено: “ну тогда сами и пишите, кек”. В итоге, оффшор, негодуя, переписывал индусский код, дабы сделать его хоть немного тестируемым.

Planning

Bandwidth и распределение нагрузки вообще отдельная тема. Планирование спринта выглядит так:

на это можно ответить “абсолютли”

Логика раскидывания новых задач прозрачна: “Сделал за неделю N задач? На следующей получишь N*1.25”. В какой-то момент достигается асимптотичное значение, разработчик не успевает закрыть все, хоть и зачем-то пытается. Очевидный лайфхак — час поработал, три отдохнул, ибо значение N ни на что не влияет.

Что делать, если тимлиду очень нужно купить на премию в конце месяца новую теслу, а дедлайны тютю? Закрыть еще несделанные задачи. Тикет закрыт, сторипоинты капнули, а MR создается уже потом, если конечно создается. На все вопросы тестировщиков “Dude wtf u r working on closed task?” отвечать приходится девелоперу. Как-то в “закрытой” задаче активное обсуждение шло еще месяц.

Merge vs Rebase vs Indian senior dev

Бекмердж больших фичей страшен. Я удивился, увидев как быстро это делают индусы. За час PR успевает быть созданным, заапрувленным и смердженым. Но с .pbxproject чуда не бывает. В результате от проекта отваливются строки или целые файлы описанных фич.

Была задача, которую я делал три раза за четыре месяца. Коммичу, тесты проходят, DONE. Проходит месяц, БАГ! Срочно чинить! Смотрю историю и оказывается, что бэкмерджа мои изменения не пережили. Не тратя времени на разборки, черипикаю. Плюсик к карме, оперативно закрыл critical баг.

бегом использовать pattern matching

Была табличка с доступными способами доставки из локального json. Реализовал получение JSON с сервера. Захожу спустя месяц, смотрю: по-прежнему локальный json. Лезу в историю: изменения откатили в бекмердже. Мальчик: “БЛЯДЬ ГОВНО ПСИНА ТЫ ЧО МРАЗЬ”, мужик: “фича закрыта, зарплата переведена”. До сих пор никто не заметил, что фича отсутствует.

Лебедь, щука и индус

Хотя в товарищах согласья есть, но каждый товарищ знает, как сделать еще лучше чем договаривались. Фича ветки напоминают отдельный проект со своими архитектурами практиками. Ревьювил такое:

не вижу, почему бы трем благородным донам не втянуть haskell

Стоит ли говорить о десятках одинаковых Util классах и трех разных подходах к мокированию. Зачастую хочется сделать наподобие уже реализованного. Находишь несколько примеров, делаешь свою задачу единообразно. А потом узнаешь, что твой вариант говно. Те места, откуда списывал, просто еще не успели переписать, но // TODO: refactor that shit спрятан где-то в центре файла.

Д’артаньян и три индуса

Взаимодействие онсайта с оффшором напоминает сюрреалистичную комедию. Стоит отметить высокую техническую экспертизу моих коллег. Люди знают как делать НОРМАЛЬНО, чтобы модуляризация, git-flow и линтер.

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

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

Indian flow

Это классическая схема. Но кто-то к этому еще не привык. Очень забавляют попытки все предотвратить. Всякие линтеры, ревью, запреты на пуш в фича ветки. Проталкивание всех этих инициатив дается с большим трудом, два часовых митинга для объяснения VIPER.

Это как строить карточный домик, имея 20 котов вокруг. И каждую карту нужно нарисовать самому. В любой момент на запреты и практики кладется болт, а разработчикам напоминают кто здесь правит бал. Но русские не сдаются, упорно педалят идеи, вводят новые ограничения.

А потом вдруг без всяких предупреждений отключаются учетки. Ситуация сразу же меняются. Пару дней люди работают через чужую учетку (профессионал закончит задачу ДАЖЕ БУДУЧИ УВОЛЕННЫМ). А потом начинают обновлять корпоративное резюме, чтобы убедить “тупых индусов” повторно себя купить. Сразу же вспоминается, чье тут лавэ, и огонь в глазах гаснет.

Test, Stage и Prod

можно и домой ехать

Тестовые энвайроменты постоянно отваливаются, базовые эндпоинты не работают. Тестовые данные иногда забывают добавлять в базу, иногда добавляют невалидные. Невалидные данные (зажигалка приходит с типом “мебель”) приводят к неадеквтному поведения UI. На это сразу же заводятся КРИТИЧЕСКИЕ баги, которые надо бежать фиксить. То есть, упорно объяснять QA, что “проблема не на нашей стороне”.

Рабочий день начинается с поиска рабочего энва по пяти чатикам. В случае отсутствия оного, рабочий день превращается в анальный карнавал с моканием запросов в Charles.

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

Confluence

sad, but true

Описание задачи не должно объяснять бизнес логику, содержать корнер кейсы или хотя бы тестовые данные. Вполне достаточного: “Fire analytic event when user selects delivery”. Доставку чего? Какой формат? С какого экрана отправлять? Разберешься сам.

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

  1. (optional) адресовать коллегам вопрос “Чо эт за хуерга?” и попробовать собрать по кусочкам логику
  2. Реализуем наугад, заливаем PR, ждем мерджа
  3. Откуда-то тут же вылезают QA. У них тестовые данные и AC, которых нет в описании задачи
  4. Они записывают подробные видео багов, в которых показано как воспроизвести и как должно быть
  5. Вот теперь можно начинать работать нормально

Была задача добавить в событие аналитики фирму доставки шкафа. Событие в коде отправляется из двух мест. Добавил я эту фирму, еле нашел откуда вытащить информацию. Пишут: “Из второго места шкафы покупать нельзя, выпилывай”. На мой вопрос, откуда я мог это узнать, мне предложили сесть поближке к более опытным коллегам и беспокоить их по любому вопросу.

Чистые тесты

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

bdd аннотации делают тесты чище

Был тест который загонял приложение в бэкгрануд и все оставшиеся проходили там, отчего рандомно падали. Иногда в тестах утекает нужный объект, потому что объявлен weak. Иногда незамокан нетворк или менеджер геопозиции. Подобное распиздяйство приводит к фейлам CI, которые принято чинить перезапуском билда и молитвой.

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

Много мест, разящих духом авантюрюзма и “авось смерджат”.

когда попросили потестить вайпер модуль

Очередное подтверждение индусской смекалки. Не мерджим код без тестов? Ок, вот держи, я сделаль

Так улучши сам!

На perfomance review меня попросили выставить по десятибалльной шкале впечатления от работы. Я честно ответил: процессы — 2/10, сплоченность в команде — 3/10. Но такие оценки согласно политике компании ставить было нельзя. И меня долго убеждали их поменять. Спустя пятнадцать минут я не выдержал сюрреализма ситуации, в которой двое взрослых людей просят третьего поправить циферку, и поставил везде восьмерки.

“Не нравятся процессы? НУ ТАК ИДИ УЛУЧШИ САМ”

Правильной считается позиция попрыгунчика, который лезет с нововведениями и улучшениями, практиками и советами. Я может и хотел бы быть правильным, но… Такие активисты давно есть в проекте, а процессы по-прежнему 2/10.

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

Ты должен стать добровольцем

Слышали про PagerDuty? SaaS для реагирования на баги. Мы прогали SDK для компании X. X решила продать потребителям своего SDK услуги по гарантированной поддержке. На критические баги в SDK должна последовать реакция в течении четырех часов, а фикс в течении дня.

После подписания этого договора к нам на созвон пришел менеджер компании Х и рассказал, что теперь мы по очереди должны дежурить всю неделю 24/7. По ночам и выходным. Целый день убеждал в том, что нас никто не заставляет, но мы все таки должны. И даже доплатят денег за дежурство на выходных! Но только если баги реально возинкнут. За сам процесс — нет, извините.

Поведение менеджера русского напоминало бултыхание известной субстанции в не менее известном водоеме. Он прекрасно знал, что должен убедить нас этой хуйней заниматься, но при этом не хотел потерять уважение, выступив поперек коллектива. Поэтому то вторил нашим возгласом “Да как так! По выходным? Пидорасы!”, то вдруг заводил: “А может нормально, ребят? Может потянем?”

Приоритезация задач

У Apple TV есть жалкий клон Google Chromecast. На него можно стримить со смартфона при помощи Google Cast SDK. Мы поддерживали эту вещь (оборачивали гугловоское API своей рекламой).

Дали задачу обновиться до последней версии Cast SDK. Очень долго обсуждали, поставили важнейший приоритет, отрядили двух человек. Это была самая тяжелая неделя в моей жизни. Ночевал в офисе, истерил, но сделал к дедлайну.

А потом релиз перенесли на месяц. А за месяц выяснился критический баг: “Трансляция стабильно вылетает через 7 минут”. Оказалось, у Chromecast 512 мегабайт оперативной памяти. И за семь минут наш плеер выжирал ее всю под чистую, после чего довольный подыхал. То есть, НИКТО НИКОГДА не пользовался этой фичей дольше семи минут. Этот случай научил меня становиться индифферентным к задаче любого приоритета после шести часов вечера.

Блиц

  • Аналитика на трех платформах отсылается с результатами GET запросов. Клиент что-то просит, бекенд что-то отдает, клиент отправляет в аналитику результаты запроса. Почему бы не учитывать на бэкенде? Исторически сложилось
  • Был баг с аналитикой. Нашли тикет, в котором требования поменялись через полтора дня после того, как он был смерджен. Ни дев, ни QA даже не были поставлены в известность об изменении. Даже тестинг успел пройти до того, как AC изменились кардиально
  • Один Cocoapods на билд сервере, никаких конфигов версии в CI, никакой изоляции окружения. Апдейт версии для одного проекта на 1.6.1 привел к падению всех билдов для проекта, который пользует 1.5.3
  • На ревью в AppStore упало приложение, ревью справедливо завернули. Оказалось, что аналитики крашей со стектрейсом в проде нет, а потому слезно просим у Apple скинуть логи и ждем пару дней.
индусы придумали свои секретные ошибки сер
  • Отступы между лейблами отмечены фиолетовыми прямоугольниками и подписаны текстом. Справа таким же текстом выписаны размеры шрифтов. Потом все это закинуто в PDF и сделано один из экранов в фигме
  • Делал я задачку, пытаясь догнать андройд, который пару недель бодро отписывался, что прогрес есть, скоро выкатим. И меня менеджер пингует: “швыдче, Василий”. Начал тыкаться в API, а оно не работает. Локти кусал, день разбирался, а потом с горя как рубану в чат “а че это вы тут делаете с неработающими запросами?”. Оказалось, что никто, включая андройд команду, API даже не тестировал. Ребята просто радостоно выставляли эстимейты и ходили на стендапы

Лицо коммерческой разработки

В аутсорсе невозможно создать даже отдаленную видимость дружной команды. Словосочетания “тупые индусы” и “ебал я это все” употребляются регулярно даже менеджерами. Замечания “не забывайте, кто тут платит деньги” звучат лишь чуточку реже. Только тут видишь истинное лицо IT. Без всяких прикрас типа радения за продукт, мерча и образа большой дружной семьи, которая вместе ходит в бары пить вишневое пиво.

Очевидная правда лежит на поверхности, но признавать ее хотят немногие. Иногда кто-то устает обманывать себя, перегорает и пишет длинные ноющие посты про хуевую жизнь с зарплатой в 300к/наносек. Но я никогда не выгорю от шестереночного синдрома, ведь мне с самого начала указали мое место. А чем меньше когнитивных искажений, тем легче живется.

Не работал в аутсорсе — не разработчик!

Если понравилась статья, похлопай (50 раз) и распространи ее. И завтра же иди во фрон… аутсорс :) Забегай в твиттер посраться

--

--

Антон 🐺 Назаров

Пишу про эффективное трудоустройство и зарплатный рост в IT. Весь выходящий контент тут: https://t.me/m0rtymerr_channel