Search code examples
plantuml

Documenting Layered Architecture with PlantUML


I want to document layered software architecture with plantUML that at the end will look like this:

enter image description here

What will be the best approach to create this type of diagram with plantUML?

This is the initial what I came up with, which represents 3 layered architecture with some generic components. (please check the link) enter image description here

@startuml
LAYER_3 -[hidden]down- LAYER_2
LAYER_2 -[hidden]down- LAYER_1

package LAYER_3 {
    component Comp30 {
    }
    component Comp31 {
    }
    component Comp32 {
    }
    component Comp33 {
    }
}

package LAYER_2 {
  component Comp20 {
  }
  component Comp21 {
  }
  component Comp22 {
  }
  component Comp23 {
  }
  component Comp24 {
  }
  component Comp25 {
  }
  component Comp26 {
  }
  component Comp27 {
  }
}

package LAYER_1 {
    component Comp10 {
    }
    component Comp11 {
    }
    component Comp12 {
    }
    component Comp13 {
    }
    component Comp14 {
    }
    component Comp15 {
    }
    component Comp16 {
    }
    component Comp17 {
    }
}

Comp23 -[#6666ff,dotted]> Comp10
Comp21 -[dotted,#red]> Comp10
Comp20 -> Comp10
Comp20 -> Comp16
@enduml

Solution

  • It's not ideal, but with some encouragement from carefully placed hidden arrows and judicious use of norank on the visible arrows, this is possible:

    PlantUML diagram with aligned layers

    The changes I made were:

    • Deleted the hidden arrows between the layers, since while this help with vertical alignment, they do not help with left-aligning.
    • Added hidden right arrows between each component in a layer, e.g. from Comp30 to Comp31, and Comp31 to Comp32, etc. This is necessary to encourage the components to remain in order within the layer.
    • Added hidden down arrows from the first component in each layer to the first component in the below layer. This encourages each layer to be left-aligned the same amount. Additionally, made this arrows long (e.g. --->) to create more space between the layers, so that there is more space for the visible arrows to be clearly distinguished.
      • However, if there will be a visible arrow between these two components, then the hidden one is omitted, because otherwise the hidden arrow causes the visible arrow to curve.
    • Added norank to all the visible arrows, to prevent them from breaking the layout that was encouraged by the hidden arrows.
      • However, for any visible arrow that is identical to a hidden one (e.g. the Comp20 to Comp10 arrow), the hidden arrow is omitted and the visible arrow is not marked as norank. Again, this is to avoid a curving arrow caused by having two arrows on the same connection. Essentially the visible arrow is serving the purpose of encouraging the right layout.

    Here are these modifications applied to your PlantUML example, or view it live here:

    @startuml
    package LAYER_3 {
        component Comp30 {
        }
        component Comp31 {
        }
        component Comp32 {
        }
        component Comp33 {
        }
    }
    
    package LAYER_2 {
      component Comp20 {
      }
      component Comp21 {
      }
      component Comp22 {
      }
      component Comp23 {
      }
      component Comp24 {
      }
      component Comp25 {
      }
      component Comp26 {
      }
      component Comp27 {
      }
    }
    
    package LAYER_1 {
        component Comp10 {
        }
        component Comp11 {
        }
        component Comp12 {
        }
        component Comp13 {
        }
        component Comp14 {
        }
        component Comp15 {
        }
        component Comp16 {
        }
        component Comp17 {
        }
    }
    
    ' Hidden connections
    ' ------------------
    
    ' Use hidden right connections to encourage the components
    ' within each layer to be placed in the desired order.
    Comp30 -[hidden]r- Comp31
    Comp31 -[hidden]r- Comp32
    Comp32 -[hidden]r- Comp33
    Comp20 -[hidden]r- Comp21
    Comp21 -[hidden]r- Comp22
    Comp22 -[hidden]r- Comp23
    Comp23 -[hidden]r- Comp24
    Comp24 -[hidden]r- Comp25
    Comp25 -[hidden]r- Comp26
    Comp26 -[hidden]r- Comp27
    Comp10 -[hidden]r- Comp11
    Comp11 -[hidden]r- Comp12
    Comp12 -[hidden]r- Comp13
    Comp13 -[hidden]r- Comp14
    Comp14 -[hidden]r- Comp15
    Comp15 -[hidden]r- Comp16
    Comp16 -[hidden]r- Comp17
    
    ' Use hidden down connections between the first component in each
    ' layer to encourage all the layers to be left-aligned.
    ' NOTE: Use longer arrows to force more space between the layers, so
    ' that the visible arrows can be more clearly distinguished.
    ' NOTE: Since we later create a *visible* connection from Comp20 to
    ' Comp10, we omit create a hidden connection here, otherwise the
    ' visible connection ends up curving to avoid the hidden one.
    Comp30 -[hidden]d-- Comp20
    'Comp20 -[hidden]d-- Comp10
    
    ' Visible connections
    ' -------------------
    
    ' NOTE: Use norank to prevent these visible connections from taking
    ' prescedence over the hidden connections and breaking the layout,
    ' *except* for the visible connections which are equivalent to the
    ' hidden connections that we have omitted.
    Comp23 -[norank,#6666ff,dotted]-> Comp10
    Comp21 -[norank,dotted,#red]-> Comp10
    Comp20 -d--> Comp10
    Comp20 -[norank]-> Comp16
    @enduml
    

    For reference, I found this guide helpful in encouraging the right layout. In particular, it introduced me to the norank property. However, I fear this answer goes against the advice from that same page that these "layout tweak mechanisms [should] be used sparingly". The page also says:

    Wrangling diagram elements to an exact position or layout is not what PlantUML is for.

    I suspect that the approach I have taken will become increasingly brittle as the diagram grows in size and complexity, to the point of become untenable, but in the absence of a better solution it might be sufficient for simpler use cases.