Пользователь
0,0
рейтинг
1 мая 2013 в 15:20

Разработка → Десятикратная разборчивость

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

Как же они этого добиваются?

Часто считают, что десятикратная производительность вытекает из десятикратных способностей или десятикратных знаний. Я так не думаю. Не хочу сказать, что способности или знания бесполезны. Но за много лет я заметил, что самое главное тут — десятикратная разборчивость. Фокус в том, чтобы постоянно уклоняться от паршивой работенки.

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

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

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

Вы знаете, что такое «арифметика с фиксированной точкой»? Я вам расскажу. Это когда вы работаете с целыми, но делаете вид, что это дроби, неявно предполагая, что целое x на самом деле представляет собой x/2^N для какого-то значения N.

Чтобы сложить два числа, вы просто вычисляете x+y. Для умножения вам нужно x*y>>N, потому что просто x*y — это будет x*y/2^2N, правильно? Еще необходимо быть осторожным, чтобы эта дрянь не переполнилась, как-то разбираться с разными N в одном выражении и так далее.

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

Вот часть моих тогдашних дел:
  • Был готов сляпанный на скорую руку шаблон C++ под названием InteliFixed<N> (он и сейчас существует, я не обманываю). Я вложил немало труда, чтобы сделать его, гм… сляпанным на медленную руку (это противоположность «скорой руки»?). Надо было, например, сделать operator+ коммутативным, когда он получает два числа с фиксированной точкой различных типов (каким будет тип результата?); заставить ужасный инлайновый код на ассемблере, выполняющий 64-битовые промежуточные умножения, инлайниться получше; и т. д., и т. п.
  • Мой босс велел мне держать две версии кода — одну с плавающий точкой, для благородных разработчиков алгоритмов, а другую с фиксированной, — для нас, чернорабочих, возящихся с рабочим кодом. Поэтому я синхронизировал эти версии вручную.
  • Босс также приказал придумать способ, как запускать часть кода с плавающей точкой, а часть — нет, чтобы найти ошибки потери точности. Поэтому я написал эвристический парсер С++, который автоматически сливал две версии в одну. Он брал одни функции из «плавающей» версии, а другие — из «фиксированной», выбирая их по специальному файлу типа заголовочного.
    Конечно, все это слитое дерьмо не запускалось и даже просто так не компилировалось, точно? Поэтому я сделал макросы, благодаря которым вы передавали в функцию не vector<float>&, а REFERENCE(vector<float>), и написал жуткий кусок кода, который поддерживал во время исполнения тот случай, когда передается vector<InteliFixed> (код внутри функции превращал его в vector<float>).
  • И кроме всего этого мета-программирования, было, конечно же, и само программирование. Например, решение системы уравнений 5x5, чтобы подобрать многочлены под зашумленные ряды данных, всё с фиксированной точкой. Я ухитрился заставить его работать, используя жуткие фокусы с нормализацией, а ассемблерный код использовал 96 битов точности. Мой код работал даже лучше, чем код с плавающей точкой одинарной точности без нормализации! Вот это да!


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

А вот что мне на самом деле нужно было сделать:

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


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

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

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

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

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

Если брать известные примеры — вы знаете Кена Томпсона по Си и Юниксу — но не по Плану 9, в самом-то деле, и не по языку Go. Пока что наоборот — Go привлек ваше внимание только потому, что это детище тех парней, которые сделали Юникс. Вы знаете Линуса Торвальдса, хотя Линукс — это клон Юникса, а Гит — клон Биткипера — собственно, потому что это клоны успешных продуктов, и преуспели они, потому что появились вовремя.

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

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

Один из этих умных людей спросил меня как-то о checkedthreads, которые я только что закончил: «Кто-нибудь это использует?» с той самой фирменной иронией. Я сказал, что не знаю; на «Hacker News» кто-то написал в комментариях, что, может, попробует.

