Technical Documentation

Public vs Internal

Opening

Presenter

  • Brian Dominick, DocOps Lab

  • docopslab.org

  • 25 years software development experience

  • 10 years tech-docs specialization

Presenter

  • Tech writer for BigData Engineering startup (2015-2018)

  • DocOps contractor since acquisition (2018-present)

  • Working on DocOps framework, utilities, libraries, and trainings/courses

  • Write the Docs participant since 2017

Audience

  • You are either a product developer or technical writer (or aspiring).

  • You are looking to initiate or improve the handling of internal documentation at some kind of engineering organization (or expect to).

Focus

  • Product is enterprise software

  • Subject-matter experts are developers and product managers

  • Product audience includes downstream developers and end users

Definitions

Jargon

Git

Leading (dominant) version-control system for flat-file tracking

API

Application programming interface

SDK

Software development kit

docs-as-code

Documentation authored using the same tools and processes as product code

Internal Roles

documentarian

Someone who contributes substantially to docs

TW

Technical writer

PM

Project or product manager

Support

Customer support technician or represntative

External (User) Roles

end user

Someone who uses the most-abstract interfaces of the product (mobile apps, web forms, even CLIs)

downstream dev

Or “dev user”, someone who uses the product’s APIs, SDKs, etc

External Docs

  • focus on interfaces

  • consumer is customer / client / prospect / user

  • includes downstream “dev docs”: API/SDK/etc

Internal Docs

  • also focus on interfaces

    • including private APIs, etc

  • also cover resources

    • assets, infrastructure, processes, styles

  • consumer is coworker / collaborator / successor / you

  • may be publicly accessible (open source)

Problems

Divergence and Convergence

Documentation of overlapping subjects is authored and output in different ways, using different tools.

Content divergence is an inevitable problem that can be solved with innovation.

Source duplication is a problem that can only be solved with manual effort (or elimintation).

Divergence Breakdown

contributor roles

developers, TWs, PMs

tech preferences

WYSIWYG, CCMS/XML, lightweight markup, Git, etc

audiences

end users, downstream devs, internal devs, etc

delivery methods

static site, wiki, PDF, etc

The Platform Divide

InternalUser/Dev Docs

Confluence

Markdown & GitHub Pages

Google Docs/Sheets

ReadTheDocs

Notion

OpenAPI/Markdown

SharePoint / Office 365

MadCap Flare / DITA

Duplication of Truth Sources

Source 1

The product source code.

Source 2

The documentation source code.

It matters not at all what is written in Confluence or Markdown or Flare if the source code does not agree.

(Ideal) Audience Breakdown

Internal DocsPublic Docs

Internal Devs

Public & private APIs, SDKs, policies

N/A

Downstream Devs

N/A

Public APIs, SDKs, etc

End Users

N/A

Public UIs, tutorials, etc

Docs Source Convergence

internal docs venn diagram

Content Complication Examples

private/public APIs

Same API might have 90% overlap, 10% private endpoints. Docs sourced in code or aside.

configuration

Config is defined internally, used by downstream devs and end users. Docs usually sourced aside.

Typical Implementation

  • 2 API references: public on Mintlify or SwaggerHub, used by both internal and downstream devs, private in Confluence or Notion used by internal devs.

  • 2-4 config guides: public on ReadTheDocs, premium for paid users in the WebUI, private versions of both on GitHub, used by devs and QA testers.

Key Differences

Internal Docs are:

  • more directly maintained by SMEs

  • fewer constraints on delivery methods/formats

  • not expected to be as “polished”

  • backed up by code (real source of truth)

Key Differences

External/User Docs are:

  • easy for users to discover and access

  • expected to be more polished and accurate

Risks of bad or missing docs

AudiencePotential Cost

customer

revenue loss

prospect

deal loss

coworker

frustration, cycles

open-source dev

code contributions

Solutions

Internal Documentation Principles

  1. All docs are first-class docs.

  2. Meet developers where they’re at (authoring and discovery).

  3. Minimize the number of technologies.

  4. Don’t repeat yourself (DRY).

All Docs are First Class

  • edited and architected by content professionals

  • delivered conveniently

  • accurate

  • polished

Meet Devs in Dev World

  • Use existing dev platforms

    • JIRA/GitHub Issues

    • Confluence/Wiki

    • Docs-as-code via Git

    • Commandline tools

Meet Devs in Dev World (Cont’d)

  • Deliver to accessible platform

    • Could be Confluence

    • Could be static site on company VPN

    • Could be GitHub wiki or Notion

Keep the Toolchain Short

  • SSG or Wiki/CMS?

  • collaboration platform

  • runtime environments / Docker

  • linters

  • deployment platform

Keep the Language Stack Shorter

  • Content markup (Markdown, AsciiDoc*, rST)

  • Data markup (YAML*, JSON, CSV)

  • Template markup (Liquid*, Jinja2, Handlebars)

  • Scripting (Bash*, Python, Rust, Golang)

