вторник, 3 декабря 2019 г.

Главный навык программиста

Я заметил, что опытных специалистов из разных областей объединяет как минимум одна вещь: осторожность в суждениях.

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

Нужно ли писать тесты? Важно ли качество кода? Какая лучшая степень прожарки мяса? С чем лучше всего сочетается белое вино? Нужно ли делать жим лежа со становой или турника будет достаточно?

Когда я рассматриваю источники информации по некоторой теме я ищу в авторе глубину и осторожность. Желание дать фундаментальные принципы, а не конкретные ответы на сложные вопросы. В этом плане старина Боб Мартин меня давно разочаровал. Когда-то он для меня был автором лучших книг и статей, но его категоричность, негибкость в суждениях и неумение смотреть на проблемы шире перевели его в категорию "анти"-авторов. В категорию людей, чье мнение скорее опасно для индустрии, чем полезно.

Моя нелюбовь к старине Бобу началась с его книги "Принципы, паттерны и методики гибкой разработки на языке C#" (вот большая критическая статья на эту тему), но дядюшка Боб периодически выдает и вот, после очередного его высказывания, мне захотелось подумать над поднятой им темой более подробно.

Итак, вот его твит:

When you read code, the race, religion, politics, gender, and orientation of the author are irrelevant and invisible. The only thing you can tell about the author is their ability to write well organized code. Nothing else matters.

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

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

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

Поскольку тема эта интересна, то давайте немного пофилософствуем по этому поводу.

"Что самое главное в жизни?", может спросить Боб. "Семья, конечно", ответит один. "А как же здоровье? Если нет здоровья, то радости от семьи будет не много.", возразит второй. "А как же призвание, а деньги? На одной семье, пусть и здоровой, далеко не уедешь! Нужно ж еще и кушать вкусно, да и делом интересным заниматься!", скажет третий. "Ну а помощь другим? Это ж тоже важно! А друзья? А карьера? А красивое тело?".

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

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

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

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

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

Хороший специалист может увидеть проблему (в себе, в коде, архитектуре или подходах), подумать об альтернативах и изучить наиболее подходящее решение.

Мне может лишь в страшном сне привидеться, что вся команда состоит из однотипных людей. Людей с одним, даже самым лучшим единственным навыком. Хорошая команда - это разнообразие в лучшем понимании этого слова. Разнообразие характеров, навыков, подходов. Их должны объединять схожие принципы и ценности, но попытка грести всех под одну гребенку вызывает у меня лишь недоумение.

Мне тоже хочется найти простое решение таких сложных проблем, как разработка ПО. "Развивай навык Х и ты будешь отличным специалистом!". Но мир и разработка ПО достаточно сложны и многогранны, чтобы был один главный навык, который бы в одиночку смог бы решить все наши проблемы.

вторник, 12 марта 2019 г.

О пользе ведения блога

Пришло время ответить на вторую часть вопроса, который я поднял в предыдущем посте «Я выгорел?: Насколько полезно вести блог: с профессиональной, финансовой и других точек зрения?

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

Я знаю людей, которым блог, выступления на конференциях или участие в опен-сорс проектах помогли в поиске новой работы или в продвижении на текущей. Если вы следите за .NET сообществом, то, может быть, заметили, что довольно многие MVP (Most Valuable Professional) оказываются в итоге сотрудниками Майкрософта. Мой путь, собственно, очередной тому пример.

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

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

Блоггинг, опен-сорс и публичные выступления – это не единственный способ получения хорошей работы. Есть случаи, когда все это сработало, но ведь на каждого MVP, который нашел хорошую работу, есть десятки не-MVP, которые нашли работу не хуже.

Так стоит ли вести блог для карьерных целей? Я бы сказал, нет.

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

Позитивная сторона блоггинга

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

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

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

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

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

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

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

Негативная сторона блоггинга

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

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

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

Остерегайтесь своих собственных коммитментов. Я ставил себе цель: публиковать посты раз в 2 недели. И вокруг этого строил все свое самообразование. Но такой темп стимулирует более глубокое изучение уже известных тем и не дает сосредоточиться на новом.

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

