Pull to refresh

Синий. Нет! Жёлтый! — или — Дают ли новые языки программирования прирост скорости разработки

Reading time 8 min
Views 21K
Original author: Robert C. Martin (Uncle Bob)
Какой язык использовали для написания самых первых программ для самых первых компьютеров с хранимой программой?

Двоичный машинный язык, конечно.

Почему?

Очевидно потому, что не было символьного ассемблера. Первые программы необходимо было писать двоичным кодом.

Насколько легче писать программы на ассемблере, чем на двоичном машинном языке?

Намного легче.

Можно цифру? Во сколько раз легче?

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

Экономия объёмов работы огромная.

Насколько? Можно цифру?

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

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

Хорошо, достаточно. Таким образом, использование символьного ассемблера снижает объём работ в два раза?

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

Пожалуйста, поясните.

Хорошо, предположим надо изменить одну строку в программе на символьном ассемблере. Это займёт у меня 20 минут на старом PDP-8 с перфолентой. Но при ручном ассемблировании я должен затем пересчитать все адреса и реассемблировать все машинные команды вручную. В зависимости от размера исходной програмы уйдут часы. Последующий ручной ввод потребует не меньше времени.

Я мог бы сэкономить время, сегментируя программу на модули, загружаемые на фиксированные адреса, имеющие свободные интервалы между ними. Можно сэкономить ещё немного времени, написав небольшую программку, которая поможет загружать большую программу. Однако такая «рутинная» нагрузка будет, всё же, очень, очень высокой.

Хорошо. Но, всё же, можно цифру? В среднем, насколько использование ассемблера облегчает работу по сравнению с написанием программы в двоичном коде?

Ладно. Полагаю, можно сказать, примерно в 10 раз.

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

Да, это, вероятно, близко к правде.

Если символьный ассемблер уменьшил трудоёмкость примерно в 10 раз, то насколько это сделал Фортран?

Очень прилично. Если мы говорим о 50-х, то Фортран тогда был простым. Иначе говоря, он был несколько больше, чем символьный ассемблер для символьной компоновки, — не уверен, понимаете ли вы, что я имею в виду.

Значит ли это, что он уменьшил трудоёмкость ещё в десять раз?

Что вы, конечно, нет! «Рутинная» нагрузка у символьного ассемблера не была такой высокой. Я бы сказал, что Фортран уменьшил трудоёмкость сравнительно немного. Возможно, примерно на 30%.

Иначе говоря, 10 программистов на Фортране могут заменить 13 программистов на ассемблере?

Если вы желаете рассматривать процесс с такой позиции, то да, похоже на то.

Продолжаем — насколько помогает сберечь время такой язык как С по сравнению с Фортраном?

Ну, С затрачивает немного меньше времени на «рутинную» работу, чем Фортран. В старом Фортране нужно было помнить такие вещи, как номера строк и порядок общих операторов. Было также невероятное количество операторов перехода по всему тексту. Язык С намного более комфортный для программирования, чем Фортран 1. Я бы сказал, что он уменьшил трудоёмкость примерно на 20%.

Хорошо. То есть 10 программистов на С могут заменить 12 программистов на Фортране?

Ну, это, конечно, только предположение, но я бы сказал, обоснованное предположение.

Хорошо. Теперь: насколько С++ уменьшил трудоёмкость по отношению к C?

Послушайте, давайте остановимся. Мы сейчас не вспоминаем о намного большем воздействии.

Разве? Что именно?

Среда разработки. Это значит, что в 50-х годах мы использовали перфокарты и бумажные ленты. Компиляция простой программы занимала, как минимум, полчаса. И то, если вы могли получить доступ к машине. Но в конце 80-х, когда С++ стал популярным, программисты хранили свои программы на дисках, а компиляция простой программы продолжалась уже всего две-три минуты.

Это — снижение трудоёмкости? Или просто уменьшение времени ожидания?

А. Так вот оно что. Вопрос ясен. Да, тогда машину приходилось ждать долго.

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

Понятно, понимаю. Итак, вы спрашивали о C++. Вообще-то, честно, я не думаю, что C++ как-то значительно снизил трудоёмкость. Конечно, что-то было, но, полагаю, не более 5%. Это значит, что рутинная нагрузка в С просто была небольшой, и поэтому сравнительная экономия времени при работе в С++ не могла быть значительной.

Если использовать 5%, то это значит, что 100 программистов на С++ могут заменить 105 программистов на С. Это, действительно, так?

В общем, да. Но только для небольших и средних по размеру программ. Для больших программ C++ даёт некоторые дополнительные преимущества.

Какие?

Это довольно сложно объяснить. Но суть в том, что объектно-ориентированные характеристики C++, в частности, полиморфизм, позволили разделять большие программы на независимо разрабатываемые и развёртываемые модули. И это — для очень больших программ — значительно уменьшает рутинную нагрузку.

Можно цифру?

Хорошо, вы, похоже, и дальше собираетесь выкручивать мне руки… Учитывая количество действительно больших программ, которые создавались в 80-е и 90-е годы, я скажу, что, в целом, C++ уменьшил трудоёмкость, возможно, на 7%.

Это не прозвучало особо уверенно.

Да. Но давайте использовать это значение. 7%.

Хорошо. Итак, 100 программистов на C++ могут заменить 107 программистов на C?

Похоже, так я и сказал. Давайте использовать это значение.

Сколько времени сберегает Java по сравнению с C++?

Трудно сказать. Какое-то время сберегает. Java — более простой язык. У него есть автоматическое управление освобождением динамической памяти («сборка мусора»). У него нет файлов заголовков. Он работает на виртуальной машине. У него есть много достоинств. И немного недостатков.

Как насчёт цифры?

