References
LikeC4 uses the lexical scope, with hoisting, almost like in JavaScript.
To understand references, we need to understand scopes first.
Example:
model { service service1 { component api component frontend }}
Every element is unique in the model, so we can add a relationship referencing them, like:
model { service service1 { component api component frontend } frontend -> api}
But if we add service2
with another api
:
model { service service1 { component api component frontend } service service2 { component api }
frontend -> api // ⛔️ Error: 'api' not found}
The reference is ambiguous, as there are two api
components in the model.
Every element creates a new scope inside {...}
, so api
is unique inside service1
and service2
,
but not in the scope of model
.
We can resolve by moving the relationship to the scope of service2
:
model { service service1 { component api component frontend } service service2 { component api
frontend -> api // ✅ This is OK, // 'api' is unique in 'service2' // 'frontend' is unique in 'model' }}
Hoisting
Section titled “Hoisting”In LikeC4, the element, besides being hoisted in its scope, also “bubbles” to the upper scopes, if it stays unique.
We may reference something that is not yet declared but will be hoisted later.
The relationship on line 8 references graphql
defined below on line 15:
model {
service service1 { component api component frontend
frontend -> api // ✅ This is OK, references to 'api' from 'service1' frontend -> graphql // ✅ This is OK, references to unique 'graphql' }
frontend -> api // ⛔️ Error: 'api' is ambiguous
service service2 { component api component graphql
frontend -> api // ✅ This is OK, references to 'api' from 'service2' }
}
Fully qualified names
Section titled “Fully qualified names”Top-level elements (placed directly in the model
block) are available globally.
To reference nested elements we use their fully qualified names (FQN).
Example:
model { service service1 { component api component frontend } service service2 { component api }
frontend -> api // ⛔️ Error: 'api' not found frontend -> service1.api // ✅ This is OK frontend -> service2.api // ✅ This is OK}
Or even:
model { service service1 { component api component frontend { -> service2.api } } service service2 { component api }}
Some parts may be omitted, if FQN stays unique:
model { service service { component backend1 { component api } component backend2 { component api component graphql } }
frontend -> service.backend1.api // ✅ Non-ambiguous fully qualified name
frontend -> backend1.api // ✅ This is OK, 'api' is unique in 'backend1', // and 'backend1' is unique in the model // We may omit 'service'
frontend -> backend2.api // ✅ This is also OK
frontend -> service.api // ⛔️ Error: 'api' is ambiguous in 'service'
frontend -> service.graphql // ✅ This is also OK, we omit 'backend2' // as 'graphql' is unique in 'service'}