Junior — роскошь

.. а не ресурс разработки Junior — человек, которому вы не можете выдать задачу сложностью выше некоторого уровня, если хотите, чтобы задача была решена в нужные вам сроки. Таким макаром в разных монастырях один и тот же человек может быть ранжирован не одинаково. В Кукусофте он middle, в Почтоваре он junior, а в учреждении для общественного воспитания детей дошкольного возраста и вовсе senior. Зависит от задач и сроков.
Ещё три исходящих пункта.
Раз. Джуниор (впрочем, как и любой другой) интересен тогда, когда для него есть фронт задач его уровня. Иными словами, стоимость их решения адекватна.
Два. Джуниор интересен тогда, когда из него хотят и могут [почти] любой ценой сделать что-нибудь другое. Характерно для больших компаний, выращивающих себе кадры, особенно штучные (тот же ШАД Яндекса примером).
Три. Джуниор интересен тогда, когда интересен не задачами и не ростом. Бывают занятные схемы. Скажем, вы аутсорсер, по контракту оплачивают работу с учётом занятых на проекте голов, выгодно эти головы набрать и демонстрировать. Это Вася. У него димплом МГУ, он джавист, уважаемый Джон Смит, похлопайте Васе и перечислите нам очередной транш. Что там за знания у Васи, чем он реально занят… никого не волнует. Такие схемы обсуждать не будем, достаточно того, что оно бывает и к разработке не относится.

Ещё ремарка про стоимость джуниоров. Давайте на пальцах следующую формулу зарплаты изобретём (почти по рынку, хоть для красоты округлил): J(unior) = n, M(iddle) = 2*J, S(enior) = 2*M. Это вот зарплата. Но работодателя интересует стоимость решений. Если junior делает софт 4 месяца, а senior тот же софт за 1 месяц, видим смешное: junior выпустил продукт на три месяца позже при senior’ной стоимости решения.
Слишком чистенько. На деле живые джуны делают ещё дольше и требуют ещё больше вложений. Они перетягивают на себя внимание middle+ (code review, консультации). Плохо интегрируются с нужной бюрократией (тексты коммитов, тикеты в JIRA). Плохо понимают командную работу (тусить в изоляции, забив на состояние мира вокруг — штатное состояние). Понимание ответственности на нуле (для них часто по воображаемым последствиям примерно равны «мама, я застелил постель» (не застелил) и «Аристарх Петрович, я протестировал все изменения перед выкаткой» (не все, не протестировал)), что добавляет рандома в production.
Всё это вместе с исправлением, обучением и банальным надзором замедляет работу остальных, что влияет на стоимость уже их решений. И, что прикольно, всё это в какой-то момент может оказаться пустотой — то вдруг оказывается, что чувак не подходит профессии. Или у него прошло увлечение и теперь он хочет на лыжах кататься. Или просто зайку не ценят и потому зайка уходит в монастырь. Или начитался про успешные стартапы и уходит в загул пилить Super Duper ToDo Tracker, который обязательно поглотит рынок.

Также нередко джуниоров, если они прям юные, надо учить:

  • жить («Сань, давай в будний вечер ты не будешь бухать до похмелья с утра, тебе два критикала срочно разрулить»),
  • общаться («Олег, заказчик не твой друзяшка со двора, давай не бычить и вообще полезно быть вежливым»),
  • взрослеть («Стёп, ты же обещал? Обещал. Не выполнил и знал заранее, что не выполнишь. Давай в следующий раз ты подойдёшь и скажешь заранее, что не успеваешь, чёт придумаем»)
  • и матереть («Филь, вот чего ты молча в пол смотрел? Тебя Иваныч сожрать собирался шоле? Нет. Голову поднять, факты озвучить, логикой задавить, в глаза смотреть спокойно, задачу не ты просрал, не тебе отвечать»).

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


Теперь подумайте и себе честно ответ: нафига всё это работодателю? Обычной софтварной конторе от гаражика до «это здание всё наше». Не приюту. Не благотворительному фонду. Не школе для одарённых детей. Не яростной молотилке кадров, в которой в день сто страниц копипасты. Вот нафига? Middle и senior выгоднее. Головняка с ними заметно меньше. Рандома в проде заметно меньше. Ставить их на путь истинный тоже проще, бойцы уже биты жизнью, могут гонор в карман спрятать и таки сделать то, что надо, а не «я так вижу». Прогноз работы с ними тоже проще — если до middle добрался, есть куда толкать и выращивать. Потому в общем случае джуниоров не нанимают. Убыточно. Проблемно. Результат не спрогнозировать. Нафиг надо.
Исключения бывают, безусловно (особенно когда у исключения «глаза горят», учебники от зубов отлетают и в анамнезе годный код на GitHub’е, тут прям удовольствие смотреть, как талант раскрывается). Но меня подбешивает, когда на голубом глазу говорят «а чё, ну наберите роту джуниоров, воспитайте, вот вам и будут кадры». Нет, спасибо. Сами набирайте. Все люди хорошие, братья, друзья и ромашки, но иногда полезнее тикеты вовремя закрывать, а не переоткрывать по десять раз, выполняя гражданский долг матери Терезы.
PS. Конечно, вы не такой junior. Это какие-то другие такие. А вы самый умный, самый хороший, самый клёвый junior в мире.

