0.1.1 • Published 5 years ago

aac-cli v0.1.1

Weekly downloads
10
License
MIT
Repository
github
Last release
5 years ago

architecture-as-code

CircleCI codecov

A project to help define architecture logically as code, and generate living, interactive diagrams.

Design Goals

The goals of this project are to allow a team to define architecture declaratively, as simple yaml files, and have interactive diagrams and visualisations generated automatically.

At a high level:

  1. Developers and tech leads should be able to collaborate on architecture using standard practices such as pull-requests, code reviews, etc.
  2. The 'toil' of generating the diagrams and artifacts should be eliminated.
  3. The system should be simple enough to very quickly define an architecture at a high-level, then layer on details as needed.
  4. The system should allow 'multidimensional' models, allowing logical architecture to be defined, but also allow the viewer to 'dive' into lower level details, such as physical or network infrastructure if needed.
  5. The system should allow UI developers to rapidly create 'styles' for renderings, or custom renderers for typed entities.

High-Level Requirements

A team should be able to use a yaml file to represent logical or physical architecture. There are three types of entities:

Components

A component is any logical or physical entity. It might be a system, such as an ESB, a server, a switch, and storage service, and so on.

Containers

A conatainer is any logical grouping of components. It could be a logical container (such as 'Front End Services'), or a technical container (such as an AWS region).

Connections

A connection is a relationship between components or containers. It could be logical, such as a dependency between a service and a database, or a technical connection, such as a potential HTTP connection between a mobile app and a web server, via a gateway.

Level

A 'level' is an optional concept which may represent a 'zoom' of the diagram. For example, level 1 in a diagram might be the high level architecture. Level 2 might be the specific services and systems, level 3 might be the physical infrastructure on which an instance resides. By providing levels, diagrams should be able to be 'zoomed' as needed.

Aspect

An 'aspect' is a 'view' of the system. For example, the infrastructure aspect might only show physical and network infrastructure for the on-premise data center, which the 'cloud' aspect might show only the cloud components.

Technical Notes

The in-memory structure may be best represented as a graph.

Containers, components and connections should be rendered in a simple 'boxes and lines' fashion.

It should be possible to give a container, component or connection a 'type', from a pre-defined library. For example, a specific type might be an 'EC2 Instance'. Each type has a schema, of required and optional fields. Each type should also have an associated 'renderer', which allows the type to be rendered in a specific way (for example, an EC2 instance might be rendered with the AWS EC2 logo, with the instance name at the lower side and the instance type at the upper right side).

It should be possible to associate arbitrary metadata with entities, to allow custom rendering if needed.

It should be possible to specify 'levels'. Levels would

Examples

Below are a few examples, highlighting a proposed format.

A simple, three tier application

The code might look like this:

title: Three Tier Application
author: Dave Kerr

---

container:
  id: channels
  name: Channels

container:
  id: services
  name: Services

container:
  id: databases
  name: Databases

component:
  name: Mobile App (iOS)
  container: channels

component:
  name: Mobile App (Android)
  container: channels

component:
  name: Website
  container: channels

component:
  id: api_gateway
  name: API Gateway

component:
  name: Application Server
  container: services

component:
  name: Application Database
  container: databases

connection:
  from: channels
  via:
    - api_gateway
  to: services

connection:
  from: services
  to: databases

The resulting diagram should be rendered as something like this:

Example 1: Diagram

Other Ideas

Some additional features would would be useful:

  1. Creating a structure from Terraform files
  2. Creating a model from an external structure, such as AWS
  3. Layering data from an APM such as New Relic in real-time
  4. WebGL rendering

Policy Enforcing

Enforce policies. Go to AWS, highlight any resource which is not part of an architecture schema. Allows existing environments to be audited, e.g show me resources which don’t fit into my defined architecture. This is potentially quite a useful feature, allowing an existing cloud set up to be audited against a well defined architectural spec.

Alternatives

Current solutions which are similar in nature:

  • Structurizr: Create diagrams based on Markdown or AsciiDoc

Technical Design

  1. Parser: The parser will read the yaml file, validate it for syntax and structure, then produce an in-memory model. Suggested implementation is a Node.js module which can be run in-memory to validate the structure, and load into an in-memory representation, or as a cli to vlidate from the commandline. This will allow validation to happen as part of a CI/CD process, to allow Pull Requests on the structure to be validated.
  2. Visualiser: The visualiser will use the parser to build the in-memory model, which will be rendered to an HTML5 Canvas (or perhaps in 3D). Suggested implementation is a simple HTML SPA.
  model.yaml  --> validator --> warnings, errors, model.json
  model.json  --> inflator  --> warnings, errors, model-inflated.json
  model-inflated --> renderer --> visualisation

Other options:

  • A CLI to render a PNG of the diagram, potentially highlighting a 'diff' for a pull request.

Model Compilation

A model is simply the yaml representation of an architecture. This representation is designed to be as easy as possible to be created and maintained by a human. Therefore, we want to provide a simple, declarative schema to define architectures.

However, to render a model, we must first build an intermediate structure, which is the 'compiled model'. The reason that the model must be compiled is that there are elements of a model which do not have to be defined in the yaml, but which are still required to be rendered. This compiled model is built with the compile function. The compiler will:

  1. Validate that the model is syntactically and semantically correct
  2. Assign an id to every entity which does not have one explicitly defined
  3. Build a graph of entities, starting from an artificial root entity

The following features of the compiler are not yet completed:

  1. Link entities together, for ease of traversal (e.g. child entities have a parent reference, parent entities have a children reference. NOTE: This brings in a small challenge which is that the compiled model cannot be serialized as a POJO, due to potential circular references. One simple approach to deal with this would be to unlink the model by replacing parent with parentId, children with childrenIds and so on. This would be straightforward to read in the serialized compiled model, and straightforward to re-link after loading the model.

The CLI

Some ideas for the CLI interface:

aac validate # validate a model
aac render   # render a model
aac import   # create a model from an external structure
aac diff     # compare models, or a model to an external structure
  • Consider yargs rather than commander
  • Consider inquirer for cli guidance

API Documentation

The key APIs are documented below.

Validate

Validates the structure of a model YAML, and returns the in-memory representation of the model:

const modelYaml = fs.readFileSync('model.yaml', 'utf8');
const { model, errors, warnings } = validate({ modelYaml });

console.log(`${errors.length} errors`);
console.log(`${warnings.length} warnings`);
console.log(`Model: ${JSON.stringify(model, null, 2)}`);

Developer Guide

Common tasks can be run from the makefile

CommandUsage
make testLint and test the code.
make circleInstall the CircleCI CLI and run the CircleCI build locally.

TODO

  • aac ./some/file.yaml shows no output - it should demand a command
  • meta field on anything, just key value pairs. Use it as a 'dumping ground' (e.g. platform: as400) when building models, until you find a structured location for it. When rendered, available as a tooltip.
  • styling should be handled with a separate css file, which can use classes, selectors etc. Regardless of whether the renderer is HTML, CSS provides a known framework for styling.
  • aac demo - creates a three-tier architecture, renders and watches it, with an informative message. One command to show all the good stuff.
  • validate should give a unique id to all elements