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

    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 – название проекта документации.

    Надеюсь, эта статья поможет вам начать писать документацию к вашим проектам (если вы еще этого не делаете) за что ваши пользователи наверняка скажут вам спасибо. Успехов вам в написании документации!
    Метки:
    Поделиться публикацией
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 29
    • +3
      отлично! спасибо
      • 0
        Спасибо за очень подробное описание. Сразу сходил посмотреть, что за компоненты продаете :) Они кормят или это так, подработка?
        • 0
          отличное описание! спасибо, многие моменты уже забыл)
          • +1
            Исчерпывающе. Спасибо.
            • 0
              ваши слова, да многим разработчикам в уши… с первого курса!

              Ну ни одна маленькая/средняя компания не хочет писать не то, чтобы документацию или структуру программы, а банальные комментарии ко всему коду и форматировать его.
              Как можно скорость разработки продукта и скорость «вхождения» в проект для новых девелоперов променять на ленивое «программист должен кодить, а не программировать» или «а зачем комментарии, тут же и так все понятно» ??!!!
              Дико…

              Сегодня глаза сломал разбираясь в каше двухлетней давности какого-то кодера.
              • +6
                За всех то не говорите. У нас, например по форматированию кода суровые правила — к SVN-у прикручен StyleCop (в нем задаётся шаблон по форматированию кода)
                И криво отформатированный код разработчик даже не сможет закоммитить :)
                Возможно о работе такой связки позже статейку напишу
                • +2
                  С удовольствием прочитал бы про связку SVN и StyleCop. То есть по-отдельности я их использую, а вместе пока не доводилось. Насколько понимаю, там используются хуки SVN?
                  Еще интересно, будет ли ваш подход работать на svn-хостингах типа code.google.com.
                  • 0
                    В общем то да, основано на pre-commit хуках.
                    Чужими SVN-хостингами не пользовался, поэтому не в курсе какие средства управления они предоставляют. Но в любом случае сомневаюсь, что там получится это настроить
                  • +1
                    Обязательно напишите такую статью. Очень интересно.
                    • 0
                      за всех и не говорю ('… да многим разработчикам ...').

                      Радостно, что есть фирмы, в которых к разработке подходят серьезно
                      • 0
                        Также с удовольствием почитал бы статью на эту тему. И прикрутил бы у себя же на проекте.
                    • 0
                      Этот файл уже сам по себе полезен тем, что если его положить рядом со сборкой (вашей dll), то это позволит функции IntelliSense в Visual Studio отображать описания для методов в момент набора пользователем кода.


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

                      Добавлю, что при включении генерации файла xml-документации, компилятор (по крайней мере C#) начинает генерировать warning'и на все публичные элементы без xml-комментариев. Довольно удобно.
                      • 0
                        Файл с xml-комментариями можно не прикладывать, но тогда вся информация для IntelliSense будет добываться из сборки через reflection. В сборке, откомпилированной в конфигурации Release, информации не очень много. В итоге работать со сборкой будет менее удобно.
                      • 0
                        GhostDoc не продвинулся в плане тега Exception?

                        /// Thrown when...
                        public void DoSomething() {… }

                        Всегда хотел какие-нибудь средства автоматически-полуавтоматически описать исключения гененируемые методом

                        • 0
                          парсер тег сожрал… в общем отсюда msdn.microsoft.com/en-us/library/w1htk11d.aspx
                          • 0
                            К сожалению, в плане автоматического прописывания исключений в GhostDoc ничего не поменялось.
                            Я сам очень хочу найти способ автоматически документировать исключения.
                          • 0
                            У нас принято использовать синтаксис комментариев совместимый с Doxygen
                            Это обеспечивает единообразие стилей и способов генерации документации на разных платформах и языках.
                            • +1
                              Выскажу свое мнение.

                              Я вот лет 5 назад тоже увидел эту программулину и давай сразу тыкать, применять для всего. Но потом задумался — а кому нафик нужна эта автоматически сгенеренная документация? Особенно если там нет внятных примеров использования кода а всего по 2-3 очевидных объяснения к методу, которые можно и так понять из его названия.

                              Даже проводил соц. опрос среди разработчиков: полезна эта документация всего 10% разработчиков.

                              Ну сами подумайте. Скачали какую-нибудь либу. Открываете папку — там 150 Кб либа и 2 Мб документации. В документации только названия методов и очевидное их описание. Ну какой смысл в ТАКОЙ документации? Станете ли вы ее читать?

                              Нужна документация иного рода, где описывается процесс использования в общем + приведены конкретные примеры. И поменьше воды.

                              Мне гораздо полезнее примеры использования. Вот на это стоит потратить время. А заниматься пустотой смысла нет. То что так делают все — это не повод транжирить время.
                              • +1
                                Я некоторое время назад был склонен думать как вы. Но теперь изменил свое мнение.
                                Дело ведь в том насколько полна документация, а не в том, чем она сгенерирована. MSDN вот тоже автоматически генерируется и разве можно сказать, что эта документация не нужна?

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

                                Можете поискать в гугле LibTiff.Net. Это опенсоурсная библиотека, для которой документация сделана описанным в статье способом. Насколько получившаяся документация (а она содержит в том числе примеры использования) полезна — решать вам. Может быть ваше мнение по поводу такого способа документирования изменится.
                                • +1
                                  Наверное зависит от того, будете ли вы для каждого метода приводить примеры и полезное описание. Иначе получается слишком много воды, а это плохо. Кто будет открывать и просматривать всем члены всех классов, дабы найти те 3-4 нещастных метода, где вы разместите примеры?

                                  Просмотрел LibTiff.Net. Красота! Глаз нельзя отвести, как красиво. И себе захотелось так сделать… А вот толку — нуль (я имею в виду та часть, где неймспейсы и классы, а не где примеры и общее описание). Реально, если бы я использовал их библиотеку — мне бы были интересны лишь примеры и общее описание. Остальное легче глянуть в intellisense.

                                  Ну разве что для красоты, для «крутости» имеет смысл это сделать. Чтоб же все видели, что я таки не отстаю от жизни и как все делаю абсолютно никому не нужную автогенеренную документацию (это ж круто!).

                                  И еще одно. MSDN врядли писалась прямо в коде .Net. Это не удобно. Все примеры, все примечания туда втулить. У них наверняка более удобный инструмент. Вот от чего-либо подобного я б не отказался. А автогенеренная документация ТОЛЬКО по коду — не есть гуд. Тем более как ее переводить на другие языки?
                              • 0
                                Можно включить файл проекта (*.shfbproj) от Sandcastle Help File Builder в solution Visual Studio, однако в настоящее время нет возможности использовать его как полноценный проект.


                                Вроде есть вот такой полноценный проект для VS, который генерирует документацию с помощью Sandcastle: docproject.codeplex.com/
                                • 0
                                  Да, действительно есть такой альтернативный SHFB-у проект (о нем есть упоминание в статье). К сожалению, у него есть свои недостатки.

                                  Я работал и с DocProject, и с Sandcastle Help File Builder и пришел к выводу, что второй нравится мне больше.
                                  • 0
                                    прошу прощения, когда писал комментарий, случайно пропустил упоминание :)
                                    кстати, спасибо за отличную статью
                                • 0
                                  Годика этак четыре назад писал статью про Sandcastle:
                                  rsdn.ru/article/helpsystems/Sandcastle.xml
                                  • 0
                                    А еще если написать тройной слеш (///) Visual Studio сама вставит теги (summary, params, return) и останется только добавить для них описание.
                                    • 0
                                      Активно пользуюсь вашей статьей для старта с Sandcastle, а заодно и документацией к docotic, в качестве живого примера — спасибо!
                                      • 0
                                        Однако в большинстве случаев сгенерированный xml-файл содержит комментарии к внутренним структурам, которые пользователям не нужно или нельзя видеть. Ниже я напишу, как автоматически очистить xml-файл так, чтобы в нем остались только описания к публичным методам.


                                        Может не внимательно читал, но чето не нашел где в статье про это написано?
                                        • 0
                                          Про это написано в начале раздела «Генерируем файл документации». Можно поискать строчку «IntelliSense Component» (без кавычек).
                                        • 0
                                          Затруднялся с написанием документации для проекта. Теперь есть хорошее руководство — спасибо.

                                          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.