Or press ESC to close.

Keeping Code and Documentation in Sync with Deno

Sep 27th 2024 8 min read
easy
typescript5.6.2
deno2.0.0
documentation

Keeping documentation up to date can be a challenge. Code evolves quickly, but examples in JSDoc comments or Markdown files often get left behind, leading to frustrating errors for developers who rely on them. Fortunately, Deno offers a powerful feature to help solve this problem: documentation tests.

Why Documentation Matters in Code

In software development, documentation is just as critical as the code itself. Good documentation serves as a guide for both developers and users, providing clarity on how to use functions, APIs, and modules effectively. Without it, even the best-written code can become inaccessible or misunderstood.

However, documentation has a major pitfall - it can quickly become outdated. As code evolves, new features are added, and bugs are fixed, the documentation can lag behind. This mismatch between the code and its accompanying examples can lead to confusion, wasted time, and frustration, especially when developers try to follow code snippets that no longer reflect the actual implementation.

For example, imagine a developer referencing a JSDoc comment or a Markdown file with code examples to implement a feature. If the example is broken or outdated, it can lead to unexpected errors and costly debugging sessions. Documentation errors can impact team productivity, especially in larger projects or open-source communities where documentation serves as the first point of reference for external contributors.

This is where automated documentation testing becomes invaluable. By validating the examples embedded in JSDoc comments and Markdown files, developers can ensure that their documentation stays up-to-date as the code evolves. Deno's documentation testing feature provides a seamless solution to this problem, enabling teams to automate the process and eliminate guesswork. By running documentation tests alongside regular test suites, we can guarantee that our documentation remains reliable and in sync with our codebase.

Deno's Solution: Running Code from Our Docs

As codebases evolve, keeping documentation accurate becomes increasingly challenging. Deno offers a powerful solution with the deno test --doc command, which allows us to test the code snippets embedded in our documentation. By turning examples in JSDoc comments or Markdown files into real, executable tests, Deno ensures that our documentation remains functional and up-to-date with our codebase.

When we run deno test --doc, Deno extracts the code blocks from our documentation, wraps them in test cases, and executes them alongside our normal tests. This prevents our documentation from becoming stale or inaccurate as our code changes. It's a straightforward yet powerful way to ensure that our examples aren't just static text but live, verified code.

Let's walk through a practical example of how to use this feature.

Step 1: Write Your Function and JSDoc Comment

First, let's create a simple function in TypeScript that reverses a string, accompanied by a JSDoc comment that includes an example of how the function should be used:

                
/**
 * Reverses the provided string.
 *
 * # Example
 *
 * ```ts
 * import { assertEquals } from "jsr:@std/assert/equals";
 * const result = reverseString("deno");
 * assertEquals(result, "oned");
 * ```
 */
export function reverseString(input: string): string {
  return input.split('').reverse().join('');
}
                

In this JSDoc block, the example demonstrates how to call the reverseString function and verify the result using assertEquals. This example will be tested to ensure that it stays in sync with the actual code.

Step 2: Run deno test --doc

To test the example from our JSDoc comment, we simply run the following command in our terminal:

                
deno test --doc reverseString.ts
                

This command extracts the code snippet from the documentation, converts it into a test case, and runs it. If the example works as expected, Deno will pass the test. If the function or the example code is incorrect, Deno will flag the issue.

Step 3: View the Test Results

Once we execute the command, Deno will inform us whether the test passed or failed. For instance, if the example is correct, we'll see:

running 0 tests from ./reverseString.ts
running 1 test from ./reverseString.ts$6-11.ts
file://file-path/reverseString.ts$6-11.ts ... ok (0ms)

ok | 1 passed | 0 failed (24ms)

If the test fails (for example, if the example doesn't match the function's behavior), we'll get a detailed error message:

error: AssertionError: Values are not equal.
[Diff] Actual / Expected
- deno
+ oned

