Закон Хофштадтера: Любое дело всегда длится дольше, чем ожидается, даже если учесть закон Хофштадтера.
—?Дуглас Хофштадтер, Гёдель, Эшер, Бах
У написания прозы и кода есть много общего. Но самое заметное сходство, вероятно, заключается в том, что ни писатели, ни программисты не могут закончить свою работу вовремя. Писатели славятся отъявленной привычкой срывать сроки. Программисты заслужили репутацию людей, чьи результаты всегда серьезно отличаются от первоначальных расчетов. Возникает вопрос: почему?
Сегодня у меня появилась идея, как можно на него ответить. И мои находки меня поразили.
Изучая свои книги
Обе свои книги, Привет, стартап и Terraform: запускаем и работаем, я написал в среде для создания книг Atlas, которая предусматривает управление всем контентом с помощью Git. Это означает, что каждая строчка текста, каждая правка и каждое изменение были зафиксированы в коммит-логе Git.
Проверим, сколько же усилий было затрачено на написание двух книг.
Привет, стартап
Начнем с моей первой книги Привет, стартап. В ней 602 страницы и примерно 190 тыс. слов. Я запустил
cloc
в git-репозитории Hello, Startup и получил следующие результаты (для простоты дробные части отброшены):602 страницы содержат 26 571 строк текста. Львиная доля написана на языке AsciiDoc, похожем на Markdown. Он используется в Atlas для написания практически любого контента. С помощью HTML и CSS в Atlas задаются макет и структура книги. Кроме них есть и другие языки программирования (Java, Ruby, Python и не только), на которых написаны различные примеры к обсуждаемым в книге темам.
Но 602 страницы и 26 571 строка — это лишь конечный результат. Они не отражают около 10 месяцев написания, изменений, редактирования, вычитки, стилистических корректировок, исследований, заметок и другой работы, способствующей выходу книги в свет. Поэтому, чтобы получить больше полезных идей, я воспользовался
git-quick-stats
для анализа всего журнала коммитов книги.Итак, мною были добавлены 163 756 строки и удалены 131 425, что в сумме дает 295 181 строк переработанного материала. То есть получается, что я написал или удалил в общей сложности 295 181 строк, из которых в итоге осталось 26 571 строки. Это соотношение составляет чуть больше 10:1. Для получения каждой опубликованной строки мне пришлось сначала написать 10 других!
Признаю, что подсчет количества добавленных в Git и удаленных из него строк нельзя считать идеальной метрикой процесса редактирования. Но, по крайней мере, это позволяет понять, что для оценки проделанной работы простого подсчета недостаточно. Существенная часть процесса вообще не отразилась в журнале коммитов Git. К примеру, первые несколько глав были написаны в Google Docs до того, как я перешел в Atlas, и многие правки были внесены на моем компьютере без коммитов.
Несмотря на то, что эти данные далеки от идеала, я полагаю, что общее соотношение «первоначального текстового материала» к опубликованному составляет 10:1.
Terraform: запускаем и работаем
Давайте проверим, применима ли эта пропорция к моей второй книге Terraform: запускаем и работаем, содержащей 206 страниц и около 52 тыс. слов.
Упрощенный вывод
cloc
:206 страниц состоят из 8410 строк текста. И снова большая часть текста написана в AsciiDoc, хотя в этой книге заметно больше примеров кода, написанных преимущественно на HCL, основном языке Terraform. Кроме него много Markdown, которым я пользовался для документирования HCL-примеров.
Воспользуемся
git-quick-stats
для проверки истории правок этой книги:В течение почти пяти месяцев я добавил 32 209 и удалил 22 402 строки, что в сумме дало 54 611 переработанных строк. Точность оценки процесса редактирования этой книги страдает еще больше, поскольку работа начиналась как серия блог-постов, прошедших через ощутимую переработку до их перемещения в Atlas и Git. Объем этих блог-постов занимает не меньше половины книги, поэтому будет логично увеличить итоговый показатель переработанного текста на 50%. То есть всего получится 54611 * 1,5 = 81 916 строк редактируемого текста, вылившихся в итоговые 8410 строк.
И снова наблюдается соотношение примерно 10:1!
Неудивительно, что писатели не укладываются в сроки. Если по графику положено сдать книгу в 250 страниц, то на практике выйдет, что в процессе работы мы напишем 2500 страниц.
А что насчет программирования?
Как обстоят дела в области разработки? Я решил проверить несколько git-репозиториев с открытым исходным кодом разного уровня зрелости: от нескольких месяцев до 23 лет.
terraform-aws-couchbase (2018)
terraform-aws-couchbase — набор модулей для деплоя и управления Couchbase на AWS, исходный код которых был открыт в 2018 году.
Упрощенный вывод
cloc
:А вот и результат проверки
git-quick-stats
:Получаем целых 37 693 строк рабочего кода, вылившихся в 7481 строк итогового кода в соотношении 5:1. Даже в репозитории младше 5 месяцев уже пришлось переписать каждую строку пять раз! Неудивительно, что оценка разработки ПО сложна: мы даже не представляем, что для получения 7,5 тыс. строк итогового кода на самом деле приходится написать 35 тыс.
Посмотрим как обстоят дела в более старых продуктах.
Terratest (2016)
Terratest — opensource-библиотека, созданная в 2016 году для тестирования инфраструктурного кода.
Упрощенный вывод
cloc
:Результаты
git-quick-stats
:Это 49 126 рабочих строк кода, превратившихся в 6140 строк итогового текста. Для двухлетнего репозитория соотношение составило 8:1. Но Terratest все еще довольно молод, поэтому давайте рассмотрим репозитории постарше.
Terraform (2014)
Terraform — библиотека c открытым исходным кодом, созданная в 2014 году для управления инфраструктурой с помощью методов программирования.
Упрощенный вывод
cloc
:Результаты
git-quick-stats
:Получаем 12 945 966 рабочих строк кода, вылившихся в 1 371 718 строк конечного результата. Соотношение 9:1. Terraform существует почти 4 года, но библиотека все еще не вышла в релиз, поэтому даже при таком соотношении ее кодовую базу пока нельзя назвать зрелой. Заглянем еще дальше в прошлое.
Express.js (2010)
Express — популярный JavaScript-фреймворк с открытым исходным кодом, выпущенный для веб-разработки в 2010 году.
Упрощенный вывод
cloc
:Результаты
git-quick-stats
:Получаем 224 211 рабочих строк кода, сократившихся до 15 325 итоговых строк. Результат 14:1. Express исполнилось около 8 лет, последние его версии имеют номер 4.х. Он считается самым популярным и проверенным в боевых условиях веб-фреймворком для Node.js.
Создается впечатление, что как только соотношение достигает уровня 10:1, мы можем с уверенностью говорить, что кодовая база уже «взрослая». Давайте проверим, что будет, если отправиться еще глубже в прошлое.
jQuery (2006)
jQuery — популярная JavaScript-библиотека с открытым исходным кодом, выпущенная в 2006 году.
Упрощенный вывод
cloc
:Результаты
git-quick-stats
:Итого 730 146 рабочих строк кода, вылившихся в 47 559 строк конечного результата. Соотношение 15:1 для почти двенадцатилетнего репозитория.
Отправимся еще на десять лет назад.
MySQL (1995)
MySQL — популярная реляционная база данных с открытым исходным кодом, созданная в 1995 году.
Упрощенный вывод
cloc
:Результаты
git-quick-stats
:Получаем 58 562 999 рабочих строк, 3 662 869 строк конечного кода и соотношение 16:1 для почти двадцатитрехлетнего репозитория. Надо же! Каждая строка кода MySQL была переписана по 16 раз.
Выводы
Обобщенные результаты по моим книгам выглядят следующим образом:
Название |
Рабочие строки |
Итоговые строки |
Соотношение |
Привет, стартап |
295 181 |
26 571 |
11:1 |
Terraform: Запускаем и работаем |
81 916 |
8410 |
10:1 |
А вот сводная таблица для различных проектов в области программирования:
Название |
Год выпуска |
Рабочие строки |
Итоговые строки |
Соотношение |
terraform-aws-couchbase |
2018 |
37 693 |
7481 |
5:1 |
Terratest |
2016 |
49 126 |
6140 |
8:1 |
Terraform |
2014 |
12 945 966 |
1 371 718 |
9:1 |
Express |
2010 |
224 211 |
15 325 |
14:1 |
jQuery |
2006 |
730 146 |
47 559 |
15:1 |
MySQL |
1995 |
58 562 999 |
3 662 869 |
16:1 |
Что же значат все эти цифры?
Правило 10:1 в прозе и программировании
С учетом того, что мой набор данных ограничен, я могу сделать только некоторые предварительные заключения:
- Соотношение «исходного сырья» и «конечного продукта» для книги составляет примерно 10:1. Держите эту цифру в голове, когда будете обсуждать с редактором график сдачи материала. Если вам необходимо написать книгу в 300 страниц, значит на самом деле придется сочинять около 3 тыс. страниц.
- Аналогичное правило можно вывести и для зрелого и нетривиального программного обеспечения: соотношение объема переработанного кода к итоговому составляет как минимум 10:1. Помните об этом, когда менеджер или клиент попросит вас оценить временные затраты. Приложение размером в 10 тыс. строк потребует от вас написания примерно 100 тыс. строк.
Эти находки можно резюмировать в виде правила 10:1 для писательства и программирования:
Написание хорошего ПО или текста требует, чтобы каждая строка была переписана в среднем по 10 раз.
Следующие шаги
Конечно, строки кода и строки текста нельзя считать идеальной мерой. Но, полагаю, если собрать достаточное количество данных, то можно определить, насколько правило 10:1 универсально и полезно для уточнения срока завершения работы над проектом.
Некоторые вопросы, на которые мне хотелось бы получить ответ:
- Можно ли использовать соотношение переработанных строк кода к итоговым как быструю метрику оценки зрелости того или иного ПО? Например, можем ли мы доверять решение ключевых инфраструктурных задач базам данных, языкам программирования или операционным системам, если для них это соотношение достигло хотя бы 10:1?
- Зависит ли объем рабочего текста от типа ПО? Например, Билл Скотт выяснил, что в Netflix только около 10% кода пользовательского интерфейса доживает до одного года, а остальные 90% к этому времени полностью переписываются. Какова скорость замены кода для бекэнда, баз данных, утилит командной строки и других типов программ?
- Какой процент кода перерабатывается уже после первоначального релиза? То есть какой процент работы можно считать «поддержкой ПО»?
Если вы автор книг и можете проделать аналогичный анализ, я буду рад узнать о ваших результатах. И если у кого-либо найдется время для автоматизации подобного анализа, будет здорово узнать о соотношениях, обнаруженных в различных проектах с открытым исходным кодом.
Обновление от 13 августа
Обсуждения поста на Hacker News и Reddit’s r/programming позволили выяснить еще два интересных момента:
- Судя по всему, похожее правило 10:1 справедливо для фильмов, журналистики, музыки и фотографии! Кто бы мог подумать?
- Читатели оставили много комментариев о том, что изменение даже единственного символа может быть засчитано в Git как вставка или удаление строки, поэтому показатель в 100 тыс. измененных строк вовсе не значит, что переработке подверглась каждая строка.
Последнее замечание справедливо, но, как я уже писал выше, мои данные не учитывают другие типы изменений:
- Коммиты я делаю не для каждой отдельной строки. Я могу изменить ее десять раз, но сделать при этом только один коммит.
- Описанная в предыдущем пункте ситуация еще более актуальна для программирования. Во время тестирования кода я могу менять одну строку по 50 раз, делая при этом всего лишь один коммит.
- Многие циклы правок и написания текста были выполнены за пределами Git (некоторые главы были написаны в Google Docs или Medium, а стилистические правки были выполнены в PDF).
Думаю, что все эти факторы компенсируют особенность учета вставки или удаления строк в Git. Конечно, мои оценки могут быть неточными, и реальное соотношение окажется 8:1 или 12:1. Но в целом разница не слишком велика, а 10:1 легче запоминается.
Обновление от 14 августа
Пользователь Github Decagon создал репозиторий под названием hofs-churn с bash-скриптом для простого расчета степени проработки кода в ваших репозиториях. Он также воспользовался им для анализа целого ряда репозиториев, таких как React.js, Vue, Angular, RxJava и многих других, и результаты получились довольно интересные.
Комментарии (5)
Guitariz
29.08.2018 15:53+1Необходимо еще учитывать, что количество переписываний будет постепенно уменьшаться. Если в начале пути можно в принципе бесконечно заниматься переписыванием без приемлимого результата, то со временем, возможно, получится писать хорошо и с первого раза. Не целиком программу, но по крайней мере модули.
Опять же, если в начале ты тратишь больше времени на переписывание тонких моментов (условно — строки), то с опытом ты больше занимаешься изменением архитектуры, заменяя целые модули и компоненты.
Впрочем, и планка растет — то, что в начале казалось очень хорошо «вымученным» проектом, со временем хочется переписать полностью.eexo
29.08.2018 22:45Это работает только если в какой-то момент поставить «программу» на полку. Любой проект который развивается — переписывается. Как пример — те же jQuery и MySQL из статьи. Не сказать чтоб только джуниоры их писали/переписывали, однако соотношение переписанного у них самое большое.
Дело не в планке, дело в фичах. Иногда добавление даже небольшой фигни, требует существенного перетряхивания потрохов. А фичи всегда тянут за собой баги :) Поэтому количество переписываний уменьшаться не будет никогда.
А переписать полностью — не работает на больших проектах. Притча во языцех — Мозилла. Нетскейп в свое время рулил и покрывал всё стадо в тогдашних интернетах. Но потом они решили его полносьтю переписать. Чем это кончилось — известно.
Darka
29.08.2018 20:16wirex, не совсем по теме, но посмотрите пожалуйста личные сообщения ( habr.com/conversations )
inoyakaigor
30.08.2018 14:37Хотелось бы плагин для своего редактора который бы занимался подсчётом вот этих всех переписываний
mSnus
В фотографии примерно так же — если не делать лишних дублей "на всякий случай", то 1 хорошая на 10 "в мусорку" вполне неплохой результат!