emacsway / go-structurizr

A library for auto-generating C4 diagrams from Golang applications

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

go-structurizr

This library allows you to auto-generate C4 component diagrams out from the Golang code.

Exemplary output:

Example

How it works?

The library provides a set of tools (Scraper and View) that allow you to scrape and render given Golang structures into a C4 component diagram in *.plantuml format.

Scraper component reflects given structure in accordance with structure interfaces, predefined rules and configuration.

You may pass the scraped structure into a View definition which you can then render into a plantUML diagram code.

Scraper identifies components to scrape in one of the following cases:

  • type that is being examined implements an interface model.HasInfo.
  • type that is being examined applies to one of the rules registered in the scraper.

Components

Component Info

Structure model.Info is a basic structure that defines a component included in the scraped structure of your code.

type Info struct {
	Kind        string      // kind of scraped component
	Name        string      // component name
	Description string      // component description
	Technology  string      // technology used within the component
	Tags        []string    // tags are used to match view styles to component
}

Scraper

Scraper may be instantiated in one of two ways:

  • from the code
  • from the YAML file

In order to instantiate the scraper you need to provide scraper configuration which contains a slice of prefixes of packages that you want to reflect. Types that do not match any of the given prefixes will not be traversed.

config := scraper.NewConfiguration(
    "github.com/org/pkg",
)
s := scraper.NewScraper(config)

Having a scraper instantiated, you can register a set of rules that will allow the scraper to identify the components to include in the output structure.

Each rule consists of:

  • Set of package regexp's - only types in a package matching at least one of the package regexp's will be processed
  • Name regexp - only type of name matching regexp will be processed
  • Apply function - function that produces model.Info describing the component included in the scraped structure.
r, err := scraper.NewRule().
    WithPkgRegexps("github.com/org/pkg/foo/.*").
    WithNameRegexp("^.*Client$").
    WithApplyFunc(
        func(name string, _ ...string) model.Info {
            return model.ComponentInfo(name, "foo client", "gRPC", "TAG")
        }).
    Build()
err = s.RegisterRule(r)

The apply function has two arguments: name and groups matched from the name regular expression.

See the example:

r, err := scraper.NewRule().
    WithPkgRegexps("github.com/org/pkg/foo/.*").
    WithNameRegexp(`^(\w*)\.(\w*)Client$`).
    WithApplyFunc(
        func(_ string, groups ...string) model.Info {
            // Do some groups sanity checks first, then:
            n := fmt.Sprintf("Client of external %s service", groups[1])
            return model.ComponentInfo(n, "foo client", "gRPC", "TAG")
        }).
    Build()
err = s.RegisterRule(r)

Alternatively, you can instantiate the scraper form YAML configuration file:

// go-structurizr.yml
configuration:
  pkgs:
    - "github.com/org/pkg"

rules:
  - name_regexp: "^.*Client$"
    pkg_regexps:
      - "github.com/org/pkg/foo/.*"
    component:
      description: "foo client"
      technology: "gRPC"
      tags:
        - TAG

Regex groups may also be used within yaml rule definition. Here you can find an example:

rules:
  - name_regexp: "(\\w*)\\.(\\w*)Client$"
    pkg_regexps:
      - "github.com/org/pkg/foo/.*"
    component:
      name: "Client of external {1} service"
      description: "foo client"
      technology: "gRPC"
      tags:
        - TAG
s, err := scraper.NewScraperFromConfigFile("./go-structurizr.yml")

Eventually, having the scraper instantiated and configured you can use it to scrape any structure you want. Scraper returns a struct model.Structure.

structure := s.Scrape(app)

View

Similarly, to the scraper, view may be instantiated in one of two ways:

  • from the code
  • from the YAML file

In order to render scraped structure, you will need to instantiate and configure a view. View consists of:

  • title
  • component styles - styles are applied to the components by matching first of component tags with style ids
  • additional styling (i.e. line color)
  • component tags - if specified, view will contain only components tagged with one of the view tags. When no tag is defined, all components will be included in the rendered view.
  • root component tags - if specified, view will contain only those components which have connection (direct or in-direct) to at least one of components with root tag.

In order to instantiate default view, use the view builder:

v := view.NewView().Build()

In case you need to customize it, use available builder methods:

v := view.NewView().
    WithTitle("Title")
    WithComponentStyle(
        view.NewComponentStyle("TAG").
            WithBackgroundColor(color.White).
            WithFontColor(color.Black).
            WithBorderColor(color.Black).
            WithShape("database").
            Build(),
    ).
    WithComponentTag("TAG").
    WithRootComponentTag("ROOT").
    Build()

Alternatively, you can instantiate the view form YAML configuration file:

// go-structurizr.yml
view:
  title: "Title"
  line_color: 000000ff
  styles:
    - id: TAG
      background_color: ffffffff
      font_color: 000000ff
      border_color: 000000ff
      shape: database
  root_component_tags:
    - ROOT
  component_tags:
    - TAG
v, err := view.NewViewFromConfigFile("./go-structurizr.yml")

As the view is initialized, you can now render the structure into planUML diagram.

outFile, _ := os.Create("c4.plantuml")
defer func() {
    _ = outFile.Close()
}()

err = v.RenderStructureTo(structure, outFile)

Debug mode

In order to see detailed scraping or view rendering logs, set LOG_LEVEL env variable with debug of DEBUG.

Examples

You may find a couple of examples implemented in the cmd directory. In order to run any of those examples, please run the shell script attached.

Good practices

The best results and experience in using the library will be ensured by enforcing the following practices:

  • Having a solid and well-organized application context following clean-architecture principles will make your diagrams simple and easy to read. Also, this will allow you to create a short list of component types and styles.
  • Following consistent naming conventions will help you in creating simple and straight-forward scraper rules.

Full code documentation

https://pkg.go.dev/github.com/krzysztofreczek/go-structurizr

About

A library for auto-generating C4 diagrams from Golang applications

License:MIT License


Languages

Language:Go 98.9%Language:Shell 1.1%