Leveraging PlantUML for Model Driven Development
Continuously Deliver your Models and Code Designs with PlantUML
Model Driven Development (MDD) emphasizes delivering the engineering model before the code. Whether generating code or writing it from scratch, the code should accurately represent the model. Tools like PlantUML have made modeling developer-friendly.
We together will have a look on MDD, pros and cons and then we will see how PlantUML can solve MDD's shortcomings
Value of MDD
It all starts with the requirements, where stakeholders typically deliver requirements mostly in textual form or a combination of text and diagrams.
From my experience, conducting requirements gathering is akin to a social experiment where all involved parties—stakeholders, product owners, and team members—share their vision. Visualizing this vision is best achieved through diagrams, a widely used practice in modern day development.
Another important observation I've noticed in international teams is that while we all communicate in English, whether verbally or in written forms, there are subtle differences imposed by two factors:
We all come from different backgrounds. What you say can mean different things for others, even if the word's meaning is clear. Yet contextually, it might differ depending on the recipient's background.
Non-native speakers of English often face challenges in expressing themselves fully, resulting in language that may lack detail, be overly simplistic, or a combination of both.
This solidly manifests the importance of a universal language we can all speak.
The Unified Modeling Language (UML) and its extension, the System Modeling Language (SysML), provide a universal language that the whole team can communicate with.
This language is supported and maintained by OMG, a software consortium that sets standards in the area of distributed object computing.
One significant advantage of Model-Driven Development (MDD), which happens to be my favorite, is its ability to encapsulate system requirements on a single A4-sized paper. This ensures that all parties involved in development share a common visualization of the system.
If one A4-sized paper is insufficient, it suggests inadequate abstraction. Additional details can be incorporated per building block. Don't worry about the lack of details due to abstraction; you can always add more details for each system element, each encapsulated in another A4-sized paper.
This approach is beneficial as it prevents overload of the recipient's short-term memory, thereby enhancing comprehension of the system. It allows for the visualization of the system's building blocks, which are constructed one A4-sized paper at a time.
Moreover, it enables the recipient of the requirements to choose the level of detail to delve into.
MDD Short Comings
Lack of Clarity
Since any model is an abstraction, models can become enigmatic if cooperation between the involved parties occurs late in the modeling process. This leads us to the next shortcoming: limited collaboration.
Limited Collaboration
Teams often tend to shy away from the idea of modeling due to its time-consuming nature. Even when they choose to engage in modeling, the models are often not adequately maintained. Maintaining diagrams proves to be challenging for several reasons:
Tooling Limitations:
lack features for seamless collaboration and version control, making it difficult for teams to maintain and update diagrams effectively.
The complexity of traditional modeling tools may deter team members from actively engaging in model maintenance.
Software Development Process is Dynamic!
Coming from an agile environment, it is not only time consuming but annoying to develop on 2 tools in parallel, one for coding another for modelling.
Consequently, reviews becomes tedious and confusing where the reviewer is reviewing one product reflected on 2 different platforms/tools
PlantUML as a Solution
PlantUML is a simple yet powerful tool that enables users to create diagrams from plain text. It facilitates the creation and customization of UML diagrams and other supported diagram formats with great ease, thanks to its elaborate documentation.
So lets shed some light on how it counters the short comings mentioned above.
Modularity
PlantUML can be integrated, for instance, into VSCode with ease where you can generate diagrams while developing.
Simplicity
PlantUML is simple to use, just type the text and press "Alt+D" and your diagram will be generated automatically, you do not even need to keep pressing "Alt+D" to update the diagram after updating the text.
Continuous Delivery Made Easier
PlantUML is text based, so binaries or non-version control friendly files are not required, making it easy to share your model(s) altogether with your code. This promotes easier peer reviews as well for 2 reasons:
The reviewer is reviewing the model and the code using the same reviewing tool.
The reviewer now can compare what is intended (the design/intent) vs. what is implemented (source code) altogether promoting an enhanced review process.
Lets Have a Closer Look on PlantUML
Integrating PlantUML with VSCode
Before delving into our example and how to use PlantUML lets integrate it first within VSCode.
Note: I am rendering diagrams locally for PlantUml server render, check this page.
Installing is easy on 3 steps:
To start using the PlantUML, all you need is
Create a file with any PlantUML's extensions such: .plantuml, pu, puml, even that for convenience.
Enter PlantUML guards then your code in between these guards
@startuml some_name diagram based code more code ... @enduml
Now, Lets get our hands dirty with a brief and simple example.
Coin Flipper
To demo how easy the usage of PlantUML I will represent a simple application basically a "Coin Flipper" application.
We will write PlantUML text based script to generate a state diagram representing the coin's state.
We will have a look on the code to compare "Coin" class with the generated class diagram, in this example, I am using C++.
Requirements
The coin shall be initialized with an initial state.
The coin shall has a set of states = {Heads, Tails} only.
The coin shall be in either of the mentioned states.
When Flipped the coin randomly flipped in either of the states.
The user shall be able to enquire for the coin's state.
The user shall be able to flip the coin.
Coin's State Diagram
To model the system's state diagram with PlantUML here is the code:
@startuml coin_state_diagram
hide empty description
scale 1000 width
state entry_choice <<choice>>
[*] --> entry_choice : [mCoinState]
entry_choice -[dashed]-> Tails
entry_choice -[dashed]-> Heads
entry_choice -[dashed]-> Tails
entry_choice -[dashed]-> Heads
Heads -> Heads
Heads -> Tails : Toss\n && [mCoinState == Tails]
Tails -> Tails
Tails -> Heads : Toss && [mCoinState == Heads]
@enduml
@startuml and @enduml are must to start a uml creation script, the name can be next to the @startuml, I prefer adding the file name.
entry_choice is a state diagram element can be created by defining a state object of type "<<choice>>"
[*] : entry point annotated with "[mCointState]" as the choice will be based on the initial value of "mCointState"
Then from choice arrows head towards both states, since this is not concurrent we use dashed lines to emphasize it is a choice depends on the initial "mCoinState".
Heads transition to Tails and vice versa
There are self transition, in other literatures called state restart, for each state
To Generate the diagram for the first time press "Alt+D", after that whenever the editor is updated, your development view shall be some like the following
You can just export the diagram by copying it.
Coin's Class and Class Diagram
Now lets compare the class diagram to the class implementation.
the class is fairly simple, only one enum and 2 methods, one to reveal the state and another to flip the coin.
#include <string>
class Coin
{
public:
enum CoinState
{
eHeads = 0,
eTails,
eCointStatesCount
};
Coin(CoinState const coinInitialState = eHeads);
std::string FlipCoin();
std::string GetCoinState() const;
~Coin();
private:
CoinState mCoinState;
};
Now lets create a file class_coin.plantuml to create a simple class diagram.
@startuml coin_class
Coin +-- CoinState
enum CoinState
{
eHeads
eTails
}
class Coin
{
- CoinState mCoinState
--
+ Coin(CoinState const coinInitialState = eHeads)
+ std::string FlipCoin()
+ std::string GetCoinState() const
}
@enduml
Analysis:
Starting a Class UML:
Start a UML diagram via @umlstart and @umlend, you can give a name to the UML, I prefer the file name, feel free to add what you see fit.Creating Class Blocks:
Define your classes like how you would define them in C++, I defined the enum as well for show casing purposes.Attributes visibility:
Public : add + before the attribute.
Private : add - before the attribute, pretty much intuitive, huh.
for the rest of options you can check PlantUML documentation in the references.
Relationships, the enum is part of the class, defined as "Containment" relationship "Coin +-- CoinState" which is the same as "CoinState --+ Coin". You can full source code in references.
Inheritance/extension: A --|> B
Composition: A --* B
Aggregation: A --o B
Lets check the result together:
Conclusion
Model Driven Development is not a new concept, and with tools like PlantUML, the continuous delivery of a source code accompanied by its model becomes easier, enhancing the development experience and enhancing the collaboration within the development team and stakeholders as well.