вторник, 24 сентября 2013 г.

Культ карго в программировании

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

Первые примеры такого подражания легко увидеть у детей или подростков. Вспомните, как мы встречались мальчишками осенью и кто-то начинал хвастаться своими бицепсами. Сразу же вокруг него соберется группа однокашников, страстно желающих узнать рецепт успеха. При этом самое смешное, наблюдать, как избирательно работает наш мозг, который воспринимает лишь то, что мы хотим услышать. Так во фразе: "я тренировался на турнике каждый день по 40 минут в течении трех месяцев", мы услышим лишь «тренировался на турнике» и будем озадачены отсутствием результата через неделю, подтянувшись за все это время 4 раза. "А, турник – это не для меня! У меня мышцы спины слабые" ("руки слишком длинные", "турник во дворе кривой", "нет подходящих перчаток" и т.п.), услышим мы через неделю, когда энтузиазм ребят начнет спадать.

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

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

Давайте рассмотрим следующий пример. Предположим, мы хотим начать использовать новые асинхронные возможности языка C# (async/await) или хотим поделиться своим успешным опытом использования этой штуки в своем проекте. С одной стороны, мы можем начать расписывать все радости этой async-ов и await-ов и убедить команду в том, что это именно та возможность, отсутствие которой не позволяло вовремя сдать ваши проекты.

Но можно подойти с другой стороны.

Когда я рассказываю об асинхронном программировании, я прежде всего говорю о преимуществах и недостатках синхронной и асинхронной модели программирования, а потом рассказываю об эволюции паттернов асинхронного программирования на платформе .NET: начиная от APM, через EAP, к TAP и потом уже к async/await. При этом я стараюсь убедить слушателей (или своих коллег), что async/await – это лишь вершина айсберга и вам понадобиться понимание всех аспектов, на которых эти возможности построены (такие как Synchronization Context, TPL и многие.).

Попытка разобраться с подобным инструментом с наскока приведет к тому, что появятся различные фобии и комплексы: "async/await – это плохо, поскольку из-за этого страдает производительность", "async/await не стоит использовать, поскольку это усложняет обработку ошибок" и т.п. Эти замечания вполне обоснованы, но говорят они не столько о проблемах async-ов, сколько о недопонимании принципов этой возможности и истории ее возникновения.

Подход "а давайте быстренько внедрим вот эту новую штуку" приводит к возникновению известного "бага" в поведении, известного нынче под именем культа карго, автором которого является Ричард Фейнман (который описывал его в контексте науки, но он применим и к другим областям, таким как разработка ПО):

"У народностей, населяющих регионы южных морей, бытует «культ карго». В войну к ним прилетали самолеты с массой полезных вещей. Теперь люди хотят, чтобы так было опять. Поэтому они устраивают некое подобие взлетно-посадочной полосы, вдоль нее разжигают костры, строят будку, в которой сидит человек, изображающий диспетчера (с деревяшками вместо наушников и бамбуковыми палочками-антеннами), и ждут приземления самолета. Они все делают как нужно. По форме все правильно. Все выглядит так, как было раньше. Вот только самолеты не приземляются. Я называю такие вещи наукой «культа карго» (наукой самолетопоклонников): соблюдаются все внешние признаки и рецепты научного исследования, но нет чего-то очень важного, потому что самолеты так и не приземляются."

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

clip_image001

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

Так, можно встретить целые команды, в которых нельзя использовать цикл foreach в языке C#, только потому, что некоторый авторитетный товарищ из этой команды 10 лет назад прочитал вумную статью, в которой говорилось, что пустой цикл foreach аж-но в 3 раза медленнее пустого цикла for. Или можно встретить команды, в которых для каждого класса требуется написать интерфейс, и обязательно использовать DI-контейнер якобы для улучшения дизайна. При этом вся команда плюется, потому что разобраться в коде невозможно, написание юнит-теста занимает полдня, каждое изменение ломает два десятка этих самых тестов, а добавление даже самой маленькой возможности требует невероятных усилий. Часть команды чувствует, что здесь что-то не так, но боится выглядеть белой вороной на фоне остальных. Многие понимают, что идет подмена понятий и IoC отождествляется с хорошим дизайном, хотя на самом деле контейнер лишь инструмент, а не самоцель.

Как и с турником, чтобы добиться успеха в разработке ПО, нам нужно не просто слепо перенимать чьи-то подходы, а критически их анализировать. Это не значит, что не нужно использовать чужой опыт и признавать авторитеты, это лишь значит, что время от времени нужно пересматривать свои подходы и смотреть, не изменилось ли ваше к ним отношение за прошедшее время.

З.Ы. Многие, скорее всего, слышали такое высказывание, что если вы смотрите на свой код годичной давности, и не считаете его го#%$-кодом, то это значит, что вы остановились в своем развитии. Я бы не был столь категоричным, поскольку кодирование пусть и важный, но не единственный аспект разработки ПО. Поэтому я бы несколько изменил формулировку таким образом: если через год вы не изменили своего мнения хотя бы в одном из аспектов разработки ПО (кодирование, дизайн, архитектура, работа с пользователями, методологии разработки ПО и др), значит вы остановились в своем развитии.

2 комментария:

  1. Спасибо за отрезвляющую статью. Как вы правильно заметили по хорошему в любых подходах надо придерживаться рационального зерна, то бишь здравого смысла или чувства меры. Было бы интересно изучить проблематику культа карго в психологическом или нейропсихологическом аспекте. Одним из ограничением мыслительного процесса является достижения цели (умозаключение, вывода) с наивысшей эффективностью, то есть с минимальным расходом энергии. Из этого ограничения следует что держать в уме "здравый смысл" очень энергозатратное занятие с точки зрения мозга, поэтому стремление к простым решением - субъективное ассоциативное связывание не связанных (объективно) событий, явлений или сущностей наиболее простой и дешевый способ для умозаключений. То есть "культ карго" в принципе не искореним, так как является следствием вышеупомянутого базового ограничения (или) свойства мозга. Частичным решением подобных и других искусственных субъектных проблем (например борьба со сложностью) является увеличение энергоинформационных способностей мозга. Количество сущностей, а как следствие и абстракций неуклонно растет, а способности нашего мозга эволюционируют не так быстро. Отсюда и изобретаем ООПы, теории сложности, абстракции и тд.

    ОтветитьУдалить
  2. Сергей, спасибо и за эту статью, и за цикл статей про DIP.
    Не нужно переживать за собственное "выгорание", ибо то, что вами написано -- не сиюминутно, и будет приносить пользу долго. Если уже всё охвачено -- может, замахнуться на книгу? Как Джоэль Спольски сделал в своё время?
    По ООП сколько книг не пиши, а всё равно мало.

    Хорошо про обезьян, я их тоже иногда привожу в пример.
    И отдельное спасибо за Фейнмана! Его "Вы, конечно, шутите, мистер Фейнман!" стоит прочитать каждому (а ведь казалось бы, при чём тут ООП...)

    ОтветитьУдалить