У меня ощущение, что мы буксуем… Но поскольку вы так прессуете меня, то сказал бы, что при прочих равных условиях (чего никогда не бывает) можно, работая с Java, получить снижение трудоёмкости на 5% по сравнению с С++.

Итак, 100 программистов на Java могут заменить 105 программистов на C++?

Да! Впрочем, нет. Это не так. Разброс слишком большой. Если выбрать случайным образом 100 программистов на Java и сравнить их с так же выбранными 105 программистами на C++, то я не решился бы спрогнозировать результат. Чтобы получить реальный выигрыш, требуется намного больше программистов.

Насколько больше?

Как минимум, на два порядка.

Иначе говоря, 10 000 случайным образом выбранных программистов на Java могут заменить 10 500 так же выбранных программистов на C++?

Пожалуй, так.

Очень хорошо. Насколько такой язык, как Ruby, снижает трудоёмкость по сравнению с Java?

Ну, уважаемый! (вздыхает). О чём вы? Смотрите, Ruby, действительно, прекрасный язык. Он одновременно простой и сложный, элегантный и причудливый. Он намного медленнее Java, но компьютеры сейчас такие дешёвые, что …

Извините, но я спрашиваю не об этом.

Вы правы. Я знаю. Итак, главное направление, на котором трудоёмкость у Ruby меньше по сравнению с таким языком, как Java, — это Types (Типы). В Java необходимо создавать формальную структуру типов и поддерживать её согласованность. В Ruby можно играть с типами довольно быстро и свободно.

Звучит как прирост производительности труда.

В общем, нет. Оказывается, возможность играть быстро и свободно со структурой типа ведёт к появлению класса ошибок времени исполнения, которые отсутствуют при программировании на Java. Поэтому программисты на Ruby имеют более высокую нагрузку по тестированию и отладке программ.

Иными словами, эти эффекты уравновешиваются?

Это зависит от того, кого вы спрашиваете.

Я спрашиваю вас.

Ладно. Я бы сказал, что эффекты не уравновешивают друг друга. Трудоёмкость при работе с Ruby ниже, чем с Java.

Насколько? 20%?

Люди привыкли думать так. Действительно, в 90-е многие думали, что программисты на Smalltalk работают во много раз производительнее, чем на C++.

Вы запутываете меня. К чему вспоминать те языки?

Да потому, что C++ довольно близок к Java, а Smalltalk — к Ruby.

Ясно. Таким образом, Ruby снижает трудоёмкость в несколько раз по сравнению с Java?

Нет, скорее всего, не так. Если оглядываться на 90-е, то проблема со временем ожидания была ещё довольно выраженной. Длительность компиляции для типичной программы на C++ составляла несколько минут. Длительность компиляции для программы на Smalltalk была практически нулевой.

Нуль?

Практически, да. Проблема в том, что при использовании таких языков как Java и C++ необходимо выполнять много действий по согласованию всех типов. При использовании Smaltalk и Ruby такой проблемы нет. Поэтому в 90-е для них требовалось время от минут до миллисекунд.

Ясно. Но поскольку всё это — только время ожидания, то мы можем не рассматривать его.

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

Быстрая обратная связь снижает трудоёмкость?

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

Нелинейно?

Да, «рутинная» нагрузка растёт непропорционально длительности цикла. Она может расти как, например, O(N^2). Я не знаю. Но я совершенно уверен, что зависимость нелинейная.

Замечательно! Значит, Ruby является лидером!

Нет. И в этом-то суть. Благодаря совершенствованию нашего аппаратного обеспечения в последние двадцать лет длительность компиляции для Java стала практически нулевой. Время цикла у программиста на Java стало не больше (или должно быть не больше), чем у программиста на Ruby.

Уточните, пожалуйста.

Я говорю, что программисты, использующие дисциплину короткого цикла, увидят лишь небольшое различие в трудоёмкости (или, вообще, не увидят его), работая с Java и Ruby. Имеющееся различие будет настолько малым, что его трудно будет измерить.

Неизмеряемое различие?

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

Но вы раньше сказали, что Ruby снижает трудоёмкость по сравнению с Java.

Я думаю, что так оно и есть, но только если время цикла большое. Если цикл редактирование/компиляция/тестирование держать очень коротким, то эффект будет пренебрежимо малым.

Нуль?

Конечно, нет, — более вероятно около 5%. Но разброс будет гигантским.

Таким образом, 10 500 программистов, работающих в коротком цикле на Java, выполняют ту же работу, что 10 000 программистов в коротком цикле на Ruby?

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

Существуют ли языки, превосходящие Ruby?

Можно получить ещё 5%, используя язык типа Clojure, поскольку он, с одной стороны, довольно простой, и, с другой стороны, функциональный.

Вы даёте лишь 5% функциональному языку?

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

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

То есть: Swift? Dart? Go?

Не имеет значения.

Scala? F#?

Не имеет значения.

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

Не совсем так. Я говорю лишь, что мы идём по пути снижающейся эффективности. Ни один будущий язык не даст выигрыш в 10 раз, как это было у ассемблера по отношению к двоичному коду. Ни один будущий язык не даст снижение трудоёмкости на 50% или 20% или даже 10% в сравнении с имеющимися языками. Дисциплина короткого цикла свела различия к практической неизмеримости.

Тогда почему же появляются всё новые языки?

Это поиск Святого Грааля.

А, так это всего лишь вопрос уровня любимого цвета.



Примечание переводчика: Заголовок поста и его тематика являются отсылкой к фрагменту фильма «Монти Пайтон и Священный Грааль», в котором рыцари Круглого стола отвечают на пять три вопроса, чтобы пересечь Мост смерти
Tags:
Hubs:
+7
Comments 119
Comments Comments 119

Articles