Ele foi desenvolvido por Simon Brown, um arquiteto de software e consultor, e é amplamente utilizado por equipes de desenvolvimento de software em todo o mundo.
Para começar a usar o C4 Model, você precisará de uma ferramenta de modelagem de arquitetura, como o Microsoft Visio ou o PlantUML. Recomendo usar o PlantUML e integrar com o VSCode através de sua extensão. Em breve, vou elaborar um tutorial de uso do PlantUML com o VSCode, mas por enquanto, você pode visualizar os diagramas no servidor do PlantUML no link abaixo:
https://www.plantuml.com/plantuml
Isto posto, vamos seguir os seguintes passos:
Defina o escopo do sistema: antes de começar a modelar a arquitetura, é importante definir o escopo do sistema que você está trabalhando. Isso ajudará a determinar os componentes que devem ser incluídos no modelo e a orientar o nível de detalhe que será necessário.
Crie um diagrama de contexto: o primeiro nível do C4 Model é o diagrama de contexto, que deve mostrar os principais componentes externos ao sistema, como clientes, fornecedores e usuários finais, bem como o contexto em que o sistema será utilizado.
Crie um diagrama de contêiner: o segundo nível do C4 Model é o diagrama de contêiner, que deve mostrar os principais componentes do sistema, como servidores, banco de dados e aplicativos, bem como as dependências entre eles.
Adicione seus diagramas de classes à documentação do projeto para aumentar o nível de detalhamento no quarto nível do modelo C4.
O C4 Model é composto por quatro níveis hierárquicos:
Nível de contexto
Neste nível, são mostrados os principais componentes externos ao sistema, como clientes, fornecedores e usuários finais, bem como o contexto em que o sistema será utilizado.
@startuml C4_Context
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Context.puml
LAYOUT_LEFT_RIGHT()
Person(customer, "Cliente", "Cliente de uma concessionaria")
Person(dealer, "Concessionaria", "Concessionaria de veiculos")
Person(supplier, "Fornecedor", "Fornecedor de veiculos")
System_Boundary(system_app, "Aplicação Web") {
System(web_app, "Sistema de Anúncios", "Exibe lista de veículos disponíveis para venda, possibilitando a escolha de um veículo e a compra do mesmo.")
}
Rel(customer, web_app, "Escolhe um veículo", "HTTP")
Rel(web_app, dealer, "Notifica", "E-mail")
Rel_L(dealer, supplier, "Comunica", "E-mail")
Rel(supplier, dealer, "Confirma venda", "E-mail")
Rel(web_app, customer, "Notifica", "E-mail")
@enduml
Comece importando a biblioteca de Context do C4 Model:
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Context.puml
' Indica a direção dos blocos no diagrama:
LAYOUT_LEFT_RIGHT()
' Cria as pessoas (atores) do diagrama:
Person(customer, "Cliente", "Cliente de uma concessionaria")
Person(dealer, "Concessionaria", "Concessionaria de veiculos")
Person(supplier, "Fornecedor", "Fornecedor de veiculos")
' Defina os limites do sistema:
System_Boundary(system_app, "Aplicação Web") {
System(web_app, "Sistema de Anúncios", "Exibe lista de veículos disponíveis para venda, possibilitando a escolha de um veículo e a compra do mesmo.")
}
' Defina os relacionamentos e ações de cada elemento:
Rel(customer, web_app, "Escolhe um veículo", "HTTP")
Rel(web_app, dealer, "Notifica", "E-mail")
Rel_L(dealer, supplier, "Comunica", "E-mail")
Rel(supplier, dealer, "Confirma venda", "E-mail")
Rel(web_app, customer, "Notifica", "E-mail")
' Rel: Define um relacionamento padrao
' Rel_L: Força um elemento fique à ESQUERDA do elemento relacionado
' Rel_R: Força um elemento fique à DIREITA do elemento relacionado
Nível de contêiner
Neste nível, são mostrados os principais componentes do sistema, como servidores, banco de dados e aplicativos, bem como as dependências entre eles.
@startuml C4_Container
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml
LAYOUT_LEFT_RIGHT()
Person(customer, "Cliente", "Cliente de uma concessionaria")
Person(dealer, "Concessionaria", "Concessionaria de veiculos")
Person(supplier, "Fornecedor", "Fornecedor de veiculos")
System_Boundary(advertising, "Sistema de Anúncios") {
Container(next_app, "Sistema de Anúncios", "NextJS", "Permite ao cliente visualizar e enviar proposta de compra dos veículos")
}
Rel(dealer, supplier, "Compra veiculo", "HTTP")
Rel(customer, next_app, "Pesquisa veiculo", "HTTP")
Rel(dealer, next_app, "Pesquisa veiculo", "HTTP")
Rel(supplier, next_app, "Pesquisa veiculo", "HTTP")
Rel(next_app, customer, "Mostra veiculo", "HTTP")
Rel(next_app, dealer, "Mostra veiculo", "HTTP")
Rel(next_app, supplier, "Mostra veiculo", "HTTP")
@enduml
Nível de componente
Neste nível, são mostrados os componentes mais detalhados do sistema, incluindo classes, módulos e pacotes de software.
@startuml C4_Component
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Component.puml
' Diagrama c4 model de componentes
' para mais informações, veja https://c4model.com/
Person(customer, "Cliente", "Cliente de uma concessionaria")
Person(dealer, "Concessionaria", "Concessionaria de veiculos")
Person(supplier, "Fornecedor", "Fornecedor de veiculos")
System_Boundary(car_dealership, "Concessionaria de Veiculos") {
Container(web_app, "Aplicacao Web", "Java, Spring MVC", "Exibe a lista de veiculos")
Container(rest_api, "API REST", "Java, Spring MVC", "Exibe a lista de veiculos")
Container(database, "Banco de Dados", "PostgreSQL", "Armazena os dados dos veiculos")
}
Rel(customer, web_app, "Visualiza a lista de veiculos")
Rel(customer, rest_api, "Visualiza a lista de veiculos")
Rel(dealer, web_app, "Visualiza a lista de veiculos")
Rel(dealer, rest_api, "Visualiza a lista de veiculos")
Rel(supplier, database, "Armazena os dados dos veiculos")
@enduml
Nível de classe
Neste nível, são mostrados os detalhes da implementação do código, como as interfaces e as classes concretas. Os detalhes mais profundos podem ser adicionados à medida que o projeto for se desenvolvendo. Num primeiro momento, apenas o nome das classes e seus relacionamentos já é suficiente. Pra esse exemplo, vou adicionar um diagrama de classes com as propriedades e métodos para passar uma idéia mais completa.
@startuml Class_Diagram
title Diagrama de Classes
' create a package for the classes
package "Classes" {
class Customer
class Dealer
class Supplier
class Vehicle
class Car
class Truck
class Motorcycle
}
class Customer {
-String name
-String address
-String phone
-String email
+String getName()
+String getAddress()
+String getPhone()
+String getEmail()
+void setName(String name)
+void setAddress(String address)
+void setPhone(String phone)
+void setEmail(String email)
}
class Dealer {
-String name
-String address
-String phone
-String email
+String getName()
+String getAddress()
+String getPhone()
+String getEmail()
+void setName(String name)
+void setAddress(String address)
+void setPhone(String phone)
+void setEmail(String email)
}
class Supplier {
-String name
-String address
-String phone
-String email
+String getName()
+String getAddress()
+String getPhone()
+String getEmail()
+void setName(String name)
+void setAddress(String address)
+void setPhone(String phone)
+void setEmail(String email)
}
class Vehicle {
-String make
-String model
-String year
-String color
-String vin
-String licensePlate
-String mileage
-String price
+String getMake()
+String getModel()
+String getYear()
+String getColor()
+String getVin()
+String getLicensePlate()
+String getMileage()
+String getPrice()
+void setMake(String make)
+void setModel(String model)
+void setYear(String year)
+void setColor(String color)
+void setVin(String vin)
+void setLicensePlate(String licensePlate)
+void setMileage(String mileage)
+void setPrice(String price)
}
class Car extends Vehicle {
-String engine
-String transmission
-String fuelType
-String driveType
-String bodyStyle
-String interiorColor
-String exteriorColor
-String mileage
-String price
+String getEngine()
+String getTransmission()
+String getFuelType()
+String getDriveType()
+String getBodyStyle()
+String getInteriorColor()
+String getExteriorColor()
+String getMileage()
+String getPrice()
+void setEngine(String engine)
+void setTransmission(String transmission)
+void setFuelType(String fuelType)
+void setDriveType(String driveType)
+void setBodyStyle(String bodyStyle)
+void setInteriorColor(String interiorColor)
+void setExteriorColor(String exteriorColor)
+void setMileage(String mileage)
+void setPrice(String price)
}
class Truck extends Vehicle {
-String engine
-String transmission
-String fuelType
-String driveType
-String bodyStyle
-String interiorColor
-String exteriorColor
-String mileage
-String price
+String getEngine()
+String getTransmission()
+String getFuelType()
+String getDriveType()
+String getBodyStyle()
+String getInteriorColor()
+String getExteriorColor()
+String getMileage()
+String getPrice()
+void setEngine(String engine)
+void setTransmission(String transmission)
+void setFuelType(String fuelType)
+void setDriveType(String driveType)
+void setBodyStyle(String bodyStyle)
+void setInteriorColor(String interiorColor)
+void setExteriorColor(String exteriorColor)
+void setMileage(String mileage)
+void setPrice(String price)
}
class Motorcycle extends Vehicle {
-String engine
-String transmission
-String fuelType
-String driveType
-String bodyStyle
-String interiorColor
-String exteriorColor
-String mileage
-String price
+String getEngine()
+String getTransmission()
+String getFuelType()
+String getDriveType()
+String getBodyStyle()
+String getInteriorColor()
+String getExteriorColor()
+String getMileage()
+String getPrice()
+void setEngine(String engine)
+void setTransmission(String transmission)
+void setFuelType(String fuelType)
+void setDriveType(String driveType)
+void setBodyStyle(String bodyStyle)
+void setInteriorColor(String interiorColor)
+void setExteriorColor(String exteriorColor)
+void setMileage(String mileage)
+void setPrice(String price)
}
Customer "1" -- "1..*" Vehicle : compra
Dealer "1" -- "1..*" Vehicle : gerencia
Dealer "1" -- "1..*" Supplier : comunica
Supplier "1" -- "1..*" Vehicle : fornece
Vehicle "1" -- "1..*" Car
Vehicle "1" -- "1..*" Truck
Vehicle "1" -- "1..*" Motorcycle
@enduml
Bom, pra começar já temos um bom material!
Documentar a arquitetura de um software é importante por diversas razões. Algumas dessas razões incluem:
Comunicação: A documentação da arquitetura permite que os membros do time compreendam como o software foi projetado e como os componentes se relacionam uns com os outros. Isso facilita a comunicação e a colaboração entre os membros do time, pois todos estão trabalhando a partir de uma base comum de conhecimento.
Manutenção: A documentação da arquitetura também é útil para a manutenção do software, pois permite que novos desenvolvedores entendam rapidamente como o software foi projetado e como ele funciona. Isso pode tornar mais fácil identificar problemas e implementar soluções.
Evolução: A documentação da arquitetura também é importante para o planejamento de futuras alterações e evoluções no software. Isso permite que o time tenha uma visão clara de como o software está atualmente e como ele pode ser modificado de maneira a manter a integridade e a qualidade do software.
Utilizar o C4 Model para documentar a arquitetura de um software pode ajudar a garantir que a documentação seja completa e precisa, e pode ser uma ferramenta útil para comunicar a arquitetura do software aos membros do time e a outros stakeholders.
Por enquanto, é isso! Fique ligado que em breve teremos mais artigos sobre arquitetura de software, documentação e muito mais.
Vlw :=)