20 мая 2012 г.

Тестирование и документирование

Я тут осознал, что сильно недооценивал роль примеров (examples) для технической документации. Документация очень сильно выигрывает от хороших примеров. Продуманные примеры могут быстро сориентировать читателя – ввести в курс дела, и облегчить понимание более детального описания. Более того, хорошо подобранные примеры способны сходу предоставить читателю (= пользователю) решение конкретной проблемы, без необходимости вообще вникать в детали. Вообще, кажется, есть много сценариев, где наиболее практичная документация == правильно подобранный набор примеров с краткой аннотацией.

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

Документация через примеры – дешевле

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

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

Замена текста на продуманные примеры – выглядит как одна из таких возможностей.

Я за собой не раз замечал, что читаю документацию по диагонали, выискивая глазами примеры – если я примерно ориентируюсь в теме, то мозг понимает примеры легче, чем текст. И вряд ли я один такой – скорее всего многие используют доки похожим образом. И если предположить, что люди все равно будут выискивать в доке примеры – так почему бы не облегчить им эту задачу? Ведь примеры могут быть и короче текстового объяснения, и полезнее практически, и легче восприниматься.

Как может выглядеть документация через примеры

На самом деле это не то, чтобы революционная идея, и я далеко не первый, кто об этом подумал. Вот, например, известный сайт Oh shit, git организован похожим образом: короткий заголовок-проблема – и сразу код решения, с аннотацией.

Другой пример это документация по JMH, которая тоже организована как набор примеров нарастающей сложности, с аннотациями. Но аннотации тут вряд ли повернется язык назвать краткими: текстовых аннотаций к примерам раза в 3 больше, чем кода. Вероятно, это потому, что тема бенчмаркинга достаточно сложная сама по себе, и документация JMH пытается решить сразу 2 задачи: не только объяснить, как пользоваться JMH, а прежде всего объяснить, в чем вообще сложности бенчмаркинга кода для JVM, и почему для этого нужен специальный инструмент.

А вот man-ы это контр-пример, они почти всегда устроены наоборот: бОльшая часть содержимого это подробное текстовое описание разных флагов и их комбинаций. А примеры если и есть, то единичные, и только в самом конце. Для меня это удивительно: по-моему, man-pages были бы гораздо удобнее и полезнее, если бы там сначала шел набор 5-7 практических примеров, а потом уже подробности1.

Я попробовал активнее использовать примеры в своих рабочих доках: вместо обычного текстового описания "как это все работает" стал давать один абзац введения в контекст ("о чем тут вообще речь"), и 3-5-7 практических примеров, с коротким комментарием к каждому – только потом уже детали и подробности. Что-то вроде:

Script builds and (re-)deploys application X from source code. Allows full and per-component deploys:

deploy.sh -c f459dca       # redeploy everything from git commit f459dca
deploy.sh -b release14     # redeploy everything from git branch release14

deploy.sh -c f459dca -d    # redeploy database only, from git commit hash
deploy.sh -c f459dca -a    # redeploy application only...
deploy.sh -c f459dca -w    # redeploy web-UI only...

…Дальше можно уже описывать детали, проблемы, и сложные сценарии…

(Пример куцый, но более реальные примеры под NDA)

Не сказать, чтобы я очень много документации успел таким образом оформить, но результат выглядел многобещающе. Что я заметил:

  • По-моему, так оформленные инструкции гораздо удобнее читать: если хорошо подобрать эти 5-7 примеров, то многие читатели находят решение своей конкретной задачи тут же, в примерах – и не будут тратить время на не нужные им сейчас детали.

    (Я сам не раз обращался к своей документации, чтобы вспомнить какой-нибудь набор флагов под конкретную задачу – и было гораздо удобнее увидеть нужный пример сразу, вверху страницы, чем тратить время на поиск его где-то среди нескольких страниц подробного описания)

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

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

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

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

    Но это и плюс: я заметил, что пока я думаю над подбором примеров, я настраиваюсь смотреть на документацию с позиции читателя – что читателю может быть нужно? И это полезная перспектива, из нее проще понять, о чем писать дальше, после примеров (и нужно ли еще о чем-то писать)2.

  • Я не успел толком опробовать, но кажется, что примеры проще поддерживать в актуальном состоянии: в текст нужно вчитаться, подумать над ним, чтобы понять, не устарел ли он – а пример можно просто выполнить и проверить, делает ли он что заявлено.

Конечно, такой подоход не для всех видов документации подойдет – вряд ли одними только примерами можно описать архитектуру системы, или даже операционное использование сколько-либо сложного приложения целиком. Но HowTo-инструкция к конкретной утилите или конкретному процессу – вполне.

Ценность примеров в программной индустрии выше, чем в других областях

Хочется немного порассуждать насчет использования примеров в технической документации.

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

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

Если вы читаете руководство по ремонту квартиры, и видите там пример процедуры поклейки обоев, то вы не можете кликнуть по этому примеру и сказать "применить" на свои собственные обои. Или вот я читаю руководство по написанию отчетов, и там масса примеров – но ни один из них я не могу применить к своим задачам непосредственно. Даже если примеры прямо из моей предметной области – все равно, как правило, я не могу их прямо использовать. Мне нужно изучить эти примеры, извлечь из них какое-то понимание, и только потом я смогу это понимание применить для решения своих задач.

