How to Develop a Revision-Controlled Software Architecture With Mermaid.js

Consider this JavaScript-based tool that allows you to create diagrams and visualizations in unified modeling language.

Jacob Beningo

May 29, 2024

5 Min Read
An example of a UML diagram demonstrating a led_io class that controls an I/O LED through a dio interface.Jacob Beningo

At a Glance

  • Mermaid.js allows you to generate a diagram from text.
  • Other solutions such as Git and CI/CD allow you to develop diagrams using code.

According to IEEE 1471, “A software architecture is the fundamental organization of a system embodied in its components, their relationship to each other and the environment, and the principles guiding its design and evolution.”

Developing a software architecture for your system is a fundamental activity every embedded software team should do. In many cases, teams will use popular graphical tools that support UML to architect their systems. 

Unfortunately, there are several issues with the most used tools:

  1. They are graphical in nature, which means you can’t easily use diff to compare different versions of the architecture.

  2. The architecture is kept separate from the code, which means it’s likely to be out of sync with what is developed. 

An exciting solution to these problems is for teams to adopt tools that use Markdown or are inspired by it. Since Markdown is text, it can easily be revision controlled in Git with the code, and the standard git diff and other tools apply! 

An example tool that I’ve been using recently is Mermaid.js.

Note: I’m not involved or have any interactions with this project other than thinking it’s cool and using the tool myself!

What Is Mermaid.js?

According to the Mermaid intro page, “Mermaid lets you create diagrams and visualizations using text and code.” It’s a JavaScript-based tool allows you to create UML diagrams using Markdown-like syntax. For example, featured above is a diagram I created that might demonstrate the design for a led_io class that leverages a dio interface class.

Related:3 Tips for Getting Started with CI/CD

As you can see, the diagram created for this design looks just like your typical UML diagram. The question, though, is, “How was this diagram created?”

Creating a UML diagram in Mermaid

As I mentioned earlier, the diagram in the above figure was generated from text. For our example, I just used the mermaid.live visual interface. I created a classDiagram and then specified the classes and the relationships between them. The code looked something like the following:

classDiagram

    led_io <|-- dio_base

    dio_base <|-- dio_stm32

    dio_base <|-- dio_c2000

    dio_base <|-- dio_host

class led_io{

        -port_t: port_t

        -pin_t:  pin

        -dio_base *: dio

        +led_io(dio_base *, port:port_t, pin:pin_t)   

    }

class dio_base{

      <<interface>>

      +read(port:port_t, pin:pin_t)

      +write(port:port_t, pin:pin_t, state:dioState_t)

    }

class dio_stm32{

        +dio_stm32(DioConfig_t *)

    }

class dio_c2000{

        +dio_c2000(DioConfig_t *)

    }

class dio_host{

        +dio_host()

Related:Will AI Replace Embedded Software Developers?

    }

There are a few key points to notice in this code. 

First, we use classDiagram to specify that it’s a class diagram, not a flowchart, sequence diagram, or something else. 

Next, you can see that we have several classes defined using the class keyword. Each variable or method is specified as either public (+), private (-), or protected (#). If it’s a method, it ends up in the method section of the class. If it’s a variable, it ends up in the variable section. The differentiator is whether () is included.

Finally, once the classes are designed, you can use several symbols to specify the class relationships. For example, I used <|--, which specifies an inheritance relationship. Other relationships can be used as well, such as:

<|--

Inheritance

*--

Composition

o--

Aggregation

-->

Association

--

Link (Solid)

..>

Dependency

..|>

Realization

..

Link (Dashed)

If you’re wondering where you find this information, the Mermaid documentation has a lot of examples! You can see the documentation for class diagrams here. That documentation links to the documentation for other diagrams that you may want to create. 

Using Mermaid in Your Development Workflow

One problem we are trying to solve is updating our diagrams with our code. To do so, we want to be able to generate diagrams with our CI/CD pipelines or in our development workflow. 

This can be done by using the Mermaid CLI. You could install this in a Docker container, and then every developer will have access to it, including your CI/CD workflow. You can include a script that runs through your diagram code and generates the latest architectural images using something like:

mmdc -I diagram.mmd -o diagram.png

The question, though, is, how can you, as a developer, see the diagrams and integrate them closely with the software you are writing? 

Using the Mermaid VS Code Extension

Mermaid has several plug-ins that can be used with typical applications to generate the Mermaid visualizations if you don’t want to use the live editor. These plug-ins include software packages like:

  • ChatGPT

  • JetBrains IDE

  • Microsoft PowerPoint

  • Microsoft Word

  • Visual Studio Code

That last one is particularly interesting! A lot of developers have adopted VS Code as their main editor. You can learn a little bit about how to install the extension and use it here.

There are a few caveats about using the plug-in. First, you need to have a Mermaid Chart account and service. There is a free tier that limits you to only five diagrams. Second, you need to connect your Mermaid Chart service to the plug-in. Finally, you need to connect your account using some secure tokens to get it to work.

The fact that the free version is limited to 5 diagrams will make any developer or team hesitate. After all, we were looking for a free or inexpensive tool that helps us keep our diagrams in sync with our code and can be used with our typical Git workflows.

Looking at the pricing, it didn’t seem too expensive—less than $10 per developer. For me, the tool must provide value that is worth it. I found that the tool allows team collaboration and tight integration between your code and the diagrams. You can read more about how that works at the VS Code Extension link I gave earlier. 

I think the above feature is cool, but it’s unnecessary. Just a feature to help provide seamless integration between the diagrams and the code. (Did I mention I think it’s cool?). 

The Bottom Line

Keeping your diagrams and code in sync can be challenging. On top of that, it can be hard to track changes to your architecture over time and between versions. 

There are solutions out there that allow us to develop your UML diagrams using code. That code can then be added to your typical workflow. Git can track versions and compare differences and changes to the architecture. CI/CD can be used to insert the diagram images into documentation. 

In some cases, you may even be able to integrate the diagrams so that they directly interact with your code! 

At the end of the day, finding a code-based solution that can live with your application code will ensure that the architecture isn’t forgotten and stays up to date. 

About the Author(s)

Jacob Beningo

Jacob Beningo is an embedded software consultant who currently works with clients in more than a dozen countries to dramatically transform their businesses by improving product quality, cost and time to market. He has published more than 300 articles on embedded software development techniques, has published several books, is a sought-after speaker and technical trainer and holds three degrees which include a Masters of Engineering from the University of Michigan.

Sign up for the Design News Daily newsletter.

You May Also Like