Organize APIs and Write Docstrings

Docstrings for all structs, methods, and functions belong in the public or internal APIs, organized under the Reference section in Diataxis organization. Refer to this page particularly while editing Sienna docstrings and APIs for guidance on common problems in our existing documentation.

Prepare

  • If you have not read Diataxis, first read it in its entirety.
  • Refer back to the Diataxis Reference section while working.
  • Read and follow Julia's guidance on Writing Documentation, which mainly applies to docstrings
  • Read the sections on Documenter.jl's @docs block and @autodocs block, and follow the guidance below on using @autodocs wherever possible

Follow the Do's and Don't's

Julia and Documenter.jl's guidance above should be your main reference, but in addition, follow these do's and don't to avoid common pitfalls from previous versions of Sienna documentation:

Look at the compiled .html!

Do
  • Compile regularly and look at the APIs
  • Check method signatures and argument lists are formatted correctly

Ensure All Docstrings Are Located in the APIs

Do

Include a Public API markdown file for exported structs, functions, and methods, and an Internals API for private functions. See PowerSystems.jl for an example with a Public API organized with @autodocs (see next) or SiennaTemplate.jl for a basic template when starting a new package.

Do

Migrate all existing Formulation Libraries and Model Libraries into the Public API.

Do

If you want to make a docstring visible outside of the API (e.g., in a tutorial), use a non-canonical reference.

Automate Adding Docstrings in the Public API with @autodocs

Do

Use @autodocs blocks in the Public API markdown file to automatically find all docstrings in a file. Example:

## Variables
```@autodocs
Modules = [SomeSiennaPackage]
Pages = ["variables.jl"]
Public = true
Private = false
```
Don't

Manually list out the struts or methods on a topic in a @docs block, because that introduces more work whenever we add something new or make a change. Example:

## Variables
```@docs
variable1
variable2
```

Consider re-organizing code if need be, so all related functions are in the same file(s) (e.g., variables.jl).

Selectively Export Docstrings from InfrastructureSystems.jl

If you are working in another Sienna package (e.g., SomeSiennaPackage.jl) that imports and exports code from InfrastructureSystems.jl:

Do

List the files containing necessary InfrastructureSystems.jl structs and methods in SomeSiennaPackage.jl's Public API markdown file, then explicitly filter by what SomeSiennaPackage.jl exports. Example:

```@autodocs
Modules = [InfrastructureSystems]
Pages   = ["production_variable_cost_curve.jl", # examples
            "cost_aliases.jl",
        ]
Order = [:type, :function]
Filter = t -> nameof(t) in names(SomeSiennaPackage)
```
Don't

List InfrastructureSystems as one of the modules in Documenter.makedocs in the make.jl file. Documenter.jl will look to map all InfrastructureSystems.jl docstrings into the API, resulting in hundreds of missing docstring errors. Example:

makedocs(;
    modules = [SomeSiennaPackage, InfrastructureSystems],
    format = Documenter.HTML(;
        prettyurls = haskey(ENV, "GITHUB_ACTIONS"),
        size_threshold = nothing),
    sitename = "SomeSiennaPackage.jl",
    pages = Any[p for p in pages],
)

Ensure All Docstrings Have a Function Signature and Arguments List

Do

Check all exported docstrings have a function signature and detailed arguments list visible in the API when you compile it. Example:

A docstring with function signature and args list

Don't

Leave docstrings that just have a description unaddressed. Example:

A single line docstring

Automate Updating Docstring Arguments Lists

This is not commonly done in Sienna yet, but a goal is to improve our use of DocStringExtensions.jl for automation:

Do

Use DocStringExtensions.TYPEDFIELDS to automatically compile arguments lists. Example:

"""
    SomeSiennaStruct(arg1, arg2)

# Arguments
$(TYPEDFIELDS)

This is the docstring line.
"""
struct SomeSiennaStruct <: OperationalCost
    "Documentation for argument 1"
    arg1::ProductionVariableCostCurve
    "Documentation for argument 2"
    arg2::Float64
end
Don't

Copy and paste arguments lists into the docstring, which opens opportunity for out-of-date errors when arguments are added or reordered. Example:

"""
    SomeSiennaStruct(arg1, arg2)

This is the docstring line.

# Arguments
  - `arg2::Float64`: Documentation for argument 2
  - `arg1::ProductionVariableCostCurve`: Documentation for argument 1
"""
struct SomeSiennaStruct <: OperationalCost
    arg1::ProductionVariableCostCurve
    arg2::Float64
end
Do

To help users navigate Julia's multiple dispatch, add See also paragraphs at the bottom of function docstrings other versions of the function with the same name, using the guidance on adding a specific hyperlink. Example:

See also 
[`get_time_series_array` by name from storage](@ref get_time_series_array(
    ::Type{T},
    owner::TimeSeriesOwners,
    name::AbstractString;
    start_time::Union{Nothing, Dates.DateTime} = nothing,
    len::Union{Nothing, Int} = nothing,
    ignore_scaling_factors = false,
    features...,
) where {T <: TimeSeriesData}),
[`get_time_series_array` from a `StaticTimeSeriesCache`](@ref get_time_series_array(
    owner::TimeSeriesOwners,
    time_series::StaticTimeSeries,
    start_time::Union{Nothing, Dates.DateTime} = nothing;
    len::Union{Nothing, Int} = nothing,
    ignore_scaling_factors = false,
))

Follow the Guidelines on Cleaning Up General Formatting

Do

Follow How-to Clean Up General Formatting, especially by adding hyperlinks to other Sienna structs that appear within an arguments list.