А в программировании (и смежных software-defined областях) сплошь и рядом можно сделать Ctrl+C, Ctrl+V, немного подправить, Enter – и вот уже пример решил мою задачу.

Такую "разработку с помощью copy-paste", часто критикуют за то, что человек вроде бы способен что-то сделать, но у него нет фундаментального понимания, что именно он делает.

Критика небезосновательна, но не стоит с водой выбрасывать ребенка: в этом же и сила программной инженерии. Разве не круто было бы клеить обои с помощью copy-paste-enter: выбрал подходящий алгоритм поклейки, скопировал-вставил-выполнил его для своей квартиры – вуаля, обои поклеены? Будь это возможным – стали бы вы критиковать этот метод за то, что он провоцирует поверхностность, и не дает глубокого фундаментального понимания физхимии процессов адгезии?

Если вы когда-нибудь клеили обои – уверен, что не стали бы.

Могут ли примеры полностью заменить объяснение?

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

Разверну мысль: обычно предполагается, что примеры дополняют объяснение. То есть чтобы что-то объяснить, нужно именно объяснение – текстовое, визуальное, неважно – а примеры это важное, но лишь дополнение к этому объяснению.

Но недавно я поймал себя на том, что для простых идей, простых моделей – объяснение не очень-то и нужно. Я уже писал выше: фактически, общее объяснение-описание я часто пропускаю, ищу сразу примеры – и их часто достаточно для понимания.

Я для себя это объясняю так: когда мозг видит примеры, он автоматически пытается вычленить в них закономерности, т.е. обобщить примеры в абстрактную модель. Потому что подмечать закономерности – одна из основных функций мозга. И если за примерами стоит простая модель, простая закономерность, и примеры подобраны продуманно (репрезентативны) то мозг без проблем догадается до этой модели – обобщит из примеров.

Получается – в простых случаях – что в связке текст+примеры текст не особо и нужен, читать его – чуть ли не лишняя работа. Достаточно посмотреть примеры, и в голове останутся и примеры, и автоматически извлеченное из них "объяснение" (общая модель). И никаких дополнительных усилий на это не тратится, потому что процесс обобщения все равно происходит, независимо от моего желания.

(Еще раз повторю, что только гипотеза: мне кажется, что она может быть полезной, но может быть моей личной галлюцинацией)

Если это работает, то только для простых моделей, и хорошо подобранных наборов примеров – попробуйте обобщить фундаментальные физические законы из набора частных случаев, если вы не Ньютон (Максвелл, Эйнштейн, Шредингер…). Вероятно, поэтому в учебниках физики все-таки дают и уравнения, и текстовые объяснения, и разбирают множество частных примеров :)

И тут мне снова видится особенность программной инженерии: многие "модели", которые мы описываем в документации – простые, да еще и часто похожи между собой. Чтобы пользоваться gzip-ом не обязательно ни знать алгоритм Lempel-Ziv, ни даже помнить все его флаги. У любого хорошего API одна из задач – скрывать сложности реализации, и предоставлять пользователю простую поверхностную модель. Не каждый API с этой задачей справляется, да – но если справляется, то его "простую поверхностную модель" может быть удобно описывать именно продуманным набором кратко аннотированных примеров.

Так что когда речь идет о модели "как пользоваться gzip", или "как пользоваться REST API нашего сервиса" – может быть, что 5-10 примеров гораздо быстрее дадут читателю представление об общей структуре вашего API, чем текстовое описание отдельных флагов/REST endpoints.

Если же тема сложная, то конечно нужно обобщеное, абстрактное объяснение-описание, причем часто – несколько таких описаний, разных уровней абстракции. Но даже в этом случае может быть полезно хотя бы начать объяснение с простой модели, и постепенно уточнять и разворачивать ее (aka 'progressive GIF/JPEG rendering'). А вот эту простую стартовую модель можно попробовать описать … (смотри выше)…

Примечания

  1. Как мне подсказал друг в твиттере, существует проект tldr.sh – альтернатива man, ориентированная на примеры. Судя по количеству контрибьютеров и звезд на гитхабе – проект весьма популярен и активно развивается. К моему удивлению, даже на мак ставится без сучка: brew install tldr↩︎

  2. А бывает, что как ни думай, а хорошие примеры подобрать не получается, потому что система так построена, что пользоваться ей неудобно, и объяснять, как ей пользоваться – тяжело. Примеры для простых вещей неестественно сложны, и друг другу противоречат. Это еще одна полезная функция документации, о которой я когда-то уже писал: создание документации дает ценную обратную связь о дизайне системы – подобно тестам. Мне приходилось заметно переделывать какие-то утилиты, когда я попытался написать к ним инструкцию, и обнаруживал, что просто не могу описать их функционирование простым человеческим языком.↩︎

3 комментария:

  1. А ты что, сначала пишешь код, а потом уже тесты с документацией?

    ОтветитьУдалить
  2. Еще круче -- я вообще не пишу ни тестов, ни документации. Я пишу идеальный код -- он не нуждается ни в том, ни в другом.

    Вообще-то, я и код частенько не пишу -- я пишу статьи про то, как его надо писать ;)

    ОтветитьУдалить
  3. yo dawg, i heard you liked articles, so i wrote an article on how to write articles about writing articles

    ОтветитьУдалить