Python для собеседований

Однажды задолбался задавать на собеседованиях одни и те же вопросы без fun’а, родил функцию на Python. Веселился, придумывая. Кажется, решавшие задачку тоже получали свою порцию.
Собсно, вот код (Python 3.x):

import 'os'

func readFileId(names=[], mode):
    _ = ''
    id = -1
    for n in names:
        with os.open(n, 'w') as f:
            _ += f.read()
        f.close()
    print 'default: ' + id + ', actual: ' + _
    return id ? _ : id

Надо найти в нём ошибки. В зависимости от упоротости и перфекционизма количество ошибок от X до Z (подумал и решил таки не публиковать числа, лишняя подсказка получается). Кому и игнор PEP8 спать не мешает.

Суть упражнения (вполне типового, похожим джавистов на сертификациях кошмарят) в следующем:

  • Проверка знания языка.
  • Проверка внимательности.
  • Проверка умения думать над кодом.
  • Иногда показывает уровень чувства прекрасного.

Т.к. собираюсь написать более задорный вариант, этот «палю». Применять его больше не буду. Развлекайтесь.

PS. Тем, кто не согласен и у кого что-то не получается: пжлст, не пишите мне, что вы не поняли код, что это плохое упражнение и прочее. Значит, не для вас. Не беда.

Профессиональная самооценка

Один из неловких моментов: человек считает себя senior’ом, а ты по итогам считаешь, что он в лучшем случае серединка middle, и вот надо как-то это обосновать. Неудобно всё это, травмирующе для обеих сторон. Лучше, когда человек оценивает себя адекватно, актуально, объективно. Чтобы после десяти «не знаю» и «не помню» не собеседующего странным считал, но задумался о повышении квалификации.
Сузим контекст. Пусть Java (язык), JDK (библиотеки), JVM (виртуальная машина). Как джависту понять, на каком уровне он всё это знает?

Во-первых, сертификация. У Oracle три уровня: Associate (junior), Professional (middle), Master (senior). Попробуйте их сдать. Как вариант, можно купить mock certification у Enthuware и потренироваться. Или осилить книги вроде OCA: Oracle Certified Associate Java SE 8 Programmer I Study Guide: Exam 1Z0-808 или OCA Java SE 8 Programmer I Certification Guide. После чтения задуматься: да, обо всём этом спрашивают и всё это считается нужным для подтверждения уровня. Если вы не согласны и можете несогласие аргументированно оформить в текст, напишите в Oracle. Быть может, к вам прислушаются.
Слышал мнение, что никто сертификацию не сдаёт, никому не надо и т.п. Так вот, количество сертифицированных приближается к миллиону. Последнюю статистику нагуглить не удалось, но вот текст от Oracle времён семёрки: Java Programmer Certification: Java SE 7 Certified Programmers И да, работодатели тоже с интересом смотрят на сертификат.

Во-вторых, собеседования. Если вы являетесь senior’ом, для вас не составит труда за несколько месяцев пройти senior собеседования в top 20 работодателей. Вроде бы мороки много, но уверяю, оно того стоит. Сначала может оказаться больно и обидно, но после здравого размышления всё становится на свои места. И, грубо говоря, либо 20 человек признают ваш уровень, либо вы спуститесь на землю. Ну или затаите обиду непризнанного гения, что тоже бывает.
В top надо идти потому, что у них есть выбор, а вокруг десятки разработчиков, с которыми можно сравнить. И если местные senior’ы среди ночи легко ответят на вопрос «как выглядит integer underflow в Java», сам собою формируется некоторый стандарт уровня. Вы не можете на подобное отвечать? Окей, возможно, вы и senior, но не нашей мануфактуры.