Так стоит ли мне вести блог?

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

вторник, 19 февраля 2019 г.

Я выгорел?

Или почему я намного меньше пишу в блогах.

Мне недавно задали два вопроса: 1) не выгорел ли я, поскольку стал совсем мало блогать, и 2) стоит ли вести блог вообще и какие в этом преимущества?

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

Где-то год назад я начал слушать в дороге разные подкасты и самым моим любимым был (и остается) Hello Internet. В одном из первых выпусков, CGPGrey привел довольно любопытную аналогию. Человек – это такой себе аккумулятор, к которому параллельно через резисторы подключены несколько лампочек: семья, работа, спортивная форма, хобби, друзья и т.д. И человек может менять сопротивление определенного резюка и, таким образом, тратить больше жизненной энергии на одну лампочку, уменьшая свечение всех остальных.

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

Хоть аналогия и не идеальна она прекрасно иллюстрирует главную сложность в жизни: поиск баланса между разными аспектами жизни и правильное распределенные нашего времени и энергии.

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

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

Когда у нас появляется наша собственная семья распределение энергии меняется.

Во-первых, больше энергии уходит на семью хотим мы этого или нет, а во-вторых, происходит некоторое профессиональное насыщение и мы попадаем под закон убывающей доходности (diminishing returns) в вопросах саморазвития.

Когда мы начинаем чем-то заниматься, то мы удваиваем наши знания каждые несколько месяцев. Поработав же 10 или 20 лет происходит профессиональное насыщение. Одни языки сменяют другие, молодые активисты новых технологий с пеной у рта доказывают, что они отыскали серебряную пулю. А на тебя лишь накатывает смутное подозрение, что ты такое уже где-то видел.

Это не означает, что ты перестаешь развиваться, просто у тебя немного стихает мотивация трещать об этом на каждом углу.

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

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

Рассмотрим донорство органов в Германии и Дании. Эти страны достаточно похожи с точки зрения уровня жизни и культуры, но в Германии донорами органов становятся на порядок меньше людей, чем в Дании. Вопрос: почему? Дело в том, что в Дании донорство осуществляется по принципу opt-out, а в Германии – по принципу opt-in. Т.е. в Дании нужно отказаться от донорства, а в Германии – наоборот, с ним нужно согласиться.

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

Теперь давайте возьмем такое когнитивное искажение как «якорение» (anchoring). Вот небольшой пример. Давайте проведем опрос о том, в каком возрасте умер, ну, не знаю, Ницше. И для первой группы вопрос будет таким: «В каком возрасте умер Ницше, при учете, что он пережил свое тридцатилетие?», а второй – «В каком возрасте умер Ницше, при учете, что он не дожил до 100 лет?». Мы увидим, что ответы будут сильно отличаться. В первом случае средний возраст будет существенно ниже, чем во втором случае.

Я на личном опыте столкнулся с проблемой якорения. Мы были с семьей в ресторане и семья за соседним столиком, услышав, что мы говорим по-русски, рассказала о возможной скидке в 10% с чека, если мы зачекинимся на фейсбуке. Мы их поблагодарили, но «трюком» не воспользовались. Но в момент выписывания чаевых, вместо 20% я неосознанно выписал 10%.

Якорение часто проявляется во время планирования задач. Если один из разработчиков первым сказал, что фичу можно сделать за 2 дня, то все будут отталкиваться от этой «оценки» и будут стараться лишь ее скорректировать. Именно с этим борется planning poker, когда каждый член проекта записывает свою оценку на листочке и лишь когда все готовы, «карты вскрываются».

Напоследок, мы можем взять экономическое понятие – sunk cost fallacy. Идея этого явления в том, что чем больше мы вкладываем сил и средств во что-то, тем тяжелее нам быть по этому поводу объективным. Это явление проявляется на уровне человека, который спорит, что старый язык программирования или технология все еще лучшее средство для решения всех проблем. На уровне команды, которая уперлась рогом в текущие архитектурные ограничения и не в состоянии сделать шаг назад и посмотреть на проблему с другой точки зрения. Или на уровне организации, которая не может уйти от старой бизнес-модели, которая уже не применима.

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

