Литературное программирование

Table of Contents

Table of Contents

Эпиграф

Слова ниже взяты из интервью Дональда Кнута, которое Эндрю Бинсток взял у него в апреле 2008. Я позволю себе большую цитату:

Лично для меня literate programming - это наиболее важная вещь, вышедшая из проекта TeX. Этот подход не только позволил мне писать и поддерживать программы быстрее и надежнее, чем когда бы то ни было раньше, и он не только был для меня самым большим источником удовольствия, начиная с 1980-х гг. - он иногда оказывался незаменимым.

Некоторые из моих основных программ, такие как метасимулятор MMIX, не могли бы быть написаны с применением любой другой методологии, о которой я когда-либо слышал. Сложность была просто чересчур устрашающей, чтобы с ней можно было справиться на основе моих ограниченных умственных возможностей; без применения literate programming все предприятие потерпело бы полную неудачу. Literate programming - это то, что требуется для превышения обычного уровня достижений. Но я не считаю разумным навязывание идей кому бы то ни было. Если грамотное программирование - это не ваш стиль, забудьте о нем и делайте то, что вам нравится. Если этот подход не будет нравиться никому, кроме меня, пусть он умрет.

Мой опыт показывает, что программное обеспечение, созданное на основе грамотного программирования, оказывается существенно лучше, чем разработанное с применением более традиционных методов. Тем не менее, обычное программное обеспечение, как правило, оказывается неплохого качества – я поставил бы ему оценку C (или, может быть, C++), но не F; следовательно, традиционные методы остаются с нами. Поскольку эти методы усвоены огромным сообществом программистов, у большинства людей нет большого стимула к их изменению, равно как у меня нет мотивации для изучения эсперанто, хотя этот язык мог бы быть предпочтительнее английского, немецкого, французского или русского языков (если бы все на него перешли).

Он продолжает пользоваться этим подходом и сегодня: "…Что касается текущих каталогов в моей машине, в этом году я пока написал 68 разных CWEB-программ. В 2007-м году их было 100, в 2006-м - 90, в 2005-м - 100, в 2004-м - 90 и т.д."

Суть подхода

…раскрывается в его статье "Literate Programming", написанной в 1983 г:

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

Я не в силах противостоять желанию поработать над задачами по программированию, которые я обычно поручаю помощникам-студентам - и почему? Потому что мне кажется, что наконец я могу писать программы так, как они и должны быть написаны. Мои программы не только объяснены лучше чем когда-либо прежде; они лучше как программы, потому что новая методология заставляет меня делать свою работу лучше.

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

Затем два инструмента принимают на вход "литературный" исходник на и выдают - один чистый код, второй - красиво отформатированную статью-документацию.

nil

Кнут выдумал это очень давно, и его оригинальные инструменты работают на основе его же собственного TeX'а (т.е. программист пишет свой исходник-эссе пользуясь TeXовой разметкой), но сегодня есть варианты для, например, "вики-синтаксиса".

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

Это - огромная проблема. Человеческий мозг начинает уставать после первых 1000-1300 строчек. Приходится сосредоточиваться значительно сильнее чтобы все вещи держать в голове и не делать ошибок. Далее приходится вводить особые способы деления на куски, выдумывать новые абстракции более высокого уровня чтобы затем писать на "новом языке" и т.д.

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

Кнут, вполне естественно, предложил для текста TeX. Кроме того, в тот момент он использовал язык программирования Pascal, строгость которого усугубляется требованием однопроходной компиляции. Из-за этого в обычной программе порядок определения функций, типов и переменных строго фиксирован, что противоречит требованию понятности изложения.

Так что Дональду Кнуту пришлось написать свою систему WEB, которая устроена примерно так: программа состоит из кусочков (chunks) документации, чередующихся с кусочками кода. В кусочках кода можно ссылаться на другие кусочки, причем ссылки могут идти и вперед, и назад, а на один кусочек может быть несколько ссылок. Получается своего рода сеть, отсюда и название, которое потом использовали для похожей структуры документов в интернет.