В-третьих, актуальные учебники. Ну т.е. вот лично мне персонально индивидуально кажется странным, когда специалист, декларирующий знание языка, плавает уже в букварных темах, но знаю, есть считающие это нормальным. Каждому своё, конечно, а всё же рекомендую память подновлять. Открываете. Читаете. Чем больше «ого», «ух ты» и «вона как», тем больше «мда» в голове вас собеседующего.
Сюда же включите ознакомление с профильными курсами топовых вузов США. Они регулярно обновляются, ну и качеством выше отечественных. Сравните их требования знаний студента с вашими требованиями к себе.

В-четвёртых, конференции. Их полезно смотреть и слушать. Умные люди отбирают доклады умных людей, чтобы умные люди послушали. Послушайте и вы. После каждого доклада говорите вслух: «озвученная тема не нужна, не интересна, никто не использует, да что за бред вообще, это не надо знать». Чем менее смешной вам будет казаться эта фраза, тем дальше вы от senior Java, например.
Понимаю, тот ещё показатель. Но умиляет же, когда Шипилёв, например, собирает сотни слушателей, зал впитывает, статьи пишутся, софт делается, а потом мимоидущий senior expert guru Java developer роняет, шо то никому не надо. В общем, на этом оселке тоже не мешает после всего остального сверить себя с внешним миром.

В-пятых, определение. Подумайте и последовательно сформулируйте собственные определения senior, middle и junior. Именно в таком порядке. Опишите обязательные знания и умения уровней. Только честно и злобно. Словно перед вами сто кандидатов, надо нанять двоих и от этих двоих зависит, выйдет ваш бизнес на IPO завтра или через год. Сделали? Ожидаемо примените к себе. Всё хорошо? Теперь то же объективно примените ко всем своим знакомым разработчикам. Откалибруйте шкалу, попробуйте посмотреть на каждого через оценку его знаний в каждой области. И снова примеряйте к себе.
Надеюсь, что вы определили уровни не через скорость гугления неизвестного. И здорово, если вам хватило мудрости не определять через «о, я не умею в рекурсию, значит, настоящим senior’ам рекурсия не нужна».

Всё это я в какой-то степени прошёл. Разве что собеседований мне хватило и трёх, чтобы понять, что после двухлетнего перерыва был самоуверенным бревном, а не Java senior’ом. Правда, сейчас тоже вряд ли потяну полновоенное собеседование, ведь есть ещё Spring, Hibernate, NoSQL, RDBMS, алгоритмы, Linux, сети… Да-да, всё то, что вы обязательно нагуглите, если вдруг понадобится. ^_^

Архитектура костыля

В учебниках и разговорах постоянно про гибкую архитектуру. Гибкость то, гибкость сё. И толком не формализовали, особенно если взглянуть уровнем выше: какую объясняющую формулу (и понятную всем) дать, чтобы она работала для любого софта? Вот чтобы для разлапистых бекендов, для фронтового фреймворка, для мобильного приложения, для десктопной игрушки и т.д.
Для себя я всё же вывел такое и применяю. Правда, потом бывает сложно коллегам пояснить, почему код выглядит так, а не эдак, ну да всяко лучше иметь работающий код, а не довольных коллег при неработающем коде.
Внимайте:

Архитектура является тем более гибкой, чем больше в ней мест, в которые вы можете воткнуть костыль без переписывания остального кода. Костыль — ветвление, хардкод, жесть категории «if user == petrov { kill all }».

И никак иначе. Остальное не работает.


Фигня в том, что реальный мир, с которым соприкасается ваш софт, с его реальными людьми и прочими занятными явлениями является миром костылей. Мы вынуждены компенсировать чужие ошибки, например. Вынуждены учитывать, что в окружении сервиса любой элемент может упасть в любой момент времени. Мы должны учитывать пьяного дядю Васю на буровом тракторе в Кукуевке, испокон веков стоящей на трансгалактическом кабеле связи. Бухгалтеров. Детей с их разрушительными лапами. Распинаться так могу ещё долго.
И вот всё это хоть как надёжно друг с другом интегрируется только потому, что в каждом сервисе есть вёдра if’ов. Даже если вы по наивной прозрачности мозга выпустили в свет хрустальный сервис, уже через год в нём будет вот это вот всё. Окажется, что в стороннем API ошибка (или ошибки, если считать таковыми разработчиков API). Или к вам зайдёт очень грустная помощница очень главного директора с просьбой больше не делать с её директором то, что мы задумали делать со всеми. Или вам очень-очень надо оптимизироваться, ужимаясь в худенькую квоту серверов. Или клиент пишет «отправлять вам запросы могу ТОЛЬКО ТАК, всего вам хорошего, держитесь». Или бага в базе данных (тикет болтается с 2013 года), а вы это обнаружили за минуту до выкатки. Или от вас очень захотели работающего рендеринга сайта на IE под Mac OS образца 2007 года.
Так нафига страдать нервами по факту? Заранее, всё можно предусмотреть заранее. Не упарываться по фабрикам, возвращающим фабрики (привет джавистам). Не унифицировать всё до нечитаемой одной строчки. Не стремиться избавлять код от лишнего (что нередко не лишнее, но те части нужной реальности, что не попадают в вашу чистую модель). Не городить тонну абстракций. Пара лет эксплуатации и на активно живущем сервисе вас проклянут, пытаясь не убиться в попытках сберечь красоту (забьют болт и начнут запросто костылить, что будет гораздо уродливее на фоне ваших абстракций).
Архитектура (и код) должна отражать реальный мир. Реальную задачу и её прогнозируемые вариации. API отдаёт пять видов ошибок (не смогли разработчики в унификацию, потому в одном случае код есть, в другом нет, в третьем список ID хардкодом в тексте сообщения, в четвёртом списка нет аще, в пятом код ошибки в некоторых случаях является кодом удачной операции)? Делайте пять классов на каждый вид. Не, блин, унифицируйте, блин. Завтра они добавят шестую ошибку. Послезавтра заказчик попросит в третьем варианте ошибки дополнять своими данными. И всё, хана вашим красотам.

