Исследование характеристик производительности труда программиста (доклад на семинаре по технологии программирования, ИК АН УССР, 11.09.84)

Мой доклад состоит из трёх довольно автономных частей.

В первой части я расскажу о системе I, или личном банке данных. Эта система автоматизирует учёт времени по системе Любищева и позволяет получать справки о бюджете времени, о затратах времени на различные работы, и т.д.

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

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

1. Система I

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

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

Но управление не существует без учёта. Широко известна система учёта времени, разработанная А. А. Любищевым. Я давно пользуюсь ею и она очень помогла мне в жизни - как в профессиональном росте, так и в развитии вообще. Эта система стимулирует творческую активность, помогает лучше организовать работу, очень проста в использовании и практически не требует затрат времени на обслуживание. Все важнейшие показатели получаются автоматически, в виде нескольких сумм. Однако систему можно использовать намного эффективнее, если оперативно получать более развёрнутую информацию. При ручной обработке такая информация стоит слишком дорого - затраты на её получение могут перекрыть эффект её использования.

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

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

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

Время-суток количетсво минут режим ключ

8-символьный ключ присваивается каждой работе - т.е. программному проекту, книге и т.д. Например, книга Майерса имеет клюй МАЙЕНАДЕ, работа над версией 2.3 системы ДЕЛЬТА имеет ключ ДЕЛЬТА 23 и так далее. Ключ присваивается для того, чтобы не выписывать каждый раз полное наименование работы. Естественно, имеется файл с расшифровками ключей.

Режим - код из нижнего уровня классификатора работ. Этот классификатор трёхуровневый, и у меня он имеет такой вид: на первом уровне все разбиваются на: 0 - по специальности, 2- физическую нагрузку и 3 - прочее. Например, работа по специальности на втором уровне делится на: 01 - творческую, 02 - чтение специальной литературы, 03 - вспомогательную, 04 - коммуникации, 05 - описание. В свою очередь , например, творческая делится на: 011 - математика, 012 - проектирование систем, 013 - программирование и отладка, 014 - прочее. Это уже режимы работы.

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

Пример. В 10.00 я получил распечатку программы КРЕНОЛ и до 10.40 искал ошибку. На бланке это отражается так:

10.40 40 013 КРЕНОЛ

Тут пришёл пользователь с вопросами по ФОРТРАНУ и с ним я провозился 20 мин:

11.30 20 042 КОНСУЛЬТ

Затем пришёл приятель и полчаса болтали о том, о сём:

11.30 30 321 Т

И так далее. В таком виде данные вводятся в базу данных и затем можно получать различные справки. Я использую в основном отчёт по форме 1 - распределение работ по категориям.

В настоящий момент в базе данных находится 50000 записей, охватывающих период с 1 марта 1976 года по сей день. С сентября 1983 года ежемесячно выдаются месячные отчёты по форме 1. Таким образом, можно говорить, что в течение года находится в эксплуатации автоматизированная система учёта времени и, более того, автоматизированная система учёта времени и более того, автоматизированная система управления собой, так как она влияет не только на распределение времени, но и на поведение, на мировоззрение. С помощью системы I можно, в частности, исследовать некоторые аспекты профессиональной деятельности. Об этом пойдёт речь во второй части доклада.

2. Мифический "оператор в день"

За 8 лет программисткой деятельности я прошёл от убеждения в том, что знание АЛГОЛа хватит на все случаи жизни и что программирование - это искусство для избранных, до понимания того, что мы занимаемся на самом деле изготовлением программных изделий и что для этого нужна жёсткая технология и производственная организация труда. Это, в общем, закономерный путь, но шишек было набито немало - особенно, если учесть, что 90% объёма моей программной продукции составили системы или ядра систем. Многое пришлось перепробовать - менялись языки программирования (я даже внёс свою лепту и создал эн плюс первый язык - АС), менялся подход к своей продукции - от понятия программы до понятия программного изделия менялась организация труда - если мы начинали на Дельте системы еженедельных семинаров, то сейчас опробовали и бригаду главного программиста. Выяснилось одно - царской дороги в программировании, похоже, нет и не будет.

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

