How to keep .NET documentation code samples in sync with code base

ยท

3 min read

Maintaining and managing documentation for software products or libraries require a good amount of time and discipline to keep it up to date with the latest code base. Typically code samples are the ones which can quickly go out of sync when it is manually added as a code snippet in docs.

In this article I am covering a method which we have successfully used in Marten to keep the code samples current in the docs. All credits to Jeremy Miller who pioneered this method and used it in several projects including StructureMap and many projects under JasperFX using a custom built tool named StoryTeller Docs.

We will assume that docs are written in Markdown, code samples are C# code and the source content is managed in a Git repository. You can refer to the sample here

  • The first step is to mark the code fragments in your code base with region markers i.e. #region and #endregion in the C# code or it could be custom region markers for F#.
// src/Program.cs
#region sample-hello-world
Console.WriteLine("Hello, World!");
#endregion

In the code above, we have added a region named sample-hello-world. I typically use a prefix like sample- to distinguish between regions for code samples and others.

  • Add a placeholder in the docs file where the code sample content from source will get updated
# docs/index.md

This is the docs page demonstrating keeping code samples in your docs to be in sync with code base

<!-- snippet: sample-hello-world -->
<!-- endSnippet -->

In the markdown content above, we are adding a placholder named sample-hello-world, this is the same name used for the region name.

  • Install MarkdownSnippets, a wonderful tool written by Simon Cropp which we will use to update the docs with the sample code snippets from source code.
dotnet tool install -g MarkdownSnippets.Tool
  • Let us configure MarkdownSnippets using a JSON configuration file (mdsnippets.json) as below
{
    "Convention": "InPlaceOverwrite",
    "LinkFormat": "GitHub",
    "UrlPrefix": "https://github.com/mysticmind/docs-code-sync-sample/blob/master",
    "TreatMissingAsWarning": true
}

InPlaceOverwite always replaces the content within the <!-- snippet: <sample-name> --> and <!-- endSnippet -->.

Since our sample Git repository is in GitHub, we are setting it accordingly to generate the links to easily access the source content from docs (this is explained further in the article).

Also we are setting TreatMissingAsWarning as true which will result in an error while running the MarkdownSnippets tool if the sample content is not found in source code.

  • Run the MarkdownSnippets tool which will update the sample code in the placeholder within docs.
mdsnippets

docs/index.md placeholder is updated with the content as below:

<!-- snippet: sample-hello-world -->
<a id='snippet-sample-hello-world'></a>
```cs
Console.WriteLine("Hello, World!");
```
<sup><a href='https://github.com/mysticmind/docs-code-sync-sample/blob/master/src/Program.cs#L3-L5' title='Snippet source file'>snippet source</a> | <a href='#snippet-sample-hello-world' title='Start of snippet'>anchor</a></sup>
<!-- endSnippet -->

The rendered HTML looks as below: rendered-html.png

Link snippet source takes you to the actual source code line where the code sample exists.

If you using MarkdownSnippets with say F# then you could use region markers // begin-snippet: my-sample and // end-snippet in code, MarkdownSnippets will automatically handle this.

To automate updating of code samples in docs, running the MarkdownSnippets can be wired as part of the docs publishing step in your CI pipeline.

In summary, keeping the code samples in sync this way has many benefits and makes it easier to maintain it in the long run. Especially when you refactor or do a large number of breaking changes, code samples which are part of the code base will need to be updated otherwise the build will fail. This forces you to keep the code samples current at any point in time.

ย