Write Once, Deliver Everywhere

  • DRY / Single Source of Truth (SSoT)

  • True single sourcing defines product and docs

  • Minimize "hand-offs" between SMEs & documentarians

Conditionalize Source

  • Generate multiple versions of the same document

    • differ by audience role

    • differ by delivery method

  • Use modular content

    • if/else conditions

    • transclusion of reusable content

Examples

Example: AsciiDoc Conditonal & Transclusion

asciidoc conditional includes
command
asciidoctor -a env-internal --out-file=docs.html docs.adoc

Example: YAML Truth Sourcing

properties:
  base_url:
    summary: The base path to the resource.
    default: /resource
  timeout:
    summary: The timeout for the request in seconds.
    default: 30
  retries:
    summary: The number of retries for the request.
    default: 3
    private: true

Example: Liquid Template

liquid forloop asciidoc

Example: Rendered AsciiDoc

rendered asciidoc dls

Example: Converted to
HTML or PDF

richt text asciidoc reference

Example: Sample Config FIle

liquid sample config
base_url: /resource # The base path to the resource.
timeout: 30 # The timeout for the request in seconds.

Example: YAML Loaded to Python

import yaml
with open('config.yaml', 'r') as file:
    config_file = yaml.safe_load(file)
class Config:
    def __init__(self, properties):
        self.properties = {k: Property(**v) for k, v in properties.items()}
class Property:
    def __init__(self, summary, default=None, private=None):
        self.summary = summary
        self.default = default
        self.private = private
config = Config(config_file['properties'])

Example: YAML Loaded to Rust

use serde::{Deserialize, Serialize};
use std::fs::File;
use std::io::BufReader;
#[derive(Debug, Deserialize, Serialize)]
struct Config {
    properties: std::collections::HashMap,
}
#[derive(Debug, Deserialize, Serialize)]
struct Property {
    summary: String,
    default: Option,
    private: Option,
}

Example: YAML Loaded to
Java

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import java.io.File;
import java.util.Map;
public class ConfigLoader {
    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
        Map config = mapper.readValue(new File("config.yaml"), Map.class);
        System.out.println(config);
    }
}

Example: YAML Loaded to Ruby

require 'yaml'
config = YAML.load_file('config.yaml')
class Config
  attr_accessor :properties
  def initialize(properties)
    @properties = properties.transform_values { |v| OpenStruct.new(v) }
  end
end
config_obj = Config.new(config['properties'])

Example:
Mobile App Config Screens

mobile app config screens

Python Tests Based on YAML Defs

import unittest
config = Config(config_file['properties'])
class TestConfig(unittest.TestCase):
    def test_properties(self):
        for key, prop in self.config['properties'].items():
            with self.subTest(key=key):
                self.assertIn('summary', prop)
                if 'default' in prop:
                    self.assertIsInstance(prop['default'], str)
                if 'private' in prop:
                    self.assertIsInstance(prop['private'], bool)
if __name__ == '__main__':
    unittest.main()

Case Study:
Issue Tickets to Release Notes

Bridging the internal/external divide

Problem

  • Work tasks are tracked internally in Jira (or GitHub Issues, etc)

  • Release notes drafted in Confluence (or Google Doc, etc)

  • This is an extra burden at release-time

  • Release notes are often incomplete or inaccurate

Solution

  • Use a "Release Note" field in each qualifying Jira work item

  • Use a script to:

    1. download the notes and

    2. draft a Markdown file (via template)

  • Edit and save the file in Git

Example Script command

python release_notes.py --project acme-cloud --version 2.3.0

Example Jinja2 Template

## Release Notes for {{ project }} {{ version }}
{% for issue in issues %}
### {{ issue.summary }} ({{ issue.key }})
{% if issue.release_notes %}
{{ issue.release_notes }}
{% endif %}
{% endfor %}

Example Markdown Draft

## Release Notes for ACME-Cloud 2.3.0

### Fix login issue (CLOUD-453)

Some users were unable to log in to the ACME-Cloud platform.
The authentication service has been updated to resolve this issue.

### Improve performance of database queries (CLOUD-456)

### Add new API endpoint for image management (CLOUD-489)

This issue adds a new API endpoint (`/images`) for managing image assets in the ACME-Cloud platform. See [API Reference](/docs/api-reference/endpoints/images) for details.

Solution Achieves

  • Meets developers where they are

  • Uses existing tools (Jira, Git, Markdown, static site)

  • Reduces duplication of effort

  • Improves accuracy and completeness of release notes

Wrap-Up

Un-Covered Topics

  • Unified search

  • Documentation audits

  • Alignment with product versioning

  • Document lifecycle management

Further Exploration

  • Docs-as-code

  • REST APIs (Confluence, GitHub, etc)

  • Templating languages/engines

  • Conditional content

  • Structured / modular documentation

Resources

Other Talks

Making Yourself Redundant on Day One
(WtD Australia 2018 Talk by Alexandra Perkins)

Questions?