Я знаю, что это замечательная штука; с ее помощью можно найти все ваши ошибки в многопоточных программах. Но это не замена pthreads, вам придется писать код, используя новые интерфейсы — хорошие, простые интерфейсы, но не те, которые вы уже применяете. Так что вполне вероятно, что заинтересует моя библиотека немногих; хотя Helgrind и thread sanitizer имеют кучу ложных срабатываний, они по крайней мере работают с теми интерфейсами, которые люди широко используют.

Зачем мне тогда вообще было этим заниматься? Потому что для написания первой версии понадобился всего один день (я еще не решил тогда завести параллельные вложенные циклы и всё такое), и я посчитал, что какой-то шанс будет, если я напишу о моей программе в блоге (что я делаю прямо сейчас). Если бы я написал несколько постов, в которых объяснил, как практически можно отследить ошибки в старомодным параллельном, разделяющем общую память, коде на С даже легче, чем на Rust, или Go, или Erlang, тогда, может быть, люди обратили бы внимание.

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

Видите? Не заниматься тем, что скорее всего провалится — вот где производительность.

Как выбрать то, над чем стоит работать? Есть множество вещей, которые следует учесть:

  • Есть ли уже доступная альтернатива? Насколько она плоха? Если терпимая, тогда не делайте ничего сами — хорошую вещь сложно улучшить, и еще сложнее всех убедить, что это улучшение стоит перехода на новую версию
  • Насколько важна эта штука? Без нее не будет ничего работать или это просто рюшечки, которые никто и не заметит?
  • Сколько труда потребуется пользователям, чтобы получить какие-то преимущества? Она уже работает с существующим кодом или данными? Людям придется учить что-то новое или они смогут работать, как привыкли?
  • Сколько людей должны узнать об этой штуке, чтобы она хотя бы распространилась? Пользователи будут запускать код, ничего о нем не зная, потому что он идет вместе со старым кодом, или им придется что-то устанавливать? (Получить какую-нибудь функцию автоматически и затем заняться ее практическим изучением, часто лучше, чем установить что-нибудь новое и тут же забыть. Подумайте, сколько людей в конце концов изучили какую-нибудь новую функцию в Экселе; и сколько используют программы резервного копирования в фоновом режиме).
  • Какое количество кода дает какую пользу? Оптимизация до потери пульса маленького ядра, сжимающего звуки в формат mpeg, выглядит полезнее, чем просмотр миллиона строк кода, чтобы добиться ускорения в 1,2 раза (хотя последний вариант может быть полезен сам по себе; но обычно он требует в десять раз больше программистов, а совсем не одного «десятикратного» программиста).
  • Сможет ли новая возможность сама себя защитить? Если пользователи сделают что-нибудь неправильно (или «неправильно»), станет ли она тихо бесполезна (вроде статического анализа кода, когда анализатор уже не понимает программу) или же остановит работу, пока ошибка не будет исправлена (как проверка на выход за границы массива)?


Вы можете легко продолжить этот список; основная его идея — какова вероятность, что я закончу эту штуку и ее потом будут действительно использовать? Эта же идея рекурсивно применима к каждой функции, подфункции и строчке кода: целое благодаря им будет полезным? И не потратить ли мне время на что-то другое, что принесет больше пользы?

Конечно, все еще сложнее; некоторые полезные вещи по разным причинам ценятся выше других. Вот где появляется Ричард Столман и требует, чтобы мы называли Линукс «GNU/Линуксом», потому что GNU написала большую часть пользовательских программ. И хотя я не собираюсь называть систему «Гну-Линукс», в его претензиях, к сожалению, есть своя правда, в том смысле, что да, к сожалению, некоторая тяжелая и важная работа не так заметна, как другая тяжелая и важная работа.

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

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

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