Я задался целью выяснить - как менялась и от чего зависела моя производительность труда: как влиял на неё опыт, как влияли различные технологии и т.д. В базе данных системы I накоплены данные о затратах времени на все программы и системы, над которыми я когда-либо работал. В личном фонде алгоритмов и программ сохранились окончательные распечатки практически всех программ. Из них я отбросил незавершённые, специфические (контрольная точка, поверка АП и т.д.), конкурсные программы и 10 одиночных программ общим объёмом 200 операторов на ФОРТРАНе. Для оставшихся программ были выданы системой I таблицы, содержащие по вертикали режимы работы - проектирование, программирование и отладка, вспомогательная, коммуникации, документация, а по горизонтали - для каждого режима и для общих затрат: интервал дат, количество дней, количество реальных дней (т.е. дней, в которые были зафиксированы затраты времени на каждую программу), количество минут, процент от общего количества минут на данную программу, количество минут в день, количество минут в реальный день, количество минут, затраченных на единицу длины.

Первая проблема, вставшая передо мной - критерий оценки производительности труда. Первый из общеизвестных - количество операторов, отлаженных в год - я отвёл сразу: это скорее показатель активности программиста, чем производительности труда. Более точный критерий - количество операторов, отлаживаемых в человеко-день. Количество человеко-дней берётся от начала до конца проекта. Система I показала, однако, что, несмотря на то, что я человек довольно дисциплинированный, на работу хожу каждый день и на работе стараюсь заниматься только работой, количество человеко-дней существенно отличается от количества реальных дней. То не работала машина, то послали в колхоз, то весь день оформлял командировку - понемногу набирается большое количество нерабочих человеко-дней, и от программиста тут мало что зависит. Но, даже если учитывать только реальные дни, и тут не всё зависит от программиста - загрузка машины, например. В то же время задача становится так: определить "чистую", истинную производительность труда. В этом смысле максимально точной была бы оценка времени в "чистых", "хоккейных" единицах, т.е. время, затраченное на проект, должно быть учтено с точностью до минуты. Понятно, что обычно такую оценку получить трудно, но у меня нужные данные были. Для оценки длины программы использовалась методика Холстеда, т.е. складывалось количество операторов, операндов и операций. Таким образом можно получить оценку производительности труда (т.е. количество единиц программного текста, изготовляемого в единицу времени) либо обратную величину - количество минут на единицу программного текста. В данном исследовании использовалась в основном втроая оценка я назвал её относительной стоимостью.

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

Общая по одиночным по системам
1976 10.20 - 10.20
1977 5.12 5.12 -
1978 4.11 2.00 5.38
1979 3.41 2.03 4.14
1980 3.86 - 3.86
1981 - 1.99 -
1982-1983 3.40 1.71 3.40

Из таблицы видно, что средние стремительно падают первые три года, а затем стабилизируются. Причём для одиночных программ происходит довольно отчётливая стабилизация на уровне 2 минуты в единицу текста, а для систем трудозатраты падают в среднем на 10% в год.

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

И эта интерпретация вполне бы меня устроила, если бы данные были получены по программистам, мне лично неизвестным. Но...

Но стабилизация произошла именно в 1979 году, когда я познакомился с понятием "хорошее программирование" и стал активно внедрять его в свою и чужую практику. Перед расчётами я ожидал, что в 1980 году производительность труда скакнёт на порядок, а вместо этого - полная стабилизация. За что боролись? Получается, что я обманул кучу народа, от проректора по научной работе до последнего двоечника в студенческой группе, когда доказывал, что структурное программирование повышает производительность труда в 5-10 раз?

Чтобы как-то объяснить это явление, я выдвинул 3 гипотезы:

1. Условия работы в 1979-1980 году сменились, что привело к искажению (либо изменилась методика подсчёта длины)

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

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

