Skip to content

CXX-3082 Add Comprehensive Examples (bsoncxx) #1208

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 31 commits into from
Sep 25, 2024

Conversation

eramongodb
Copy link
Contributor

@eramongodb eramongodb commented Sep 13, 2024

Summary

Resolves CXX-3082 for bsoncxx. Comprehensive examples for mongocxx will be included in a followup PR.

Build and run of examples are verified by this patch. To review the displayed examples in API doc pages, the API docs must be built locally.

This PR is a smaller-sized demonstration of the design of API doc examples (bsoncxx only). The various patterns used in this PR will be extended to mongocxx library comprehensive examples.

Topic Pages

This PR adds the first set of "Topic" pages following their preparation by #1183.

image

The "Using" pages implement the "How-To Guides" quadrant of the Diataxis compass, as clearly indicated by the page descriptions ("How to ..."). The "About" pages implement the "Explanation" quadrant of the Diataxis map. The focus of CXX-3082 is on implementing "How-To Guides", so the About pages are left empty besides their description. They are still included in this PR to record their intended purpose.

The Topic pages directly correspond to the \page Doxygen commands used in doc.hpp. Each \page defines the name, title, and contents of a single Topic page. The page name (e.g. topic-bsoncxx-examples-bson-documents) is very important: this determines the corresponding page URL (e.g. /topic-bsoncxx-examples-bson-documents.html). Therefore, for link stability purposes, they must be defined and used with care. The page title (e.g. "BSON Documents") is cosmetic and does not require such stability.

Important

The <name> in @page <name> <title> must be stable! (This may not be as necessary if we revise how /api/current links are handled.)

The page hierarchy is determined by use of the \subpage command. I expect (and recommend) only a single level of nesting to ever be necessary. This will be elaborated on further below.

Markdown Files

To avoid extreme bloating of the doc.hpp file, as well as to facilitate easier authoring of topic pages, the contents of each page are written as Markdown files under docs/api/. Their layout approximately reflect the page name and hierarchy (e.g. docs/bsoncxx/examples/bson_documents/ for topic-bsoncxx-examples-bson-documents page content). This design also permits standalone formatting and preview of the Markdown files, isolated from Doxygen-specific content.

Markdown file content is imported into Doxygen pages via \include{doc}. The {doc} indicates the contents of the included file are documentation, not code. This structure permits flexibility of content layout and organization on a per-page level, e.g. splitting page content across multiple files as done for the "BSON Documents" page:

///
/// @page topic-bsoncxx-examples-bson-documents BSON Documents
/// @brief How to create and use BSON documents.
/// @tableofcontents
/// @include{doc} api/bsoncxx/examples/bson_documents/create_doc.md
/// @include{doc} api/bsoncxx/examples/bson_documents/create_array.md
/// @include{doc} api/bsoncxx/examples/bson_documents/access_doc.md
/// @include{doc} api/bsoncxx/examples/bson_documents/access_array.md
/// @include{doc} api/bsoncxx/examples/bson_documents/elements.md
/// @include{doc} api/bsoncxx/examples/bson_documents/values.md
/// @include{doc} api/bsoncxx/examples/bson_documents/json.md
///
./docs/api/bsoncxx/examples/
├── bson_documents/
│   ├── access_array.md
│   ├── access_doc.md
│   ├── create_array.md
│   ├── create_doc.md
│   ├── elements.md
│   ├── json.md
│   └── values.md
├── bson_errors.md
├── decimal128.md
├── oid.md
└── validation.md

Important

The layout and organization of contents of a page are flexible.

Section IDs are generated using GitHub style ("An Example Section" -> an-example-section) per the MARKDOWN_ID_STYLE = GITHUB as set by #1185. This permits linking directly to individual examples from regular API doc pages (this not yet utilized by this PR). I do not think going out of our way to preserve the stability of section IDs will be necessary, but it is something to keep in mind regardless.

Example Code

Examples are embedded in pages via the \snippet Doxygen command. Each example is implemented as an individual, standalone component under examples/api/. Their layout approximately reflect the layout of the page content that embeds them, e.g. for the Decimal128 page:

///
/// @page topic-bsoncxx-examples-decimal128 Decimal128
/// @brief How to use Decimal128 interfaces.
/// @tableofcontents
/// @include{doc} api/bsoncxx/examples/decimal128.md
///
# Basic Usage

@snippet api/bsoncxx/examples/decimal128/basic_usage.cpp Example

# From Bytes

@snippet api/bsoncxx/examples/decimal128/from_bytes.cpp Example

# Error Handling

@snippet api/bsoncxx/examples/decimal128/errors.cpp Example
examples/api/bsoncxx/examples/
├── decimal128
│   ├── basic_usage.cpp
│   ├── from_bytes.cpp
│   └── errors.cpp
└── ...

Note

For forward compatibility, current examples are grouped under the examples/api/bsoncxx/examples/ subdirectory to distinguish them from examples which may be embedded in regular API doc pages. e.g. if bsoncxx/v_noabi/bsoncxx/types.hpp were to include a snippet as part of its API documentation, the code being included would be placed in examples/api/bsoncxx/v_noabi/bsoncxx/types/n_snippet.cpp. This is not yet utilized by this PR.

