Искусство программирования под Unix (и не только). Часть шестая, «правило кодоэкономии»

    Я продолжаю цикл статей, посвященных некоторым простым правилам разработки под Unix «по версии Эрика Реймонда», которые, по моему глубочайшему убеждению, могут быть распространены на любые другие операционные системы. Я уже рассказывал в первых трех частях о правилах модульности, ясности, композиции, разделения и простоты. Сегодня дело дошло до шестого правила —

    Правило кодоэкономии: разрабатывайте большие программы только при наличии объективных причин это делать

    Есть такое поколение программистов, которых я называю write-only-программистами. Это такие люди, которые любят создавать, но не успевают осмыслить. Они могут за очень короткое время написать вполне работающего монстра, но через неделю уже затрудняются что-то в нем изменить. Особенно, если изменение не мелочное. Правило кодоэкономии перекликается с другими правилами Реймонда, даже более того, оно неразрывно связано с ними. Модуль, решающий одну, хорошо сформулированную задачу, должен быть небольшим по объему. Если это не получается, значит нужно подумать, а нельзя ли разбить одну задачу на несколько более мелких? В оригинальной трактовке данного правила есть слова ‘by demonstration’, что означает, что вы должны быть способны доказать своим коллегам по цеху, что разбивать дальше нельзя или нецелесообразно.

    Разработка сразу большого объема кода в короткое время вызвана зачастую не только желанием инвестора получить продукт скорее (хотя это самая распространенная причина). Большей бедой является излишний перфекционизм, приложенный к неправильному месту. Программистам, завершившим первую версию продукта, становится «скучно» заниматься рутинной поддержкой и вялым развитием и исправлением собственных ошибок, потому что они уже прекрасно понимают, что они сделали «не так» с самого начала. И они начинают все «с нуля». Обычно это преподносится инвесторам как благо. На самом деле, это часто путь, приводящий к еще большим проблемам. Не всегда приводящий, но отрицательных примеров много даже среди именитых брендов.Известно, что «читать» код значительно сложнее, чем его писать. Чем меньше человек в команде, чем лучше и согласованнее выходит продукт, потому что коммуникаций меньше, а следовательно, мнений и «разного почерка». Но добиться того, чтобы этот продукт был поддерживаем другими, при таком подходе непросто. Потому что «не барское это дело» — писать технические документации и интерфейсы администрирования (табличка «SARCASM»).

    Из собственного опыта я могу вспомнить разработку объектного языка программирования ArtPublishing. Мы создавали его на C/С++, взамен существующей реализации языка шаблонов на Perl. Последний не устраивал нас в первую очередь по производительности. В итоге из языка шаблонов получился язык, на котором строились довольно сложные сайты — интернет-магазины, сообщества, сложные корпоративные сайты, интранет-системы и, самое интересное, полноценная система управления контентом. С самого начала мы понимали, что получится монстр и делать его нужно правильно. В разработке интерпретатора языка самое главное — заложить запас на развитие, ведь оно обещает быть очень интенсивным. Где-то нам это удалось, где-то — нет. Например, неверный выбор хранения строк («сишный», с 00 в конце) сделал очень дорогой доработку под использование UTF-8. С другой стороны, использование внешних подключаемых модулей и API сделало возможным развитие системы, не затрагивая т.н. «ядро», так как на нем работало параллельно сразу несколько сайтов для разных клиентов.

    Чтобы быстрее отдать язык в тестовую эксплуатацию, мы сначала полностью повторили синтаксис библиотеки Template для Perl, и переключили обработку шаблонов на C++. Убедились, что все заработало на примере проекта chernobil.ru, а потом стали наращивать язык всякими полезными конструкциями, которых не было в Perl, оставляя обратную совместимость. Фактически, первый прогон системы был на одних «заглушках», которые, одна за одной заменялись на работоспособные модули. Если кому интересно, довольно убогая документация на язык есть здесь. Кстати, немного отвлекаясь от темы, были совсем близки к выпуску транслятора в C++. Представьте себе сайт, скомпилированный в бинарный код в форме одного запускаемого exe-шника и набора dll-модулей (в юниксе, соответственно, исполняемого файла и so-модулей)? То есть, интерпретатор для отладки и транслятор с компилятором для публикации. Для 2001–2002 годов было бы довольно интересное решение, но, увы, время уже убежало.Язык, к сожалению, был чудовищный по синтаксису — но этого было не избежать, надо было обратную совместимость с Perl-версией выдерживать. Вот на что был похож, например, функционал одного из модулей форума:
    &{../templates/header()};
    &{init()};
    &{#message_id=param('id')};
    &{#message_parent="&&{../papa(#message_id)};"};
    &{#tree="&&{../tree_message(#message_parent)};"};
    <!--%if{:'&{#message_id};' ne '':}-->
    <!--%repeat source="sql_uprate(#message_id)"--><!--%/repeat-->
    <!--%repeat source="sql_message(#message_id,#approved_check)"-->
            &{#message_answer=../templates/message_answer()};
            &{#author="&f{#author};"};
            &{#title="&f{#title};"};
            <!--%if{:'&{#user_mode};' eq 'admin':}-->&{#admin_message=../templates/admin_message()};<!--%/if-->
            <!--%if{:'&{#email};' ne '':}-->&{#author="<a href='mailto:&{#email};'>&{#author};</a>"};<!--%/if-->
            <!--%repeat source="sql_forum(#forum_id)"-->
                    &{#path="&{../templates/path()};"};
            <!--%/repeat-->
            &{../templates/message()};
    <!--%/repeat-->
    <!--%/if-->
    &{../templates/footer()};
    

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

    В итоге, возвращаясь к теме, вот мои рекомендации по разработке больших систем:
    • Система должна собираться из «кирпичиков», каждый из которых должен быть максимально «обособленным».«Кирпичики» должны образовывать иерархию. В идеале, должна быть возможность заменить «кирпичики» «заглушками», иммитирующими их работу для как можно более раннего тестового прогона.
    • Для работы над «кирпичиками» можно нанимать довольно большую группу программистов, а над архитектурой проекта — максимально компактную команду профессионалов. Техническое управление разработкой «кирпичиков» и ответственная приемка должны быть на этой команде. На разработку интерфейсов между «кирпичиками» и на всю архитектуру в целом определенно уйдет время, которое при других подходах часто экономят. Это самая большая ошибка при разработке больших систем.
    • Документирование работы «кирпичиков» должно быть максимально компактным: что на входе, что на выходе и как работает в двух словах, плюс несколько важных моментов, которые могут быть непонятны из кода. Из документов гораздо более важной является схема объединения «кирпичиков» в систему. Она должна быть построена так, чтобы можно было за пять минут объяснить, как работает программа.
    • Каждый модуль должен поставляться с набором тестов, демонстрирующих его работу в соответствии с требованиями. Критерий приемки модуля в работу — тесты проходят, документация короткая, понятная и соответствует тестам, удовлетворительный и «читабельный» код.
    « Ранее: правило простоты Правило прозрачности »
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 17

      +1
      Вот бы еще все этим советам следовали, и не пришлось бы кое-где разгребать и отлаживать методы по 1К строк на С++…
        +4
        Sadly, there is no silver bullet.
        0
        На собственном опыте пришёл к тому, что большую задачу лечге разбивать на модули: написание и отладка кода в итоге становятся проще, также сильно упрощается его чтение и понимание. А написанные однажды обособленные компоненты можно потом использовать в других проектах.

        По большому счёту, ничего нового. Но сколько программистов реально следуют этим правилам?
          0
          Увы и ах, вы сами сказали ключевую фразу — "на собственном опыте пришел к...". Остальные ничем не хуже и не лучше вас — они вместо того, чтобы довериться книгам или подобным статьям, предпочитают приходить ко всему «на собственном опыте», ломая горы копий о неприступные стены, когда обходные пути открыты и известны.

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

            Не ко всему приходишь сразу. Смысл некоторых вещей начинаешь понимать только со временем, даже если и знаешь это раньше.
          0
          Если бы еще «бизнес» понимал что эти последние 4-е пункта крайне важны и что на них действительно нужно время и ресурсы — было бы просто превосходно.
          А так поулчается как всегда — «бизнес» своим «быстрее быстрее быстрее...» сам же и провоцирует говнописание, ибо в некоторых ситуация либо ты отказываешься изза невозможных сроков либо вынужден привносить каплю/горку/вагончик говнокода…
          печально все это…

          истинно програмить можно только для себя!
            0
            Так и запишем… большой бизнец и искусство программирования вещи не совместимые.
              0
              Не то чтобы несовместимые, просто цели у них разные.
              У бизнеса цель — заработать деньги, а не писать программы.

              Соотсветсвенно с точки зрения бизнеса идеальный модуль, это модуль, максимизирующий формулу «доходОтИспользования — затратыНаНаписание — затратыНаПоддержку» (упрощённо).

              И никакие доводы о важности и полезности «искусства программирования» не помогут, если «доходОтИспользования» невелик.
            0
            suckless.org/manifest/

            Рекомендую почитать, но для Ъ (прошу прощения за не местную терминологию):

            Большинство кодеров считает, что чем больше они пишут строк, тем больше работы они делают. На самом деле чем больше строк вы удаляете, тем больше вы делаете.
              0
              Прекрасный подход :) Можно лепить из глины кусочек за кусочком, а можно — взять большое глиняное бревно и поубирать все лишнее. Отличное задание на собеседование — сделать работающий код лучше. Можно взять буквально любой модуль и отдать на трепанацию и обрезание. По крайней мере, скажет о человеке ничуть не меньше, чем модуль, заново им написанный.
              0
              Если кому интересно, довольно убогая документация на язык есть здесь.

              Где «здесь»?
              0
              «Например, неверный выбор хранения строк («сишный», с 00 в конце) сделал очень дорогой доработку под использование UTF-8.»

              Чем такой формат хранения строк плох для UTF-8?
                0
                количество символов.
                  0
                  Потому что сишные функции, используемые для работы со строками, не понимают многобайтных строк. А там много что было построено на стандартных strlen, strstr и прочего добра для того, чтобы быстро работало. Переделать можно было (на всякие mb_strlen, на классы), но много было переделывать. Вот что значит — непродумали изначально. Впрочем, это не сильно мешало: создания многоязыковых систем тогда в проектах не было вообще.
                  0
                  А зачем априори знать количество символов? На практике это почти никогда не требуется без обработки всей строки.
                    0
                    К тому же в ASC2-текстом та же самая история.

                  Only users with full accounts can post comments. Log in, please.