Что касается третьей гипотезы, её я проверить не мог, т.к. до 1979 года вообще не имел понятия о том, что существует такая фаза разработки программ, как проектирование - она учитывалась как программирование.

Относительно первой гипотезы: действительно, с 1980 года мы перешли на пакетный режим, но это должно было, напротив, уменьшить затраты времени, так как убиралось непроизводительное торчание в машзале. Методика подсчёта длины действительно претерпела изменения, за счёт того, что произошла смена языков - от ассемблера и ФОРТРАНа я перешёл на АС и ПЛ/1. Если для АС и ПЛ/1 длина программы занижается по сравнению с ассемблером и ФОРТРАНом, то естественно завышается и относительная стоимость. Однако эксперимент показал, что это не так: наоборот, один и тот же алгоритм, реализованный на ассемблере, уложился в 33 единицы длины, в то время как для ФОРТРАНа, Аса и ПЛ/1 были получены такие оценки: 47; 44; 56. То есть, оценка длины в "хороших" языках завышается, и реальная относительная стоимость на 30% хуже!

В пользу второй гипотезы говорит многое: более продуманное разбиение на модули позволяет избежать дублирования функции. Во-вторых, нисходящие и структурные методы позволяют писать программы более просто, а значит, и более коротко. Это позволяет и избежать заплат при отладке, а при беспорядочном программировании всяческие временные обходы занимают достаточно большой процент текста. Так что гипотеза вполне правдоподобна. Я проверил её на трёх версиях системы ДЕЛЬТА. Дело в том, что я дважды полностью переписал все свои модули - в первый раз это был типичный эффект второй системы, а во второй - переписал структурно. От версии к версии функциональные возможности системы по крайней мере не уменьшались, однако длина реализации неуклонно падала:

1. 0 ДОС - 7696

2. 0 ДОС - 7593

3. 0 ДОС - 6918

Если учесть, что 2.0 ОС написана на АСе, т.е. её реальная длина на ассемблере на 30% меньше, т.е. около 5000, получается, что структурное программирование уменьшило длину текста как минимум в полтора раза (здесь не учтён ещё эффект от того, что 2.0 ОС несколько богаче функционально)

Затраты времени также падают: 41430 минут, 31440 минут, 26280 минут. Следовательно, можно предположить, что структурное программирование действительно повышает производительность труда (реальную, где объём системы оценивается не длиной текста, а мощностью функций) в полтора раза, относительная же стоимость падает значительно медленнее.

Из всего сказанного следует, что критерию оценки производительности труда "время на длину" доверять нельзя, так как длина программы для одной и той же задачи может сильно колебаться в зависимости от методов программирования, опыта и индивидуальных особенностей программиста (На конкурсах программистов нередки случаи, когда одна и та же задача, решённая разными людьми за одно и то же время, реализуется программами, длины которых расходятся на порядок. Можно ли говорить о том, что и производительность труда программистов различается на порядок?). По всей видимости, для оценки объёма программы нужно использовать такое понятие, как её функциональная мощность, и пытаться её оценить.

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

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

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

В заключение скажу об одном частном эффекте, выясненном в процессе анализа данных. Несмотря на то, что производительность труда растёт, количество человеко-дней не падает. Это можно объяснить только пропорциональным ростом загрузки ЭВМ, так как распечатки обрабатываются сразу по поступлении. И, действительно, загрузка инструментальной машины постоянно увеличивалась (количество прогонов в день упало с 5-6 до 1-2). Система 1 показала, что реальная нагрузка дня также падает: 205 минут в 1976 году, 202 в 1979, и, начиная с 1980: 155, 115, 95. Мораль такова: чем больше загрузка машины, тем более широким фронтом должна вестись разработка системы, т.е. в работе должно находиться как можно больше модулей одновременно. Это требует особого подхода к тестированию, организации всяческих предбанников и т.д. и в целом требует большего напряжения сил, но, если нужно соблюдать график, иного выхода нет.

3. Бригада главного программиста

