Pull to refresh

Создание документации в .NET

Reading time 12 min
Views 54K
Open notebookКачественная документация – неотъемлемая часть успешного программного продукта. Создание полного и понятного описания всех функций и возможностей программы и программного компонента требует немало сил и терпения. В данной статье я рассмотрю некоторые практические аспекты создания документации для .NET компонентов.

Предположим, что у нас готова или почти готова некоторая .NET библиотека для разработчиков (они же конечные пользователи). API библиотеки безупречен, количество багов впечатляюще мало, да и вообще это не библиотека, а просто кладезь совершенного кода. Дело за малым – объяснить пользователям, как работать с этим замечательным продуктом.

Есть разные подходы к написанию документации. Некоторые команды предпочитают начинать создание документации в момент начала создания продукта. Другие откладывают написание мануалов на окончание работ. В некоторых командах документацию пишут специальные люди, которые ходят от разработчика к разработчику и от менеджера к менеджеру, аккумулируя знания о продукте. Во многих небольших командах таких специальных людей нет, а потому документацию часто пишет разработчик или разработчики. Кто-то использует сторонние средства вроде Help & Manual, в которых, как в заправском текстовом редакторе, можно создавать очень сложную верстку и на выходе получать документацию в многообразии форматов. Многие используют другой подход, широко пропагандируемый в последнее время – написание документации прямо в коде программы/библиотеки.


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

Описываем API


Компиляторы C# и VB.NET умеют распознавать комментарии, оформленные специальным образом (xml комментарии) и при необходимости создавать xml файл, который можно потом использовать для создания документации. Чтобы воспользоваться этой возможностью необходимо описать все публичные классы и методы с помощью xml комментариев. Выглядит это примерно так:
/// <summary>
/// Gets the R component from ABGR value returned by 
/// <see cref="O:BitMiracle.LibTiff.Classic.Tiff.ReadRGBAImage">ReadRGBAImage</see>.
/// </summary>
/// <param name="abgr">The ABGR value.</param>
/// <returns>The R component from ABGR value.</returns>
public static int GetR(int abgr)
{
    return (abgr & 0xff);
}

По умолчанию создание xml-файла из комментариев отключено. Его нужно включить в свойствах проекта на вкладке Build.
Enable Xml comments

В результате при компиляции, в дополнение к файлу вашей сборки, будет сгенерирован xml-файл, который содержит все xml-комментарии из кода (в том числе комментарии к непубличным структурам). Этот файл уже сам по себе полезен тем, что если его положить рядом со сборкой (вашей dll), то это позволит функции IntelliSense в Visual Studio отображать описания для методов в момент набора пользователем кода. Вот пример того, как это будет выглядеть для функции GetR, показанной выше:
image

Однако в большинстве случаев сгенерированный xml-файл содержит комментарии к внутренним структурам, которые пользователям не нужно или нельзя видеть. Ниже я напишу, как автоматически очистить xml-файл так, чтобы в нем остались только описания к публичным методам.

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

Тег summary служит для краткого описания назначения класса, интерфейса, перечисления (enum), методов и свойств класса или интерфейса и членов перечисления. Тег param позволяет описать параметр, принимаемый функцией. Этот тег нужно использовать для каждого принимаемого параметра. Тег returns используется для описания возвращаемого значения функции. Тег value полезен для описания значения, которое принимает и/или возвращает некоторое свойство. В некотором смысле тег value является аналогом тега returns.
/// <summary>
/// Gets the font ascent.
/// </summary>
/// <value>The font ascent.</value>
/// <remarks>Ascent is the maximum height above the baseline reached
/// by glyphs in this font, excluding the height of glyphs for
/// accented characters.</remarks>
public short Ascent
{
    get
    {
        return Impl.Ascent;
    }
}

