Не так давно у нас на работе (Виктор, Игорь, Олег привет вам) состоялась дискуссия на тему: должны ли программисты знать как работает железо на котором выполняются их программы? И я еще раз убедился в том, что большинство программистов придерживаются мнения: “железо само по себе, а я сам по себе”. Точка зрения вполне ожидаемая и ничего принципиально неправильного в ней нет, но я хотел бы “копнуть глубже”.

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

Мы с вами живем в эпоху высокоуровневых языков. Программисты большинства отраслей с успехом забыли про unmanaged языки, не говоря уже об ассемблерных вставках. В этом есть свои преимущества. Во-первых, это позволило нам программистам быть более эффективными. При равных доступных ресурсах теперь мы можем решать более сложные задачи. Во-вторых, не требуя от программистов “погружения в железо”, мы позволяем им специализироваться в своей области, а также увеличить их количество за счет более короткой learning curve. Последнее впрочем имеет и свои негативные последствия, но я не буду сейчас акцентировать на них внимание.

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

Почему стоит изучать? Link to heading

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

Возьмите хотя бы возросший интерес, к actor’ам. В общем и целом actor’ы представляют собой модель кооперативной многозадачности. Если вы хорошо помните историю, то кооперативная многозадачность в широких масштабах последний раз “упоминалась” в начале 90-х. У нее есть один существующий минус — она не работает на маленьком количестве исполнителей. Когда у вас один процессор легко может случится так, что какая-либо задача оккупирует его и другие задачи не смогут выполнятся. Тем не менее, у кооперативной многозадачности есть плюсы которые заставили нас опять обратить свой взор на эту модель…

Дело в том, что основная проблема с которой сталкиваются современные модели распараллеливания (которые преимущественно основаны на потоках) — это context switch. Доступ к памяти не является random’ным, чтобы ни говорили разработчики железа. Latency доступа к памяти на современных платформах составляет сотни тактов процессора. За это время процессор может сделать много работы. Эту проблему сейчас адресуют довольно простым путем — кеш, размер которого уже достигает 2Mb и больше на ядро. Проблемы кеша вам уже должны быть известны, — они одни и те же, неважно говорим ли мы о CPU cache или о memcached. Как только вы получаете промах кеша, вы платите performance penalty. Именно cache miss’ы являются источником деградации производительности в случае высокого context switching’а1. Об этом говорило очень много умных дядек2 3 4.

Решение довольно очевидно. Не переключатся между задачами лишний раз, только после завершения всей задачи целиком. Здравствуй кооперативная многозадачность. Не верите мне, поверьте сотрудникам Яндекса. Не зря в Windows существуют fiber’ы.

Справедливости ради, следует заметить, что скорость не единственный (и лично для меня не главный) плюс модели actor’ов. Эта модель гораздо проще в понимании и тестировании чем традиционные thread-based приложения. Но интерес к этой модели начал появляться как раз в тот момент, когда традиционные способы увеличения производительности исчерпали себя и мы начали искать новые методы обеспечения роста. А это означает одну простую вещь — программные абстракции используемые нами меняются в том числе и под “давлением аппаратных факторов”.

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

Никто не просит вас уметь программировать на ассемблере и разбираться в opcode’ах микропроцессора. Но осознание того как работает процессор и какие bottleneck’и есть у существующих аппаратных платформ может дать вам очень хороший теоретический background для решения многих задач и ответа на многие вопросы.

Root of all evil Link to heading

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

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

Tradeoffs Link to heading

С другой стороны надо трезво оценивать свои возможности. Существует масса знаний/умений которые для программиста важнее чем знание железа. Вот, на мой взгляд, всего лишь некоторые из них (перечислено в произвольном порядке):

  • ОО анализ и проектирование (шаблоны/SOLID принципы);
  • анализ и построение алгоритмов;
  • классические структуры данных;
  • диагностика типичных проблемных ситуаций;
  • тестирование и поддержка legacy систем;
  • умение писать корректный многопоточный код, а также находить ошибки в многопоточном коде (светлое будущее с Clojure, Erlang, Scala, whatever еще не наступило);
  • функциональная декомпозиция;
  • автоматизация процесса разработки;
  • продолжите список…

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

В итоге Link to heading

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