Skip to content

Calpano/featdoc

Repository files navigation

Featdoc - Feature Documentation as Code

featdoc

  • is a documentation-as-code tool, which generates wiki pages in Markdown syntax including Mermaid diagrams.

  • generates complete sequence diagrams from interacting systems, defined by simple rules

Example

sequence diagram

The example models a restaurant. From the source code, the resulting markdown is deployed to an Azure DevOps wiki, the Coffee-Wiki (and here is the sequence diagram above).

Technical Model
  • Create a Universe

Universe UNIVERSE = new Universe();
  • Create a System

System WAITER = UNIVERSE.system("waiter", "Waiter", "Waiter");
  • Define a Rule within a system (grouped by Feature)

WAITER.feature("Coffee Serving")
  .rule(orderEspresso, CoffeeMachine.espresso, MobileOrderClient.createOrder, MobileOrderClient.addItemToOrder)
  .rule(customerWantsToPay, MobileOrderClient.createBill, Customer.receiveBill);
  • Create some more systems and rules

  • Create a Scenario

Systems.UNIVERSE.scenario("Lunch-Customer (in a hurry)")
  .step(CUSTOMER, Waiter.orderEspresso)
  .step(CUSTOMER, Waiter.customerWantsToPay, "Today no credit cards");
  • Generate in one go wiki pages for each system and each scenario

The World of Coffee
world of coffee

Compare the hand-drawn domain image with the featdoc auto-generated system diagram.

Configuration
  • The example WikiContext defines the mermaid block style, an optional preamble for all pages, the language (en or de), as well as some paths.

  • The example technical model is just one class. Larger models can be split up into multiple files, e.g. one per system.

Getting Started

  1. Add feat as a test dependency

    Maven Coordinates
    <!-- https://mvnrepository.com/artifact/de.xam/featdoc -->
    <dependency>
        <groupId>de.xam</groupId>
        <artifactId>featdoc</artifactId>
        <version>1.0.0</version>
    </dependency>
  2. Define your technical model

    • Create a Universe — see the Example

  3. Generate wiki pages

    • wikiContext: Configure resulting wiki syntax (Azure DevOps Mermaid Blocks vs. Normal)

    • Run featdoc tool

      FeatDoc.generateMarkdownFiles( universe, wikiContext );
  4. Take generated wiki pages live

    • For Azure DevOps wiki: Upload via git push

Concept

  1. The core idea is to model isolated systems, each containing simple rules: Mapping one trigger to multiple actions. Each system has an API defined by messages, which are incoming (such as REST API calls) or outgoing (such as business events). Rules are grouped into features. This just makes organising them easier.

    rule
    Figure 1. Rule
  2. A scenario now merely defines an initial trigger, causing a chain reaction of systems sending messages to each other. As one rule can cause several actions, the result can be rendered tree-like or as a sequence diagram.

  3. A message is produced by one system (or a scenario) and consumed by zero or more systems (as defined in its rules).

    • A message is defined by a system. E.g. the vendor of the system defines the message structure and contents. Also, the vendor will likely provides API docs for the message.

    • Typical messages are API calls (incoming & synchronous) or business events (outgoing & asynchronous).

      Table 1. Kinds of Messages
      Direction Timing Examples

      incoming

      synchronous

      API call in a REST API

      User interface input (e.g. click)

      outgoing

      synchronous

      REST Callback/Web Hook

      User interface result (any UI reaction)

      incoming

      asynchronous

      Incoming event

      outgoing

      asynchronous

      Outgoing (business) event

Cookbook

How do I model conditional rule actions?

You can’t. But you can add a comment to a rule action, which will be visible in all generated views.

MYSYSTEM.feature("my feature")
    .rule(triggerMessage, optionalTriggerComment)
        .action(actionMesage, optionalActionComment)
        // more actions
    .build;
How to represent scheduled calls?

Define a System called "Scheduler" with messages like

System SCHEDULER = UNIVERSE.system("scheduler", "Scheduler", "Scheduler");
Message schedulerEvery2Minutes = SCHEDULER.asyncEventOutgoing("Every 2 Minutes");

and invoke them from the scenario.

How to model my systems?
  1. Create all systems in one interface

    interface Systems {
        Universe UNIVERSE = new Universe();
        System CUSTOMER = UNIVERSE.system("customer", "Customer", "Customer");
        System WAITER = UNIVERSE.system("waiter", "Waiter", "Waiter");
        System CM = UNIVERSE.system("coffee", "Coffee Machine", "CoffeeMachine");
        System MOC = UNIVERSE.system("moc", "Mobile Order Client", "Mobile");
        System POS = UNIVERSE.system("pos", "Point of Sale System", "POS");
        System ACC = UNIVERSE.system("accounting", "Accounting System", "Accounting");
    }
  2. Model each `System’s rules within an interface, like this

    /** Point-of-Sale System */
    interface PosSystem {
    
        Message createOrder = POS.apiCall("Create order for table");
        Message searchOrdersForTable = POS.apiCall("Search order of given table");
        Message addItemToOrder = POS.apiCall("Add item");
        Message addTaxesToOrder = POS.apiCall("Add taxes");
    
        static void define() {
            POS.feature("Tax Integration")
                    .rule(addItemToOrder, AccountingSystem.calculateTax, addTaxesToOrder);
        }
    }

About

Feature documentation made easy: docs-as-code

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published