Every example code block is deliberately included in a dedicated (sub)section that describes the goal of the example being described (e.g. "How To > Query an Element > In a Document > For a Single Type"). Every example code block corresponds to a single C++ source file containing an [Example] block ID. This ensures a one-to-one correspondance between example code blocks in a topic page and source files under examples/api/bsoncxx/examples/.

Various patterns for how to include example code in pages were considered and experimented with. In the end, keeping the Markdown files as simple as possible (sections + \snippet <file> Example) was determined to be the most straightforward and flexible. The doc.hpp defines pages and their hierarchy, the Markdown files define the page contents, and examples sources individually provide the contents of a single example. This keeps every individual file and component minimal in their complexity and dependencies.

API Examples Runner

Unfortunately during development of this PR, the length and depth of examples being compiled were too much for some Windows distros to handle:

C:\[...]\Microsoft.CppBuild.targets(312,5): error MSB3491: Could not write lines to file "[...]". The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters. [C:\[...]\examples\api-bsoncxx-examples-bson_documents-create_array-builder_bson_value.vcxproj]

Therefore, rather than fighting against Windows MAX_PATH, the API examples were refactored to use a single api-runner executable instead of every component generating its own (lengthy) executable target. The runner behaves as a simplified, rudimentary job scheduler that registers and executes each API example component in its own thread. This is deliberately implemented a manner that is similar to Catch2 test case registration.

Note

Using Catch2 in API examples was considered but rejected to avoid imposing C++14 build requirements on API examples.

Miscellaneous

Other notes regarding changes in this PR:

  • The API examples runner randomizes the order of execution to discourage and expose ordering dependencies. (This should ideally be done for our regular test suite as well via Catch2's --order rand flag, but alas.) The benefits of this implementation will be better realized when mongocxx examples that run server commands are introduced.
  • mnmlstc/core limitations (CXX-3101) forces awkward .compare() == 0 style of string comparison. We may be able to avoid this if we start compiling on CI with ENABLE_BSONCXX_POLY_USE_IMPLS=ON by default (as is recommended by the CMake configuration warning) or dropped entirely as part of CXX-2797.

@eramongodb eramongodb self-assigned this Sep 13, 2024
@eramongodb
Copy link
Contributor Author

Additional remarks:

  • The list of "Error Handling" examples were chosen as any/all API which may potentially thrown an exception given conditions specific to that particular API, or when the means of checking for the erroneous condition may not be immediately obvious.
  • Some examples are annotated with "DO NOT DO THIS" to document unusual conditions which users may be depending on that lead to the given erroneous behavior. Such cases should hopefully be addressed/removed in the future by API breaking changes.
  • Examples are deliberately kept as minimal as possible with little-to-no elaboration or explanation per Diataxis: these are How-To Guides, not Tutorials or Explanations. Users may consult the relevant API doc pages for further information as needed.
  • The "Basic Usage" section is often used to avoid overthinking more detailed per-section examples for an interface when it not necessary for demonstrating use of a given interface. This PR provides examples ranging from a simple, single "Basic Usage" section (+ error handling) to more thorough per-(member-)function sections. Deciding where in that range of basic <-> detailed a given example should be is left to the authors' judgement (erring towards "don't overthink it").

@eramongodb
Copy link
Contributor Author

After further thought, grouped topic pages by library:

image

This allows for better control of page ordering per library. Page titles were renamed to more accurately reflect their Diataxis quadrant. Contents and descriptions are unchanged.

Copy link
Contributor

@joshbsiegel joshbsiegel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small comment changes but otherwise LGTM


///
/// @page topic-mongocxx-examples Using the mongocxx Library
/// @brief Examples of how to use the bsoncxx library.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// @brief Examples of how to use the bsoncxx library.
/// @brief Examples of how to use the mongocxx library.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


ASSERT(!bsoncxx::validate(bytes, length, options, &offset));

// Offset of `"a.b": 1` relative to start of the sub-document. (CDRIVER-5710)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Offset of `"a.b": 1` relative to start of the sub-document. (CDRIVER-5710)
// Offset of `"$numberInt": "123"` relative to start of the sub-document. (CDRIVER-5710)

// [0,123,-1]
ASSERT((d128{0x303e000000000000, 0x000000000000007b}) == d128{"12.3"});

// [0,123,-1]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// [0,123,-1]
// [1,123,-1]

Copy link
Collaborator

@kevinAlbs kevinAlbs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exciting. The new examples seem comprehensive, tested, and easy to follow. Left minor suggestions, but otherwise LGTM.

runner.set_jobs(0);
}

return runner.run();
return runner.run(); // Return directly from forked processes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaked an upcoming change. Disregard the presence of this comment for now.

@eramongodb eramongodb merged commit b63d17a into mongodb:master Sep 25, 2024
71 of 79 checks passed
@eramongodb eramongodb deleted the cxx-3082 branch September 25, 2024 17:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants