Views
Views are the architecture diagrams, projections of the model from different perspectives, with different levels of details, like:
- System / service overviews
- Components interactions in specific use case
- Data flows and sequence diagrams
View definition
Views are defined in views
section.
Views may be named (must be unique) or unnamed (can’t be referenced):
views { // with name view index { } // unnamed view { }}
View’s name is used as a filename during the export, and a URL part for the sharing, so better to define it.
Views may have a title, description, tags and links (same as model element):
views {
view epic12 { #next, #epic-12 title "Cloud System - Changes in Epic-12" description " This diagram shows the high-level components and interactions. "
link https://my.jira/epic/12
include * }
}
Properties should be defined before any predicates.
Scoped views
View may be defined for some element (view of ..
).
View inherits the scope of the element:
views {
view { include api // ⛔️ Error: 'api' is not found }
view of cloud.backend { include api // ✅ This is OK, references 'cloud.backend.api' }
}
This view becomes the default view for the element:
views {
view view1 of cloud.backend { include * }
view { // on click navigates to 'view1', because it is the default view for 'cloud.backend' include cloud.backend }
}
You may have multiple views for the same element, but which one is default is not determined.
View predicates
Views are not static, they reflect any changes in the model.
Two types of predicates define what elements/relationships are visible.
Element predicates
Element predicates explicitly define what elements are visible, regardless of the relationships.
view { // Only backend is visible include backend
// Add frontend to the view // and its relationships with backend include frontend
// Add authService to the view // and its relationships with visible backend and frontend include authService
// Add nested elements of messageBroker (but not messageBroker), // and their relationships among themselves and visible backend, frontend and authService include messageBroker.*
// Exclude emailsQueue and its visible relationships exclude messageBroker.emailsQueue}
Combining
Predicates may be combined. The following is equivalent to the previous example:
view { include backend, frontend, authService, messageBroker.*
exclude messageBroker.emailsQueue}
Wildcard
Wildcard predicates may be used to reference “everything”, but it depends on the context.
Assume we have the following model:
model { actor customer { -> webApp 'uses in browser via HTTPS' } system cloud { container backend { component api } container ui { component webApp { -> api 'requests data' } } }}views {
// Unscoped view view { include * // Visible top-level elements: customer, cloud // and derived relationship customer -> cloud }
// Scoped view view of cloud.ui { include * // Visible: // - cloud.ui // - cloud.ui.webApp // - customer, and relationship customer -> cloud.ui.webApp // - cloud.backend, and derived relationship cloud.ui.webApp -> cloud.backend }}
With overrides
It is possible to change element properties just for this view:
view { // Include the element and override its properties include cloud.backend with { title 'Backend components' description '...' technology 'Java, Spring' color amber shape browser }}
With custom navigation
It is possible to define custom navigation and links between views:
view view2 { include * include cloud.backend with { // navigate to 'view3' on click navigateTo view3 }}
view view3 { include * include cloud.backend with { // the same element, but navigate back to 'view2' navigateTo view2 }}
By element kind or tag
// elements by kindinclude element.kind != systemexclude element.kind = container
// elements by taginclude element.tag != #V2exclude element.tag = #next
Relationship predicates
These predicates include elements from the satisfied relationships only.
Based on the model from wildcard example:
Incoming
Include elements that have incoming relationships from visible elements:
view { // visible element include customer
// include nothing, customer has no relation to backend include -> backend
// add ui, // because customer has a relationship with nested ui.webApp include -> ui
// add backend, because visible ui has a relationship to backend // derived from ui.webApp -> backend.api include -> backend}
// This view includes customer and uiview { include customer, -> cloud.*}
Outgoing
Include elements if only they have outgoing relationships to visible elements:
include customer ->include cloud.* ->
In/Out
Include nested elements of cloud
, that have any relationships with visible elements:
include -> cloud.* ->
Directed relationships
Include elements if they have relationships of specific direction:
include customer -> cloud.*
Any relationship
Include elements if they have any relationships:
include customer <-> cloud
Expand predicate
Expand predicate is a mix of element’s and relationship’s.
Include cloud
element and its children that have in/out relationships with visible elements:
include cloud._
// Same asinclude cloud, -> cloud.* ->
Auto-layout
view { include * autoLayout LeftRight}
Possible values are TopBottom
(default), BottomTop
, LeftRight
, RightLeft
.
Style predicates
Style predicates define how elements are rendered.
Example from BigBank:
view apiApp of internetBankingSystem.apiApplication {
include *
// apply to all elements style * { color muted opacity 10% }
// apply only to these elements style singlePageApplication, mobileApp { color secondary }
// apply only to apiApplication and its descendants style apiApplication, apiApplication.* { color primary }
// apply only to the tagged elements style element.tag = #deprecated { color muted }}
Extend views
Views can be extended to avoid duplication, to create a “baseline” or, for example, “slides” for a presentation:
views {
view view1 { include * }
view view2 extends view1 { title 'Same as View1, but with more details'
style * { color muted }
include some.backend }
// cascade inheritance view view3 extends view2 { title 'Same as View2, but with more details'
include * -> some.backend }
}
The predicates and style rules of extended views are merged with the ones from ancestors.
Extended views also inherit the scope:
views {
view view1 of cloud.backend { title 'Backend components' }
view view2 extends view1 { include api // ✅ This is OK, references 'cloud.backend.api' }
}