throw new AssertionError(message);
^
at assertEquals (https://jsr.io/@std/assert/1.0.6/equals.ts:51:9)
at file://file-path/reverseString.ts$6-11.ts:5:5

FAILURES
file://file-path/reverseString.ts$6-11.ts
=> ./reverseString.ts$6-11.ts:3:6

FAILED | 0 passed | 1 failed (26ms)

This allows us to catch and fix any inconsistencies between the documented examples and the actual implementation.

Step 4: Fixing Documentation or Code

If our test fails, it indicates that our documentation example is out of sync with the current code. We can either update the example in the JSDoc comment or adjust the function's implementation to ensure they match. Once we've made the necessary corrections, we rerun deno test --doc to verify the fix.

Step 5: Integrate Documentation Testing into Your Workflow

One of the biggest advantages of using Deno's deno test --doc is that we can integrate it into our regular testing workflow. Whether we're working on a personal project, contributing to open source, or collaborating in a large team, this tool ensures that our documentation evolves alongside our codebase, reducing confusion and improving the overall quality of our project.

Markdown Code Testing: More Than Just JSDoc

While Deno's deno test --doc feature shines for JSDoc examples, it doesn't stop there. We can also test code snippets embedded in Markdown files. This is especially useful for README files, tutorials, or API documentation that often include example code.

Just like with JSDoc, Deno extracts code blocks from Markdown files and runs them as part of our test suite. The syntax remains the same—enclosed in triple backticks (```)—and the language is determined by the code block's identifier (e.g., ts for TypeScript).

To test a Markdown example, we simply run:

                
deno test --doc file.md
                

Deno will automatically discover and execute the code blocks, ensuring they are functional and accurate, just like with JSDoc examples. This helps prevent "code rot" in Markdown documentation and keeps our guides and examples reliable as our project evolves.

Type-Checking Only: When Execution Isn't Needed

Sometimes, we might want to ensure that our documentation code examples are type-safe without actually running them. Deno provides two useful options for this: deno check --doc for JSDoc comments and deno check --doc-only for Markdown files.

By running:

                
deno check --doc file.ts
                

or

                
deno check --doc-only file.md
                

Deno will validate the types in our examples without executing the code. This is helpful when we want to confirm type correctness but don't need the examples to run, such as for quick validation or during early-stage documentation writing.

Real-World Use Cases: When and Why to Use Documentation Tests

Automated documentation testing, like Deno's deno test --doc, is more than just a convenient feature - it's a vital tool in several scenarios where code quality and accuracy matter. Here are some key use cases where automated documentation tests can provide real value:

1. Open-Source Projects

In open-source projects, maintaining accurate documentation is crucial for contributors and users. As the project evolves, examples in the documentation can quickly become outdated. Using deno test --doc helps ensure that the code snippets in README files, tutorials, and API docs always reflect the latest version of the code. This prevents user confusion and keeps the documentation a reliable source of truth.

2. Team Collaborations

When multiple developers work on the same codebase, documentation can easily fall out of sync. Automated testing of JSDoc and Markdown examples ensures that the examples in our docs match the current implementation, making it easier for team members to stay aligned. This is especially helpful in fast-paced environments where frequent changes occur, as it reduces miscommunication and the risk of errors.

3. Complex APIs and Libraries

APIs and libraries often come with intricate usage scenarios. Documenting these scenarios with accurate code examples is key to helping developers understand how to use the API effectively. With Deno's doc testing, we can validate the examples in our API documentation to guarantee that they remain correct as the API evolves. This is especially useful for libraries with complex inputs, outputs, or edge cases, ensuring that all documented behaviors are accurate.

4. Preventing “Code Rot” in Long-Lived Projects

In long-lived projects, code rot - where documentation becomes outdated over time - is a common issue. As codebases change, there's a higher risk that the examples in the docs no longer reflect reality. Deno's documentation testing automates the process of checking whether examples still work, providing a safety net that reduces the chances of documentation falling out of sync with the code.

5. Education and Learning Materials

For projects that include tutorials, learning materials, or onboarding guides, it's essential to keep the instructional code examples correct. By automating the testing of documentation examples, educators and content creators can ensure that all code in their materials is up-to-date and functional, providing a smooth learning experience for students or new developers.

Conclusion

Using Deno's deno test --doc feature is a simple yet powerful way to ensure our documentation stays accurate and aligned with our code. By automatically testing the examples embedded in our JSDoc comments and Markdown files, we prevent "code rot" and keep our documentation reliable. This feature not only enhances collaboration in team projects but also improves the user experience for open-source contributors and developers working with complex APIs. In the end, better documentation leads to better, more maintainable code - and Deno makes it easier to achieve both.

The RC release of version 2.0, which is now available, includes this feature. For more information, please visit their official blog.