Очень полезным (и, к сожалению, часто игнорируемым) является тег remarks, который позволяет указать примечания к описываемой сущности. Этот тег можно использовать практически везде кроме описания членов перечисления. На самом деле для членов перечисления тоже можно, но в документации, оформленной в стиле vs2005, этих примечаний просто не будет видно, что уменьшает полезность таких примечаний.

Приведу еще несколько практических замечаний/рекомендаций.

Скачайте и установите расширение для Visual Studio под названием GhostDoc. Это расширение работает во всех версия студии (начиная с версии 2005) и сильно упрощает создание xml комментариев. По нажатию на Ctrl-Shift-D это расширение вставляет описание сущности, на которой в данный момент стоит курсор. Вставляются все необходимые теги, и генерируется текст описания на основе, например, названия метода и названия его параметров. Часто остается лишь откорректировать и дополнить сгенерированный текст.

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

Если у вас есть несколько перегруженных методов, то при генерации документации для них будет создана отдельная страница (вот пример такой страницы). Текст для этой страницы нужно указать в теге overloads в описании одного из перегруженных методов.
/// <summary>
/// Saves the font bytes to the specified stream.
/// </summary>
/// <param name="stream">The stream to save font bytes to.</param>
/// <overloads>Saves the font bytes to a file or a stream.</overloads>
public void Save(Stream stream)
{
    Impl.Save(stream);
}

Если вы хотите в описании одного метода дать ссылку на другой метод или тип, то нужно использовать конструкцию вида <see cref="X:MEMBER">Текст ссылки</see>, где X – необязательный префикс, обозначающий тип сущности (T для класса, M для метода, P для свойства, O для группы перегруженных методов), а MEMBER – полная или частичная спецификация сущности. Частичную спецификацию и отсутствующий префикс можно использовать, например, для ссылок между двумя методами одного класса или между двумя сущностями одного пространства имен (namespace).

Пример использования частичной спецификации (PdfFontEmbedStyle находится в одном пространстве имен с PdfFont):
public sealed class PdfFont
{
    …
    /// <summary>
    /// Gets or sets the <see cref="PdfFontEmbedStyle"/> value that specifies
    /// how this font is embedded into the document.
    /// </summary>
    /// <value>The <see cref="PdfFontEmbedStyle"/> value that specifies
    /// how this font is embedded into the document.</value>
    public PdfFontEmbedStyle EmbedStyle
    {
        get
        {
            return Impl.EmbedStyle;
        }
        set
        {
            Impl.EmbedStyle = value;
        }
    }
}

Если вы ссылаетесь на сущность из другого пространства имен, на группу перегруженных методов или на какой-то определенный метод из группы перегруженных методов, то нужно обязательно использовать полную спецификацию. Примеры полной спецификации:
  • ссылка на свойство
    <see cref="P:System.Exception.HResult"/>
  • ссылка на метод
    <see cref="M:BitMiracle.LibTiff.Classic.Tiff.GetR(System.Int32)"/>
  • ссылка на группу перегруженных методов
    <see cref="O:BitMiracle.LibTiff.Classic.Tiff.PrintDirectory"/>
  • ссылка на класс
    <see cref="T:BitMiracle.LibTiff.Classic.TiffTagMethods"/>

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

Со ссылками на группу перегруженных методов связана одна неприятность. Visual Studio требует, чтобы такие ссылки были вида O:XXX.YYY, в то время как Sandcastle Help File Builder требует, чтобы такие ссылки были вида Overload:XXX.YYY. Для решения этой проблемы я использую простой скрипт, который вызывается на Post-build event и заменяет в xml-файле O: на Overload:, что вполне терпимо.

Для ссылки на некоторую внешнюю статью вашей документации (не связанную с описанием API) или на некоторый ресурс в Интернет используйте старый добрый тег <a> с атрибутом href. Например, <a href = "54cbd23d-dc55-44b9-921f-3a06efc2f6ce.htm">Текст ссылки</a> или <a href = "http://site.com/page.html">Текст ссылки</a>. В первом примере имя документа с внешней статьей представлено в форме “TOPIC_ID.htm”. О том, что такое topic id, речь пойдет далее.