Чем чаще пробую этот подход на проектах, тем больше нравится. Да, при первом и втором взглядах возникает ощущение избыточности кода. Наивности. Излишней прямоты. Ахаха, вместо фабрики абстрактных ящиков копипаста десяти ящиков, отличающихся… ну… тут породой дерева, тут гвоздиком, тут наклеечкой, а здесь немножко круглый. А могла быть фабрика! Могла бы. И, возможно, будет. Только через год-другой эксплуатации в бою. А то и три. А лучше десять. И то при достаточном экономическом обосновании. Ведь, что смешно, нередко эти десять ящиков ещё и работают лучше фабрик.
Слава костылю! Костылику слава!

Книги: Восстание машин отменяется!

52d32d0cdedf69ef2b508c0a01561bf0
Дэвид Минделл.
Восстание машин отменяется! Мифы о роботизации.
Альпина нон-фикшн, 2017.
По правде говоря, не собирался включать эту книгу в блог. Она не про разработку программ. Потом подумал, перечитал пару глав ещё раз… как видите, передумал.
Автор инженер, учёный. Каждая глава (кроме последней) о том, с чем сталкиваются [полу]автономные системы и их создатели в реальной жизни. Глубоководные аппараты, дроны, самолёты, космические леталки и прочее. «Официальная» аннотация почти совсем не при делах, бОльшая часть текста — инженерные истории. Остальное Минделл пустил на утомляющие повторения одной и той же мысли.
Разработчику может оказаться интересным потому, что при замене «роботов» на «программы» находим real life cases:

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

Вот так читается уже более живенько.

Рекомендовать, впрочем, не буду. 300+ страниц, из которых после отжатия воды и повторов осталась бы едва половина, а профит от чтения всё так же слабоват.

Code coverage

Кратко про тему, на которой иногда копья ломаем. Code coverage — штука, которую в 3/4 мест агрессивно игнорируют, а в другой 1/4 агрессивно используют. Равнодушные встречаются не так уж часто.

Вся фигня в том, что это количественная метрика, на такие у разработчиков аллергия ещё со времён попыток оценить работу через LOC (кто больше строчек написал, тот и победил). Доведённый до абсолюта CC звучит вот так:
У тебя код тестами покрыт?
Да.
А почему покрытие 53%?
Потому, что остальной код — это обёртки с сотней тупых get/set.
И что? У нас покрытие должно быть 100%!
Иди нафиг, я увольняюсь.
Расскажу байку из жизни. Контекст: Python, сервис с некоторым покрытием тестами и некоторой документацией, живёт в production не первый год. Нахожу багу. Исправляю. Вроде исправилось, ништяк. Выкатываю. Проходит совсем немного времени. Сервис падает. Как оказалось, фикс баги открыл доступ к куску коду, который пару лет (емнип) не исполнялся вообще. И если бы хоть раз выполнился, сразу упал бы, что и произошло, там явная ошибка категории «что будет, если у null вызвать метод». Не хватило всего одного однострочного тупого теста, чтобы избежать пятисотящего прода.
Так вот. В нынешних условиях главная и важнейшая роль code coverage — показать вам код, который НЕ покрыт тестами и, быть может, вообще никогда не дёргался. Это полезно и для самопроверки (а не забыл ли я MyCoreServiceTest написать). Полезно для сторонней проверки (а есть ли в our.core.service вообще тесты). Полезно для оценки покрытия тестами ветвлений в том, что вы всё-таки решили потестировать (внезапно один if оказался за кадром).
Давайте ещё раз, пока не кинулись сразу же закидывать тухлыми тапками. На практике code coverage НЕ о том, СКОЛЬКО у вас тестов, фиг с ним. Он о том, есть ли вообще у вас тесты в нужных местах, а в ряде случаев и про качество этих тестов. Всё.

