Pular para o conteúdo

Referências

O LikeC4 usa escopo léxico com hoisting, quase como no JavaScript.

Para entender referências, precisamos primeiro entender escopos. Exemplo:

model {
service service1 {
component api
component frontend
}
}

Cada elemento é único no modelo, então podemos adicionar um relacionamento referenciando-os, assim:

model {
service service1 {
component api
component frontend
}
frontend -> api
}

Mas, se adicionarmos service2 com outra api:

model {
service service1 {
component api
component frontend
}
service service2 {
component api
}
frontend -> api // ⛔️ Error: 'api' not found
}

A referência fica ambígua, pois há dois componentes api no modelo.

Cada elemento cria um novo escopo dentro de {...}, então api é único dentro de service1 e service2, mas não no escopo de model.

Podemos resolver isso movendo o relacionamento para o escopo de 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'
}
}

No LikeC4, além de passar por hoisting em seu escopo, o elemento também “sobe” para os escopos superiores se permanecer único.

Podemos referenciar algo que ainda não foi declarado, mas que passará por hoisting mais adiante. O relacionamento na linha 8 referencia graphql, definido abaixo na linha 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'
}
}

Elementos de nível superior (posicionados diretamente no bloco model) ficam disponíveis globalmente. Você pode usar nomes totalmente qualificados (FQN) para referenciar elementos aninhados.

Exemplo:

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
}

Ou ainda:

model {
service service1 {
component api
component frontend {
-> api
-> service2.api // references to outer scope
}
}
service service2 {
component api
}
}

Algumas partes podem ser omitidas se o FQN permanecer único:

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'
}