Привет, Хабр!
На связи Андрей из сообщества ITMO.OpenSource. Мы считаем, что важно делать открытую науку, поэтому пишем об открытом коде, проводим митапы «Scientific Open Source» и разрабатываем научные решения с открытым кодом.
Мы убеждены, что открытая наука – это не просто код на github, но и совокупность факторов, которые позволяют этим кодом эффективно воспользоваться: запустить, модифицировать, внедрить в другие проекты. Поэтому я решил перевести популярную статью JS-разработчицы Киры Окли «Art of README». Несмотря на разницу в экосистемах (я пишу преимущественно на Python), мне кажется, многие идеи этой статьи актуальны для любого проекта на любом языке.
Искусство README
Этимология
Откуда взялся термин «README»?
Это название восходит минимум к 1970-м и к PDP-10, хотя может даже отсылать ко времени, когда брошюры с нацарапанным на них «READ ME!» лежали на верхушке стопок перфокарт, описывая их использование.
Один читатель предположил, что название README может быть игривым кивком в сторону «Алисы в Стране чудес» Льюиса Кэррола, где есть зелье и торт с соответствующими надписями «СЪЕШЬ МЕНЯ» и «ВЫПЕЙ МЕНЯ».
Шаблон README, написанный заглавным буквами – это историческо неизменный признак. Помимо визуальной выразительности использования заглавных букв, UNIX системы сортировали заглавные буквы перед строчными, удобно помещая README перед остальным содержимым каталога.
Посыл ясен: «Это важная информация, которую пользователь должен прочитать перед началом работы». Давайте вместе изучим, что составляет «важную информацию» в наши дни.
Для создателей, для потребителей
Это статья о README. О том, что они делают, почему они совершенно необходимы, и как их правильно оформлять.
Эта статья написана для создателей модулей, потому что ваша задача как строителя модулей – создать что-то, что будет существовать во времени. Это внутренняя мотивация, даже если автор не собирается делиться своей работой. Спустя 6 месяцев модуль без документации начинает выглядеть новым и незнакомым.
Эта статья также написана для потребителей модулей, потому что каждый автор модулей также является их потребителем. У Node очень здоровый уровень взаимозависимости: никто не живет в нижней части дерева зависимостей.
Несмотря на то, что статья сосредоточена на Node, автор утверждает, что её уроки одинаково хорошо применимы к другим программным экосистемам.
Множество модулей: одни хорошие, другие плохие
Экосистема Node питается за счёт своих модулей. npm – это магия, благодаря которой всё работает. За неделю разработчики Node оценивают десятки модулей для включения в свои проекты. Это огромное количество энергии, вырабатываемой ежедневно и готовой к использованию со скоростью, с которой вы напишете npm install
.
Как и в любой легкодоступной экосистеме, качество её модулей сильно варьируется. npm делает всё возможное, чтобы аккуратно упаковать все эти модули и распространить их вдаль и вширь. Однако найденные инструменты сильно различаются: некоторые блестят от новизны, другие – сломанные и ржавые, а ещё где-то между находятся остальные. Есть даже такие, о которых мы даже не знаем, что они делают!
У модулей это может проявляться в неточных или бесполезных названиях (есть предположения, что делает модуль fudge
?), в отсутствии документации, тестов, комментариев к исходному коду или непонятных имён функций.
У многих из них нет активного сопровождения. Если за модулем не стоит человек, готовый ответить на вопросы и объяснить, что делает модуль, и при этом не осталось никакой документации, модуль становится странным инопланетным артефактом, непригодным и непонятным для археологов-хакеров будущего.
Модули с документацией, где же они находятся в спектре качества? Возможно, у них всего лишь однострочное описание: «сортирует числа по их шестнадцатеричному значению»
. Возможно, имеется фрагмент с примером кода. Оба этих варианта лучше, чем ничего, но они обычно приводят к худшему сценарию для исследователя современных модулей: копанию в исходном коде в попытке понять, как он на самом деле работает. Писать отличную документацию – это в первую очередь держать пользователей подальше от исходного кода, предоставляя им инструкции, достаточные для использования чудесных абстракций, которые предлагает ваш модуль.
У Node «широкая» экосистема: она в основном состоит из очень длинного списка независимых однозадачных модулей, плывущих под собственным флагом. Есть исключения, но, несмотря на эти небольшие вотчины, именно простые однозадачные модули, учитывая их большое количество, действительно правят королевством Node.
У этой ситуации есть естественное следствие: может быть сложно найти качественные модули, которые делают именно то, что вам нужно.
Это нормально. Правда. Низкий порог вхождения и проблема обнаружения намного лучше, чем проблема культуры, когда участвовать могут только избранные.
К тому же, как оказалось, проблему обнаружения проще решить.
Все дороги ведут к README.md
Сообщество Node отвечает на вызов обнаружения различными способами.
Некоторые опытные разработчики Node объединяются, чтобы создать отборные списки качественных модулей. Разработчики используют свой многолетний опыт изучения сотен различных модулей, чтобы поделиться с новичками crème de la crème: лучшими модулями в каждой категории. Эта практика также может принимать форму RSS-лент и рассылок новых модулей, которые доверенные членами сообщества сочтут полезными.
А как насчет социального графа? Эта идея стимулировала создание node-modules.com, альтернативы поиска npm, которая использует ваш граф социальных связей GitHub, чтобы найти модули, которые лайкнули или создали ваши друзья.
Конечно, есть и встроенная функция поиска npm: безопасный вариант по умолчанию и обычная точка входа для новых разработчиков.
Вне зависимости от вашего подхода, независимо от того, входит ли исследователь в подземелье модулей на npmjs.org, github.com или где-то еще, этот потенциальный пользователь в конце концов посмотрит вам в лицо через README. Поскольку ваши пользователи неизбежно окажутся здесь, что можно сделать, чтобы их первые впечатления были максимально эффективными?
Профессиональное исследование модулей
README: Ваша универсальная площадка
README – это первый и, возможно, единственный взгляд потребителя модуля на ваше творение. Пользователям нужен модуль, чтобы удовлетворить его потребности, поэтому вы должны объяснить, какую именно потребность удовлетворяет ваш модуль и насколько эффективно он это делает.
Ваша задача:
рассказать им, что это за модуль (с контекстом),
показать им, как он выглядит в действии,
показать им, как пользоваться модулем,
рассказать им любые другие релевантные детали.
Это ваша работа. Создателю модуля нужно доказать, что его работа – это блестящий самоцвет в море небрежно сделанных модулей. Поскольку многие глаза разработчиков будут обращены в первую очередь к вашему README, качество здесь – это публичная мера вашей работы.
Краткость
Отсутствие README – это яркий красный флаг, но даже длинное README не сигнализирует о высоком качестве. Идеальное README должно быть как можно короче, но не короче, чем нужно. Подробная документация хороша – создайте для неё отдельные страницы! – но ваш README должен быть сжатым.
Учитесь у прошлого
Говорят, что те, кто не изучает свою историю, обречены повторять её ошибки. Разработчики пишут документацию уже довольно много лет. Было бы расточительством не взглянуть назад и не увидеть, что люди делали до Node.
Perl, несмотря на все критические замечания в его адрес, является в некотором роде духовным предшественником Node. Оба языка являются высокоуровневыми скриптовыми языками, принимают многие UNIX идиомы, питают большую часть интернета и имеют широкую экосистему модулей.
Оказывается, что монахи сообщества Perl действительно имеют большой опыт написания качественных README. CPAN - это замечательный ресурс, который стоит прочитать, чтобы узнать больше о сообществе, которое постоянно пишет высококачественную документацию.
Нет README? Нет абстракции
Отсутствие README означает, что разработчикам придётся вникать в ваш код, чтобы понять его.
У Perl-монахов есть мудрость, которой они могут поделиться по этому поводу:
Ваша документация полна, когда кто-то может использовать ваш модуль, не заглядывая в его код. Это очень важно. Это позволяет вам отделить документированный интерфейс вашего модуля от его внутренней реализации («начинки»). Это хорошо, потому что значит, что вы можете изменять внутренности модуля, сохраняя интерфейс неизменным.
Помните: документация, а не код, определяет, что делает модуль.
Ключевые элементы
Как только README будет найден, отважный исследователь модулей должен просканировать его, чтобы определить, соответствует ли он потребностям разработчика. Это по сути становится серией задач сопоставления шаблонов, где каждый шаг уводит глубже в модуль и его детали.
Допустим, например, мой поиск модуля для обнаружения 2D-коллизий приводит меня к collide-2d-aabb-aabb. Я начинаю его изучать сверху вниз:
Название – лучше всего подходят самоочевидные названия.
collide-2d-aabb-aabb
звучит многообещающе, хотя оно предполагает, что я знаю, что такое «aabb». Если имя звучит слишком неопределённо или бессвязно, это может быть сигналом к тому, чтобы двигаться дальше.Однострочник – наличие однострочного описания модуля полезно для получения представления о том, что делает модуль, в несколько большей детализации.
collide-2d-aabb-aabb
говорит, что он
Определяет, столкнётся ли движущийся ограничивающий параллелепипед (AABB) с другими AABB.
Здорово: он определяет, что такое AABB и что делает модуль. Теперь оценим, насколько хорошо он подойдёт для моего кода:
Использование – вместо того чтобы начать вникать в документацию API, было бы здорово увидеть, как модуль выглядит в действии. Я могу быстро определить, подходит ли пример JS желаемому стилю и проблеме. У людей есть много мнений о таких вещах, как промисы/колбеки и ES6. Если он подходит, тогда я могу переходить к более подробной информации.
API – название, описание и использование этого модуля звучат для меня привлекательно. Скорее всего, я буду использовать модуль уже на этом этапе. Мне просто нужно просмотреть API, чтобы убедиться, что он делает именно то, что мне нужно, и что он легко интегрируется в мою кодовую базу. Раздел API должен подробно описывать объекты и функции модуля, их подписи, возвращаемые типы, колбеки и события. Типы должны быть описаны там, где они не очевидны. Предостережения должны быть четко сформулированы.
Установка – если я дочитала до этого момента, то я готова попробовать модуль. Если есть нетипичные заметки по установке, они должны быть в этом разделе, но даже если это просто обычная команда
npm install
, я хотела бы упоминания этого. Новые пользователи постоянно начинают пользоваться Node, поэтому наличие ссылки на npmjs.org и команды установки предоставляет им возможность разобраться, как работают модули Node.Лицензия – большинство модулей ставят её в самый низ, но, возможно, было бы лучше разместить её выше; вы, скорее всего, быстро исключите модуль, если он имеет лицензию, несовместимую с вашим проектом. Обычно я придерживаюсь вариантов MIT/BSD/X11/ISC. Если у вас копилефтная лицензия, прикрепите её в самом верху модуля, чтобы избежать путаницы.
Когнитивная воронка
Порядок вышеупомянутых элементов не был выбран случайно.
Потребители модулей используют множество модулей и должны изучить множество модулей.
Когда вы просмотрели сотни модулей, вы начинаете замечать, что предсказуемые шаблоны полезны для ума.
Вы также начинаете формировать свою собственную эвристику для информации, которую вы хотите получить, и для красных флагов, быстро отсекающих модули.
Так, в README желательно иметь:
предсказуемый формат
наличие определённых ключевых элементов
Вам не обязательно использовать этот формат, но старайтесь быть последовательными, чтобы сэкономить ценные когнитивные циклы ваших пользователей.
Представленный здесь порядок с любовью назван «когнитивной воронкой», и его можно представить как воронку, удерживаемую в вертикальном положении, где самый широкий конец содержит самые обширные и более значимые детали, а движение вглубь воронки представляет более конкретные детали, которые важны только для читателя, заинтересованного в вашей работе настолько, чтобы прочитать документ так глубоко. Наконец, дно может быть зарезервировано для деталей, предназначенных только для тех, кого интригует глубинный контекст работы (история, авторство, библиография и т.д.).
И снова у Perl-монахов есть мудрость, которой они могут поделиться по этому вопросу:
Уровень детализации в документации модулей Perl обычно идет от менее детального к более детальному. Ваш раздел SYNOPSIS должен содержать минимальный пример использования (возможно, всего одну строку кода; пропустите необычные случаи использования или что-то, что не требуется большинству пользователей); DESCRIPTION должен описывать ваш модуль в общих чертах, обычно всего в нескольких параграфах; более детальное описание процедур или методов модуля, обширные примеры кода или другой глубокий материал следует представить в последующих разделах.
Идеально, если кто-то немного знакомый с вашим модулем в состоянии освежить память, не нажимая на «page down». Пока ваш читатель продолжает чтение документа, он должен получать всё больше и больше знаний.
– из perlmodstyle
Заботьтесь о времени людей
Замечательно; порядок этих ключевых элементов должен определяться тем, насколько быстро они позволяют кому-то «срезать путь» и отказаться от вашего модуля.
Звучит мрачно, не так ли? Но подумайте: ваша задача, если руководствоваться принципом оптимального альтруизма, – не «продавать» людям свою работу. Ваша задача – позволить им как можно более объективно оценить, что делает ваше творение, и решить, удовлетворяет ли это их потребностям или нет, – а не, скажем, максимизировать ваши загрузки или базу пользователей.
Этот подход нравится не всем; он требует оставить своё эго у порога и позволить работе говорить самой за себя насколько это возможно. Ваша единственная задача – описать её возможности максимально кратко,, чтобы исследователи модулей могли либо использовать вашу работу, если она подходит, либо перейти к чему-то другому.
Призыв к действию!
Вперёд, отважные исследователи модулей, сделайте свою работу заметной и полезной благодаря отличной документации!
Бонус: другие хорошие практики
Помимо ключевых моментов статьи, есть и другие практики, которым вы можете следовать (или не следовать), чтобы повысить качество вашего README и максимизировать его полезность для других:
Рассмотрите возможность включения раздела Background, если ваш модуль зависит от важных, но не широко известных абстракций или других экосистем. Идея функции bisecting-between не сразу понятна из её названия, поэтому у её описания есть подробный раздел Background, чтобы определить и связать крупные концепции и абстракции, понимание которых необходимо для её использования. Этот раздел также отличное место, чтобы объяснить мотивацию модуля, если на npm уже существуют похожие модули.
Активно используйте ссылки! Если вы говорите о других модулях, идеях или людях, вставьте ссылку, чтобы посетители могли легче понять ваш модуль и идеи, на которых он основан. Мало модулей существуют в вакууме: все работы идут от других работ, поэтому полезно, чтобы пользователи могли следить за историей и вдохновением вашего модуля.
Включите информацию о типах аргументов и возвращаемых параметров, если это не очевидно. Предпочитайте соглашения, где это возможно (
cb
, вероятно, означает колбек-функцию,num
, вероятно, означаетNumber
и т. д.).Включите пример кода в раздел Usage как файл в вашем репозитории – возможно, как
example.js
. Отлично, когда у README есть код, который пользователи могут реально запустить после клонирования репозитория.Будьте разумны в использовании значков. Ими легко злоупотребить. Они также могут стать основой для бесконечных споров и обсуждений. Они добавляют визуальный шум в ваш README и, как правило, работают только в том случае, если пользователь читает ваш Markdown в браузере, так как изображения часто размещаются где-то в интернете. Для каждого значка подумайте: «какую реальную ценность этот значок предоставляет типичному зрителю этого README?» У вас есть значок CI, чтобы показать статус сборки/теста? Этот сигнал лучше подать важным лицам, отправив им письмо или автоматически создав вопрос. Всегда учитывайте аудиторию данных в вашем README и спрашивайте себя, есть ли поток для этих данных, который может лучше достичь его предполагаемой аудитории.
Форматирование API – предмет интенсивных дискуссий. Используйте любой формат, который, по вашему мнению, наиболее понятен, но убедитесь, что ваш формат выражает важные тонкости:
a. какие параметры являются необязательными, и их значения по умолчанию
b. информация о типах, где это не очевидно из соглашения
c. для параметров объекта
opts
, все принимаемые ключи и значенияd. не стесняйтесь предоставлять небольшой пример использования функции API, если это не очевидно или полностью покрыто в разделе Usage. Однако это также может быть явным сигналом, что функция слишком сложная и её нужно рефакторить, разбивать на более маленькие функции или полностью удалять.
e. активно добавляйте ссылки на специализированную терминологию! В markdown вы можете сохранять сноски в нижней части документа, так что ссылаться на них несколько раз становится проще. Некоторые мои личные предпочтения по форматированию API можно найти здесь.
Если ваш модуль представляет собой небольшую коллекцию функций без состояния, то раздел Usage в виде сессии Node REPL с вызовами функций и результатами может более наглядно донести способ использования, чем исходный код файла для запуска.
Если ваш модуль предоставляет CLI (интерфейс командной строки) вместо (или в дополнение к) программному API, показывайте примеры использования в виде команд и их вывода. Если вы создаете или изменяете файл, используйте команду
cat
, чтобы продемонстрировать изменения до и после.Не забывайте использовать ключевые слова в
package.json
, чтобы направить искателей модулей к вашему проекту.Чем чаще вы меняете свой API, тем больше усилий вам придется приложить для обновления документации – подразумевается, что вы должны с самого начала сделать свои API маленькими и определенными. Требования со временем меняются, но вместо того чтобы загружать предположения в API ваших модулей, загрузите их на один уровень абстракции выше: в сам набор модулей. Если требования всё-таки меняются и какой-то однозадачный модуль больше не имеет смысла, просто напишите новый модуль, который делает то, что вам нужно. Однозадачный модуль остается действительной и ценной моделью для экосистемы npm, а ваша корректировка стоила вам лишь простую замену одного модуля на другой.
Наконец, помните, что ваш репозиторий управления версиями и встроенный в него README переживут хостинг вашего репозитория и все то, на что вы делаете гиперссылки – особенно изображения – поэтому вставляйте в текст всё, что будет важно для будущих пользователей для понимания вашей работы.
Бонус: common-readme
Не случайно, что этот формат также используется в common-readme, наборе рекомендаций по написанию README и удобного генератора командной строки. Если вам нравится написанное здесь, вы можете сэкономить время, используя common-readme
для написания README. Вы также найдете реальные примеры модулей с этим форматом.
Вам также может быть интересен standard-readme, который представляет собой более структурированный, проверяемый формат общего README.
Бонус: Образцы
Теория хороша и полезна, но как выглядят отличные README? Вот некоторые, которые, по моему мнению, отлично воплощают принципы данной статьи:
Бонус: README-чеклист
Вот полезный чеклист, который поможет оценить, насколько хорош ваш README:
Однострочное объяснение цели модуля
Необходимый контекст и ссылки на фоновую информацию
Потенциально незнакомые термины должны быть связаны с информативными источниками
Чёткий и исполнимый пример использования
Инструкции по установке
Обширная документация API
Использование когнитивной воронки
Указание предостережений и ограничений с самого начала
Не полагайтесь на изображения для передачи критической информации
Лицензия
Об авторе
Привет, я Кира.
Этот небольшой проект начался в мае в Берлине на squatconf, где я изучала, как Perl-монахи пишут свою документацию, и также жаловалась на состояние README в экосистеме Node. Это побудило меня создать common-readme. Однако раздел «Советы по README» был переполнен советами, поэтому я решила собрать их в полезную статью о написании README. Так родилось Art of README!
Для дальнейшего чтения
Прочие источники
Некоторые читатели предложили другие полезные ресурсы для составления README:
Лицензия
Creative Commons Attribution License
Перевод
Андрей Гетманов, активист движения ITMO.OpenSource
Post scriptum
Мы адаптировали различные подходы к созданию README и создали шаблон для научных проектов. Надеемся, он будет вам полезен!