Но это… Честно говоря, мне гораздо спокойнее рефакторить код, который таки покрыт этими самыми тупыми и нелюбимыми 100%. Вот просто спокойнее. Не надо думать о том, правильно ли N лет назад Вася Иванов решил исключить что-либо из тестирования. Не надо прикидывать, написал ли Иван Петров в прошлом году тесты для того кода, что месяц аврально вклеивал. Если 100%, так хоть как, хоть одним вызовом, но весь код отработал.

О самостоятельности, часть I

Сначала про обычный фейл руководителя: делать всё самому. А если и не самому, то оценивать сделанное строго с позиции «как бы это сделал я». Начинающие (особенно из технарей) с этой грабли начинают, после чего либо стремительно умнеют, либо стремительно уходят из руководства (что тоже равно «умнеют»), либо становятся тем, что вроде бы должны изгонять — проблемой.
Если руководитель умнеет, он старается выделить самостоятельных бойцов и делегировать им задачи. Иначе говоря, не делает то, что могут (и/или для чего были наняты) другие. Не потому, что ленивый, но потому, что у него задач на тыщу человек, можно лопнуть лягушечкой на глобусе.
И вот тут начинается интересное. Какие качества должны быть у потенциально самостоятельного бойца (часть I)? Что такое самостоятельность и где её границы (часть II)? Как ею создать коллектив и как развалить (часть III)?

В этой части обойдусь интуитивным пониманием термина, т.к. требования к кандидатам от формализации не изменятся. Сами же требования подам через отрицание.
Во-первых, не надо давать тем, кто не хочет, пусть и может. Относится ко всему, конечно, работает и тут. Если делаешь что-то против воли, толку не будет, пусть вам и кажется, что вознаграждаете человека. Для него это наказание.
Следствие: практики «никто другой не согласился» и «только ты можешь спасти планету» плохи и далеки от оптимальности.
Во-вторых, не надо давать самостоятельность в области деятельности, в которой человек не разбирается достаточно для ожидаемого уровня решений. Это не значит, что ворота в стене Трампа только для возвысившихся senior’ов — junior вполне может получить собственную песочницу. Важна прямая зависимость между площадью песочницы и знаниями/умениями.
Следствие: хороший руководитель в ключевых областях знает и умеет больше подчинённых.
Следствие: при правильном процессе невежа никогда не получит право на решение.
В-третьих, не надо давать тем, кто не готов к негативной стороне ответственности. Отдельная и большая тема, но упомяну. Важна причиняемым вам ущербом в случае ошибок, которых вы могли объективно избежать. Поленился? Протупил? Мало знаешь? Проигнорировал инструкцию? Вплоть до увольнения с занесением в трудовую (что крайность, но нужна и вполне применяется). Не готов? Сиди кодером дальше, пиши по указке.
Следствие: очевидно, дети (и не всегда таковые по биовозрасту) к ответственности редко готовы. Массовая инфантилизация сдвигает взросление всё дальше со всем вытекающим, потому даже 30-летнего кандидата на песочницу требуется оценивать как 20-летнего лет сто назад (про Гайдара вспомнили, ага).
В-четвёртых, не давать тем, кто не готов принять всё, включая скучное или неприятное. Когда вы впервые получаете своё первое (пусть и съёмное) жильё, в «контракт» самостоятельности включается и уборка, и платежи, и воспитание соседей, и ежедневная готовка и прочее. В разработке та же фигня. Чем больше песочница, тем больше в ней работы с людьми, тестирования, сбора и обработки требований, документирования и остального, не шибко любимого разработчиками.
Следствие: кандидат на самостоятельную песочницу должен разбираться (и понимать нужду в) не только в разработке.

Что в итоге? Самостоятельность для тех, кто:

  1. Хочет её получить.
  2. Достаточно квалифицирован.
  3. Созрел для ответственности.
  4. Понимает и принимает выход за границы разработки.

Этого чеклиста безо всяких нюансов уже хватает для оценки и постановки. Да, в реальном мире такого бойца поди найди. Но чем дальше, тем увереннее думаю (а пару раз и точно знаю), что «я тебя слепила из того, что было» зачастую убыточнее по всем ресурсам, чем, скажем, бездеятельность в направлении за отсутствием человека нужных качеств.

Продолжение следует.