Мне очень понравилась идея изучения чего-то нового кусками по 20 часов (The first 20 hours – how to learn anything): ты берешь какую-то тему, находишь вменяемые источники по ней и изучаешь ее 20 часов, применяя всякие там deliberate practice и т.п.

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

Ну а теперь мы можем вернуться к вопросу выгорания. Так что же такое?

Как по мне, выгорание – это уменьшение запасов нашей батарейки с жизненной энергией. Выгорание – это когда ты тратишь меньше времени на изучение языков программирования, *и* проводишь меньше времени с семьей и друзьями, *и* не занимаешься своим здоровьем, *и* ничем другим не интересуешься.

Выгорание – это порочный круг уменьшения жизненной энергии. Видимое же уменьшение яркости одной «лампочки» не является признаком выгорания. Это вполне может говорить о перераспределении энергии и что сейчас она направлена в другие русла.

вторник, 12 февраля 2019 г.

Не очень занимательный C#

Я как-то не особо лезу со своими комментариями к другим людям, а уж тем более к постам на хабре. Но вчера вот листал RSS-ленту и увидел интригующее название поста – "Занимательный C#. Пять примеров для кофе-брейка".

Итить, думаю, дай-ка зайду, посмотрю, что да как.

И вот первая загадка – что выдаст следующий код:

using System;

public struct SDummy : IDisposable
{
    private bool _dispose;
    public void Dispose() => _dispose = true;

    public bool GetDispose() => _dispose;

    private static void Main(string[] args)
    {
        var d = new SDummy();
        using (d)
        {
            Console.WriteLine(d.GetDispose());
        }
        Console.WriteLine(d.GetDispose());
    }
}

 

Ну, думаю, ок. Странно начинать с изменяемых структур и особенностей блока using, ну, ничего.

Открыл объяснение, а в нем говорится, что причина странного поведения в упаковке, дескать. Компилятор зовет Dispose метод через каст: ((IDisposable)myStruct).Dispose(), ну а каст структуры к интерфейсу, как известно, приводит к упаковке.

Вот те на, подумалось мне. Мало того, что черти дают достаточно невменяемые и не практичные загадки, так еще и ответы у них неверные.

Я добавил комментарий, после чего началось небольшое обсуждение. Дескать, сам Эрик "уже давно в фейсбуке работает" Липперт писал, что упаковка в блоке using быть должна и компилятор нарушает спеку и все такое... (хотя сегодня это и не так).

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

Что в этом плохого?

Структуры в C# имеют две особенности – они являются "значениями", и могут располагаться напрямую в памяти контейнера (в стеке, регистрах и напрямую в других объектах).

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

Второе же (место жизни структуры) может привести к упаковке т.е. к созданию копии структуры в куче.

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

Вот, например, семантика значения и защитные копии стали гораздо более распространенной бедой с выходом C# 7x с их модификаторами ‘in’ и возвратом по неизменяемой ссылке (readonly refs) (вот, например, много буков по этому поводу - The ‘in’-modifier and the readonly structs in C#).

А самая большая беда проявляется с изменяемыми структурами, когда скрытая копия «прячет» изменения состояния, поскольку произойти они могут на временной копии. Не столь серьезное последствие заключается в некоторой потери производительности за счет создания копии, что решается путем использования readonly структур.

Упаковка же происходит совсем в других местах, при кастах к объектам/интерфейсам и в более экзотических случаях, типа при вызове методов из System.Object или System.ValueType (когда, например, Equals/GetHashCode не переопределены). А проявляется она путем увеличения давления на сборку мусора, что может аукнуться за счет тормозов сборщика мусора.

Так это я все к чему: учить других – это хорошо. Это просто здорово! Но касаясь всяких закоулков языка и рантайма, хорошо бы понимать, что, да как на самом деле происходит под капотом, да и желательно разбираться, почему происходит все именно так, а не иначе.