В 1982-1983 годах мы провели крупный (по нашим возможностям) эксперимент. В рамках системы ДЕЛЬТА нужно было создать новую подсистему - печать произвольных таблиц. Мы решили на этой новой разработке перестроить как организационную структуру группы, так и подход к проектированию и программированию модулей.

Во-первых, вместо группы отдельных программистов была создана бригада главного программиста. Вот её состав:
1. Руководитель работ
2. Главный программист
3. Второй пилот
4. Тестировщик
5. Редактор
6. Три проблемных программиста

Руководитель работ осуществлял интерфейс с пользователем, определял цели подцели, утверждал все проектные решения.

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

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

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

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

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

Программирование и отладка велись так: второй пилот вёл свои модули самостоятельно, но изменения согласовывал с главным программистом. Остальные модули писались совместно главным программистом и проблемными программистами (1-2 года стажа). Это оказалось полезно для обеих сторон - проблемные программисты сняли с главного программиста вспомогательную работу, а взамен без особых усилий овладели языком и приёмами программирования и избежали многих ошибок, свойственным начинающим программистам. Ошибки, выявленные при тестировании, в основном исправлялись так: сначала проблемный программист сам пытался найти ошибку, затем, если это не получалось, он искал её совместно с главным программистом. Исправления же согласовывались с главным программистом в любом случае. Этот стиль до конца выдержать не удалось: проблемные программисты написали самостоятельно несколько оконечных модулей и отлаживали их тоже самостоятельно.

Что касается производительности труда главного программиста, то она выросла очень незначительно, как это ни странно. Это удалось проверить, так как главным программистом параллельно с разработкой ДЕЛЬТА 2.3 разрабатывалась система I. Язык был один и тот же, концепции проектирования были сходными, да и вообще это системы одного класса.

Относительная стоимость для ДЕЛЬТА 2.3 - 2.50, а для системы I - 3.40, то есть всего в потора раза выше. Фактически это означает, что если я плюс три проблемных программиста потратили на систему два года, то один я справился бы с ней за три года, то есть выигрыш от применения бригады не такой уж большой (имеется в виду использование программистов - помощников, важность второго пилота и тестировщика не подвергается сомнению). Этот вывод подтверждается и анализом затрат времени по категориям:

Система I ДЕЛЬТА 2.3
Проектирование 7.53% 8.33%
Программирование и отладка 43.90% 14.19%
Вспомогательная 40.52% 13.67%
Коммуникации 0.78% 52.86%
Документация 7.27% 10.94%

Таким образом, видно, что проектирование и документация отнимают 15-20% времени как при одиночно разработке системы, так и при бригадном методе, а время, которое при одиночной работе ушло бы на программирование, отладку и вспомогательную работу, просто уходит на коммуникации.

Второй особенностью системы ДЕЛЬТА 2.3 было более строгое разбиение на модули. До этого вся технология сводилась в основном к структурному и нисходящему программированию и к оформлению программ. Теперь же была поставлена задача собрать систему из модулей только двух видов прочности - информационно прочных и функционально прочных. Если функциональная прочность удалась не совсем (некоторые модули в процессе отладки пришлось "расшить" на более мелкие), то информационно прочные модули оказались очень полезными. Мы упрятали в один модуль информацию о главной управляющей таблице и, хотя она затем не раз модифицировалась, модули, работающие с нею, изменять не пришлось. Упрятаны были также все наборы данных, т.е. доступ к ним осуществлялся через модули, которые полностью содержали информацию о структуре и типе наборов данных и, более того, о месте их расположения. Особенно полезным оказалось применение информационно прочных модулей для защиты от ошибок и средств диагностики, но об этом подробнее в следующем пункте.

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

Однако, оказалось, что такие средства, как и средства защиты от ошибок, сильно перегружают программу - во всех случаях, кроме одного: если они встроены в информационно прочный модуль. Тогда появляется возможность написать отладочный оператор один раз - в модуле доступа и контролировать наиболее важную информацию. Этот подход принят стандартным в разрабатываемой сейчас версии 3.0 системы ДЕЛЬТА.


© Алексей Бабий 1984