Более глубоко ознакомиться с документированием кода с помощью xml комментариев можно в этих статьях:


Генерируем файл документации


После того, как xml-описание вашего компонента готово, можно сгенерировать файл документации. Я предпочитаю для этого использовать связку Sandcastle + Sandcastle Help File Builder (SHFB). Замечу, что некоторым больше по душе DocProject. Для этого требуется:
  1. Скачать и установить Sandcastle
    sandcastle.codeplex.com
  2. Скачать и установить Sandcastle Help File Builder
    shfb.codeplex.com
  3. Скачать и применить патч для стилей, используемых Sandcastle
    sandcastlestyles.codeplex.com
  4. Если у вас возникнут проблемы со сборкой документации в формате HTML Help, то нужно проверить, что itircl.dll присутствует в системе и зарегистрирована. Обычно эта dll лежит в System32, регистрировать ее нужно через regsvr32. Подробнее написано тут:
    frogleg.mvps.org/helptechnologies/htmlhelp/hhtips.html#hhc6003

Приступаем к сборке документации в формате chm. Для этого запускаем Sandcastle Help File Builder и настраиваем Project Properties. В свойстве “ComponentConfigurations” можно настроить дополнительные компоненты, используемые при сборке. Если вы не знаете, какие компоненты вам могут быть нужны, то можно выбрать все компоненты. В любом случае я рекомендую всегда использовать IntelliSense Component, так как он автоматически создает копию входного xml-файла, очищенную от всех непубличных комментариев. Именно результат работы этого компонента нужно давать пользователям, а не тот xml-файл, который создаст компилятор.

Также я рекомендую сразу поменять следующие свойства:
  • секция Build: FrameworkVersion
  • секции Help File: CopyrightHref, CopyrightText, FeedbackEMailAddress, FeedbackEMailLinkText, HelpTitle, HtmlHelpName
  • секция Paths: OutputPath

Далее в окне Project Explorer добавляем Documentation Sources. Рекомендую выбирать здесь конкретную сборку и xml файл с комментариями для нее, а не файл C#/VB.NET проекта. Если выбрать файл проекта, то иногда возникает проблема с тем, что изменения в xml-комментариях не отражаются в документации. Кто в этом виноват, я не знаю.

Еще один важный шаг – описать пространства имен (namespace-ы) в SHFB. Xml комментарии в коде не работают для namespace-ов, поэтому нужно это сделать вручную. Тут поможет секция Comments и свойство NamespaceSummaries в ней. В описании namespace-ов можно использовать стандартные html теги.
image
Настройка проекта завершена, пришло время построить сhm-файл. Выбираем Documentation->Build Project, и, если все было сделано правильно, то получаем красивый файл документации в стиле MSDN.

Полезные ссылки по теме:


Пишем статьи


Однако не стоит останавливаться на достигнутом – одного описания API вашего компонента не достаточно для полноценной документации. Хорошая документация обычно содержит дополнительные статьи, примеры, FAQ и т.п.

В окне Project Explorer добавляем новый элемент Content Layout – это описание (с указанием взаиморасположения) того, что входит в документацию. В окне Content Layout добавляются новые статьи (topics). Каждая статья описывается в MAML формате (.aml файлы), это xml-based формат. Sandcastle Help File Builder поставляется с набором предопределенных шаблонов, что значительно упрощает дебют в написании статей. Я в основном использую шаблон Conceptual, реже – Walkthrough.

Описание каждой статьи начинается с указания topic id – уникального идентификатора. На основе этого идентификатора генерируется html файл, который позже попадет в chm. Генерируемый html-файл именуется в форме “TOPIC_ID.htm”. Данный topic id используется также для ссылок на статью из других статей или xml-комментариев в коде.

При создании статьи предлагается ее сохранить в файл с именем “TOPIC_ID.aml”. Можно и нужно при создании сразу указать нормальное имя для файла.

Рассмотрим некоторые элементы управления в SHFB, которые полезны при редактировании статей.
image

Default topic
Устанавливает стартовую страницу документации (будет показываться при
открытии документации.
API insertion point
Устанавливает положение, в которое будет вставлено описание API,
сгенерированное из xml-файла. В зависимости от того, какой вариант выбран,
описание API будет вставлено
либо перед, либо после, либо как дочерний элемент помеченного таким образом
элемента.
Preview topic
Предварительный просмотр текущей статьи.
image
Вставка ссылки на статью в документации. Используйте topic id в
качестве адреса.
SHFB tags
Вставка стандартных тегов для разметки статьи.

Окно Entity Reference (на картинке расположено справа) можно использовать для вставки ссылок на описание функций/методов и т.п. сущностей из кода. Такой способ вставки ссылок не очень удобен на мой взгляд, так как нужно сначала открыть текст статьи, потом открыть окно Entity Reference, потом в этом окне написать часть или полное названия сущности, потом найти в списке нужную строку и дважды кликнуть на нее. Все это приведет к тому, что в статью вставится ссылка в позиции курсора. Я предпочитаю писать ссылки руками, а текст для ссылок находить в build log-е (лог от предыдущего билда можно открыть в текстовом редакторе).

Для вставки кода в статью используется тег <code>. Например:
<code language="cs">
private void helloWorld()
{
    Console.WriteLine(”Hello World!);
}
</code>

Для вставки изображений необходимо проделать следующее:
  1. В окне Project Explorer выбираем Add, потом Existing Item и выбираем нужную картинку.
    Add image
  2. В свойствах добавленного файла меняем BuildAction на Image, а свойство ImageId – на удобное название (будет использоваться в ссылках на это изображение).
    Image properties

Далее можно использовать изображение в статьях так:
<mediaLink><image xlink:href="ImageId" placement="center" /></mediaLink>

К сожалению, в текущей версии SHFB редактор далек от совершенства. Например, теги не закрываются автоматически, очень много действий приходится делать мышью (нет хоткеев), не для всех стандартных тегов есть соответствующие элементы на тулбаре. Парадоксально, но мне для большинства действий с aml-файлами удобнее использовать Visual Studio. Разумеется, можно использовать и любой другой удобный xml-редактор для написания статей.

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


Интеграция в процесс сборки


Можно включить файл проекта (*.shfbproj) от Sandcastle Help File Builder в solution Visual Studio, однако в настоящее время нет возможности использовать его как полноценный проект. То есть вы не сможете увидеть содержимое такого проекта, проект лишь добавится в группу Solution Items.

Добавление осуществляется следующим образом:
  1. Для solution выбираете Add->Existing Item…, добавляете проект документации. Будет добавлен в папку Solution Items.
    SHFB project in Visual Studio
  2. Щелкаете по добавленному элементу правой кнопкой мыши и выбираете Open With… В открывшемся диалоге добавляете ”Sandcastle Help File Builder GUI” и устанавливаете его в качестве редактора по умолчанию.

После этого проект документации можно будет открывать из Visual Studio.

Более полезна сборка документации из командной строки. Такую сборку можно делать на Post-Build event или в других случаях. Собрать документацию из командной строки очень просто следующей командой:
%SystemRoot%\Microsoft.NET\Framework\v3.5\MSBuild.exe" /p:Configuration=Release Help.shfbproj
В этой строке Help.shfbproj – название проекта документации.

Надеюсь, эта статья поможет вам начать писать документацию к вашим проектам (если вы еще этого не делаете) за что ваши пользователи наверняка скажут вам спасибо. Успехов вам в написании документации!
Tags:
Hubs:
+69
Comments 29
Comments Comments 29

Articles