Автор: Иосиф Крейнин
Оригинал: www.yosefk.com/blog/10x-more-selective.html
Юрий Жиловец @gatoazul
карма
133,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (36)

  • +24
    Intelligence is the ability to avoid doing work, yet getting the work done, как говорил Торвальдс.
    • +24
      Большинство людей готово безмерно трудиться, лишь бы избавиться от необходимости немножко подумать. (Т. Эдисон)
      • +4
        Он, по-моему, так и делал, когда подбирал материал для спирали :)
        • +6
          И в итоге купил патент на лампочку у русского изобретателя)
          • 0
            У кого и на что?
            • +4
              ru.wikipedia.org/wiki/General_Electric

              «Компания основана в 1878 году изобретателем Томасом Эдисоном и первоначально называлась «Эдисон электрик лайт», после объединения в 1892 году с компанией «Томсон-Хьюстон электрик» получила своё современное название.
              1910 год — компания начинает серийное производство лампочек с вольфрамовой нитью (патент на использование в лампах накаливания нитей из тугоплавких металлов компания купила у русского изобретателя А. Н. Лодыгина в 1906 году)».
              • +1
                Александр Лодыгин, родившийся 18 октября 1847 года, занимался строительством летательного аппарата, для освещения кабины пилота в котором нужна была лампа. Лодыгин догадался выкачать из стеклянной колбы воздух и поместить внутрь угольный стержень, который под действием тока накалялся.
                Так «побочное» изобретение — лампа накаливания — сделало Лодыгина всемирно известным. Вдохновленный своим успехом, в 1872 году Лодыгин вместе с другом Василием Дидрихсоном основывает компанию «Русское товарищество электрического освещения Лодыгин и К°», которая в мае 1873 года залила электрическим светом восьми фонарей Одесскую улицу Санкт-Петербурга.
                В том же 1873 году Лодыгин получил патент на свое изобретение в Великобритании, Франции, Италии, Швеции и других странах. Но Лодыгину так и не удалось заработать на изобретенных им лампах накаливания: в 1906 году после многолетних тяжб с Томасом Эдисоном, который изобрел лампу одновременно с россиянином, Лодыгин продал патент компании General Electric, возвращаясь после 23 лет жизни за границей в Россию.
                На родине он преподавал в Электротехническом институте и работал в строительном управлении Санкт-Петербургской железной дороги. После Февральской революции 1917 года Лодыгин уехал в США, где так и не смог найти себе достойное место и умер в своей бруклинской квартире в 1923 году.

                Forbes.ru: 18 октября. Этот день в истории бизнеса
        • 0
          Этот афоризм не о том что не надо трудиться, а о том что надо думать чаще.
  • НЛО прилетело и опубликовало эту надпись здесь
    • –1
      Советский союз в эпоху застоя. Плохой пример.
  • 0
    Оригинал взял из блога Proper Fixation за авторством израильского программиста Yossef Kreinin.
    Очень интересный блог, рекомендую всем интересующимся С++ и программированием вообще.
    • 0
      Да, это тот самый Крейнин, который написал C++ FQA — подробный разбор всех недостатков языка C++
      • 0
        Собственно, через FQA я в свое время и нашел его блог :)
  • +1
    К сожалению не всегда удаеться убедить всех что идея полное Г. Еще большое сожаление в том что даже после того как все увидили что она таки Г, люди не делают выводов на будущее.

    Программирование это последнее что должен делать программист)
  • +4
    Я понимаю, что идеи «мой начальник неумен» и «надо пореже испытывать неудачу» звучат подкупающе. Однако, в конечном счете, минимизация рисков не является способом получить наибольшую отдачу ни в какой деятельности, в том числе и в разработке. Неудачи необходимы для успеха, просто нужны дешевые неудачи. И контролируемые. Ваша неудача была дешевой?

    Это еще более неблагодарное занятие, чем писать библиотеку «на выброс» — компенсировать недостатки в орг.структуре личными усилиями рядового разработчика. Кто-то должен был оценить расходы на такую конструкцию до того, как вы вляпались в поддержку двух ветвей кода — с FP и без, или хотя бы в момент, когда эта конструкция начала создавать проблему. Либо кто-то этого не сделал (и тогда проблема совсем не в ПО), либо кто-то это сделал и решил, что написание boilerplate-кода вашими силами — наиболее дешевый путь (и низкорисковый, кстати). Вы, как человеческий ресурс, для этих людей значите не более, чем для вас значит загрузка конвейера GPU. Похоже, что Вас такой подход не устраивает — и это, пожалуй, проблема.

    Статья хорошая. Но содержательная часть этой статьи — об отношениях на фирме, а не о программировании. Ну и небольшая «история неудачи» в добавок.
    • +1
      Человеческий ресурс, это, надо сказать, очень обидное выражение. При таком подходе и команда будет думать про три гвоздя (из комментария выше), а не дело делать. Тема организации сплоченной и продуктивной команды — это тема отдельного длинного разговора. Де Марко даже книжку написал о том почему к подчиненным надо относиться как к людям, а не как человеческому ресурсу.
  • +1
    Кстати говоря, доработка компилятора, чтобы он выполнял операции с плавающей точкой программным путем, обошлась бы в десятки раз дешевле, чем все те ужасы, которые вы написали. Далее система тестов просто выполняется на обоих режимах компиляции (симуляция float и честный fixed) и все случаи, когда для перехода от FP к фиксед требуются специальные полиномы и нетривиальная математика, возвращаются упомянутым «белым алгоритмописателям» обратно. Так что «путь умника», — я хочу сказать, техническое решение, не затрагивающее оргвопросов, — из той ситуации, наверное, тоже был.
  • +1
    :) Не всегда такой подход работает. Бывает что ты сам себе начальник, работаешь над исследованием чего-то нового и пока не попробуешь — не поймешь подходит один метод или другой. И какой лучше и какой быстрее. А уж начальник тем более может быть не в теме, когда у него 10 подчиненных, все работают по плану над своими достаточно общими задачами. Правильность и путь решения на плечах подопечных и пусть крутятся.

    А как хотелось бы в 10 раз больше делать. :)
  • 0
    На самом деле, производительные люди, как отмечают в отзывах разные люди, имеют ещё некоторые другие свойства. Например, способность или привычка быть постоянно погруженным в задачу или круг задач. Тогда, какой бы трудной для понимания других ни была бы тема, они — в теме. Они могут написать дополнение кода с учётом ряда особенностей среды, о которых другие уже успели забыть.

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

    Третье, есть вообще природная способность быстрее мыслить и связанный с ним показатель IQ. Но без первого (умения надолго держать тему) третье тоже мало полезно.

    Ну а разборчивость и собственное мнение о ценности проекта — да, это тоже важный фактор. Хорошо, что Вы его подробно разобрали в статье.
    • –1
      Чёрт, опять не указали впереди, что это перевод.
      • 0
        В тегах указал. А где еще надо?
        • 0
          При создании можно выбрать «Хочу опубликовать пост/перевод/событие/вопрос».
          А сам перевод отличный, приятно что английские обороты грамотно переведены, а то в последнее время с этим туго у сообщества.
          • 0
            Спасибо. Не зря я Нору Галь в детстве читал :-)
          • 0
            При редактировании нет такого выбора. Да и при создании я его не видел
            • +1


              Можно написать в тех.поддержку — перенесут в нужный тип.
  • НЛО прилетело и опубликовало эту надпись здесь
  • +2
    Вы знаете Линуса Торвальдса, хотя Линукс — это клон Юникса, а Гит — клон Биткипера — собственно, потому что это клоны успешных продуктов, которые имели прекрасные шансы преуспеть, если бы появились вовремя.

    Долго втыкал в этот кривой перевод криво построенного оригинального изречения:
    You remember Linus Torvalds even though Linux is a Unix clone and git is a BitKeeper clone — in fact because they're clones of successful products which therefore had great chances to succeed due to good timing.

    Последняя часть, конечно, должна звучать как ", поскольку появились вовремя", а все придаточное предложение со слова «которые» относится к слову «клоны», а не «продуктов», как можно прочитать.
    • 0
      Учел ваше замечание.
  • +1
    статья — прекрасное руководство к действию, спасибо за перевод!
    однако, когда говорят о разнице в производительности между худшими и лучшими в профессии, исходят все-таки из других предпосылок. Автор все же берет в расчет только тех, кто одинаково продуктивно может писать один и тот же код, но в общем случае это не верно.
    На самом деле разница просто огромна и она не только в возможности или желании не писать «унитазный» код — всегда есть рутинные задачи, выполнять которые надо и никуда от них не денешься.
    Простой пример из жизни, первое что приходит в голову: сотня картинок для проекта, надо изменить размер, или сотня текстовых файлов от заказчика — надо заметить фамилию директора и дальше уже чего-то с ними делать. Ваш джуниор кинется открывать все в редакторе и работать с каждым файлом вручную, другой отправит все назад дизайнеру или заказчику. Кто-то загонит все тексты в базу данных и поменяет все что нужно через sql-запрос. Еще один напишет программу для обработки всего этого добра. А лучший сделает все одной командой в консоли и даже никто не заметит сколько работы мог сделать кто-нибудь менее опытный. Вот и вся производительность — больше, чем в 10 раз на самом деле. А зарплата все-же в 10 раз не отличается :).
  • –2
    Плохая идея — говорить начальству, какую идею надо реализовывать, а какую нет. Начальник должен задачи ставить, а исполнитель (программист) — выполнять. Это основополагающий принцип предприятия, и его нарушать нельзя. Если не устраивает компетенция начальства — обычно меняют работу.
    • +3
      зависит от стиля управления, принятого в конторе. Часто можно попробовать переубедить. Вообще авторитарный стиль руководства в IT не часто встречается — здесь он просто не эффективен: тут не работают «от забора и до обеда».
      То же самое, кстати, с заказчиком: можно пробовать показать, подтолкнуть к мысли о том, что идея плохая.
      Хотя бывает, что делаешь, пишешь и проектируешь наперед зная, что все придется в конце-концов выбросить и сделать сначала и по-другому. За свои деньги заказчик может и даже вправе потребовать реализации собственных нелепых идей. Он тоже учится на своих ошибках и, кстати, за свои же деньги их и исправляет. Зато потом становится сговорчивей, больше прислушивается. А отправив подальше с первой нелепой идеей можно его просто потерять.
    • 0
      вот, кстати, интересно в контексте сказанного вами.
      В книге-сборнике интервью с известными программистами автор каждому задает вопрос о том, является программирование искусством или ремеслом ( Питер Сейбел, «Кодеры за работой. Размышления о ремесле программиста»).
      Когда программирование считать искусством, такой подход (в смысле «Начальник должен задачи ставить, а исполнитель (программист) — выполнять») вообще скатывается чуть ли не в область неприемлемого: художнику нельзя приказать создать шедевр :).
      • 0
        за что минусуете? мы же не о науке или творчестве. мы о промышленном программировании, о бизнесе. об эффективности, об иерархии. Этим начальником в мое случае, например, был инженер колоссального уровня, бывший разработчик JVM из SUN. Это тот случай, когда художник говорит своему подмастерью, что нужно делать.
  • 0
    Я открыл библию от Макконнелла и вот что он пишет по поводу производительности в 28 главе:
    Заголовок

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

    Если бы заранее было известно, какой код отправится в мусорку, а какой нет — тут бы и сказочке конец.
    Я сам был в ситуации, когда разработчик подвергались сомнению мои задачи из категории «data science» со словами «зачем писать бесполезный код?» А я и сейчас на 100% уверен, что эти задачи оказались полезны.

    PS. А вот доходчиво обосновать тупиковость задачи — это полезное качество. Только не надо жаловаться про «тупых начальников». Видал я таких «умных» программистов.

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