Чтобы такую программу можно было использовать, есть две утилиты - tangle, которая вытаскивает кусочки кода, подставляет их на место ссылок и формирует программу, которую можно скомпилировать, и weave , которая форматирует кусочки кода командами TeX и создает документ TeX, который можно распечатать. Сам TeX и написан таким образом, а человеко-читаемая версия вышла в виде книги "TeX: The program".

О проекте TeX

Надо сказать немного о проекте TeX.

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

Весь проект TeX вырос из задачи одного человека (самого Дональда Кнута) по созданию книги всей его жизни - TAOCP (The Art Of Computer Programming - Искуство Программирования).

Первый том книги "Искусство программирования" Д. Кнута был опубликован в 1969 году и печатался методом монотипии, технологии XIX века, которая давала на выходе издание в «хорошем классическом стиле», что нравилось Кнуту. Когда в 1976 году публиковалось второе издание второго тома, всю книгу пришлось набирать вновь, поскольку монотипия почти повсеместно была замещена фотографической техникой, и оригинальные шрифты больше не использовались. Однако 30 марта 1977 года, когда Кнут получил новые оттиски, он увидел, что они выглядят ужасно. Примерно в это же время Кнут впервые увидел результат работы высококачественной цифровой типографической системы и заинтересовался возможностями цифровой типографии. Не оправдавшие ожиданий оттиски дали ему дополнительный толчок к тому, чтобы, разработав свою типографическую систему, решить проблему раз и навсегда. 13 мая 1977 года он написал заметку самому себе, описывающую базовые возможности TeX'а.

Он планировал завершить систему во время своего творческого отпуска 1978 года, оценив, что ему потребуется приблизительно 6 месяцев на завершение разработки. На самом деле разработка была полностью завершена более чем через 20 лет - что и неудивительно, ведь до TeX копьютерных издательских систем просто не существовало - Дональд Кнут встретился с проблемой, которую еще никто не решал.

TeX содержит более 100.000 строк - это проект коллосального размера, и это при том, что он не включает в себя систему векторных шрифтов METAFONT. За каждую ошибку, найденную в TeX, автор выплачивает один шестнадцатеричный доллар, то есть $2,56 (0x100 центов, в системе счисления по основанию 16). Последняя ошибка была найдена так давно, что что мне не удалось найти упоминание об этом событии.

TeX, одна из самых сложных программ в мире, может считаться едва ли не единственной на сегодняшний момент "почти безошибочной" программой и работает на любом компьютере, включая древние 286-е и КПК. Это чудо человеческого гения. Сам Д. Кнут говорит, что без Литературного Программирования этот проект был бы невозможен.

Современное состояние

Детализация

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

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

Стиль C и C++:

for ( ic=0, ic<MaxCusts, ic++ )
  if ( Cust[ic].age > 18 ) itc_drupal_
...

Стиль Литературного программирования:

@<Для каждого из зарегистрированных потребителей, достигшего совершеннолетия>@

Синтаксически языки Литературного Программирования крайне просты и представляют собой небольшой перечень правил записи объединения высокоуровневых фрагментов псевдокода, допускающего описание программы на естественном языке, и фрагментов-"реализаций" этого псевдокода, в которых последний "реализуется" на некотором языке программирования.

Семантика языка ЛП, несмотря на простоту синтаксиса, куда более сложна. Фактически она формирует принципиально новую парадигму программирования, не зависящую (или минимально зависящую) от языка реализации программы.

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

Пора объяснений

Во всех материалах, посвященных ЛП, очень трудно отделить концептуальную часть от реалий применений. Впрочем, этим грешат все описания методологий, концепций и парадигм программирования - чтобы по-настоящему "почувствовать вкус", требуется реальный пример, а не программа класса "Hello, world", ведь материал адресуется тем, для кого базовый уровень программирования - давно пройденный этап.

Псевдокод литературных программ фактически представляет собой описание структуры будущего программного проекта. Абсолютно неформальное, допускающее включение математических формул, иллюстраций, чего угодно — вплоть до мультимедийных "вставок", такое описание-документация "по ходу дела" дополняется новыми фрагментами псевдокода и фрагментами-"реализациями".

При этом ЛП-программист не должен следить за сложной в больших программах "адресацией" — соответствием команд псевдокода и фрагментов-"реализаций", так как сами фразы на псевдокоде являются "адресом". То есть, если где-то в ЛП-программе встретилась фраза псевдокода:

@< Вывод сообщения об ошибке >@

впоследствии программист может "овеществить" ее следующим фрагментом-"реализацией":

@< Вывод сообщения об ошибке >@=
prints("Error!n);

Располагаться это "овеществление" может в тексте ЛП-программы где угодно, и если впоследствии реализующий псевдокод фрагмент кода по каким-то причинам надо изменить, достаточно произвести такое изменение только в фрагменте-"реализации".

Задача инструментов, поддерживающих ЛП-программирование, - преобразование программы на ЛП-языке в текст, пригодный к трансляции в исполняемый код, и одновременное формирование качественной документации в том или ином представлении.

Дискуссии

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

Все предпосылки для развития инструментария литературного программирования есть: во-первых, методология Литературного Программирования работает, что доказано ее успешным применением не в одном реальном проекте; во-вторых, рост популярности открытого ПО остро ставит проблему качества документации; в-третьих, инструментарий весьма прост.

Объекты Литературной Программы - фрагменты псевдоязыка - могут адресовать другие объекты и при этом включать дополнительные описания фрагментов реальных программ. Идеально соответствующая фреймовому представлению знаний картина, позволяющая говорить об Литературной Программе как о высокоуровневой базе знаний.

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

Место в индустрии

Определить место Литературного Программирования в современной индустрии разработки программного обеспечения непросто - в отличии от разрекламированных "Гибких методологий", SCRUM, экстремального программирования и тому подобных вещей, часто походящих на религиозный культ, Литературное Программирование выглядит как набор утилит GNU - и остается незаметным, продолжая верно служить одной простой цели - управлению сложностью программы.

Литературное программирование само по себе не способно обогатить своего евангелиста или его работодателя, поэтому проповедовать его не выгодно, более того, в современной индустрии таковое программирование есть прямое финансирование конкурентов.

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

Если вы не верите моим словам и анализу, может вы поверите Дональду Кнуту? Вот несколько выдержек из его интервью в отличной книге Петера Зибеля (Peter Siebel) «Coders at Work»:

"Что меня действительно волнует, так это то, что сейчас в основном программирование превратилось во встраивание магических заклинаний: вы берёте куски чужого кода, делаете магические пасы и запускаете. В этом нет чего-то креативного или творческого. И это становится слишком скучным, потому что у вас нет возможности сделать ничего особого нового. Ваш эмоциональный профит – получить удовольствие от того, что из машины вышел хороший позитивный результат. Но это совсем не то, когда вы создаёте что-то новое. Сейчас сам процесс превратился в скучную рутину, а радость можно получить только от результата работы. Но сама работа не должна быть скучной! Это неправильно."

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

Массовый рынок требует слишком много программ "сразу и сейчас", а для разработки такого количества ПО просто невозможно найти необходимое количество программистов класса Д. Кнута.

И все-таки области, где применение идей Литературного Программирования не теряет своей актуальности, никуда не исчезают — управляющие программы для встраиваемых систем, высоконадежные программные комплексы класса "mission critical", критическое системное ПО и, наконец, - "открытое ПО".

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

Таким образом, Литературное Программирование остается своего рода "мечом джедая" в современном мире - оружием сложным, не модным, но удивительно эффективным в умелых руках.

Современные расширения

Я использую современную систему для литературного программирования, встроенную в emacs. Она позволяет не только комбинировать кусочки (chunks) литературного исходника, но и заменять любой кусочек функцией, которая его генерирует.

Строго говоря, мне неизвестно, есть ли эта функциональность в оригинальном WEB и CWEB, я предполагаю, что такая очевидная идея должна была быть реализована.

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

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

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

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

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

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

Примеры использования подхода

  • TeX и METAFONT
  • Большая часть GHC (Glasgow Haskell Compiler)
  • Axiom - свободная система компьютерной алгебры общего назначения. Она состоит из среды интерпретатора, компилятора и библиотеки, описывающей строго типизированную, математически правильную иерархию типов.
  • http://zahardzhan.github.io/well-tuned-emacs/
Яндекс.Метрика
Home