Neste post, vamos ver um exemplo mais detalhado e prático de uma implementação prática da arquitetura limpa em Go, utilizando uma estrutura de pastas e arquivos definida, juntamente com exemplos de código.
Estrutura de Pastas e Arquivos
A estrutura de pastas em um projeto Go que segue a arquitetura limpa pode ser organizada da seguinte maneira:
meu_projeto/ |-- cmd/ | |-- main.go |-- internal/ | |-- entities/ | | |-- user.go | |-- usecases/ | | |-- user_manager.go | |-- interfaces/ | | |-- repositories/ | | | |-- user_repository.go | |-- infrastructure/ | |-- database/ | |-- user_db.go |-- pkg/ |-- api/ |-- handlers/ |-- user_handler.go
cmd/main.go
: o ponto de entrada do aplicativo.internal/entities
: contém as entidades do domínio, comoUser
.internal/usecases
: lógica de negócios (casos de uso), comoUserManager
.internal/interfaces/repositories
: interfaces para os repositórios, comoUserRepository
.internal/infrastructure/database
: implementação concreta dos repositórios, comoUserDB
.pkg/api/handlers
: manipuladores para a camada de apresentação ou API.
Exemplos de Código
Vamos ver como cada parte dessa estrutura poderia ser implementada
1 – Entity (internal/entities/user.go)
package entities type User struct { ID int Name string Email string }
2 – Usecase (internal/usecases/user_manager.go)
package usecases import "meu_projeto/internal/entities" type UserManager struct { repo UserRepository } func NewUserManager(repo UserRepository) *UserManager { return &UserManager{repo: repo} } func (m *UserManager) CreateUser(user *entities.User) error { // lógica para criar um usuário return m.repo.Create(user) }
3 – Interface do Repository (internal/interfaces/repositories/user_repository.go)
package repositories import "meu_projeto/internal/entities" type UserRepository interface { Create(user *entities.User) error }
Implementação do Repository (internal/infrastructure/database/user_db.go)
package database import "meu_projeto/internal/entities" type UserDB struct { // dependências do banco de dados } func (db *UserDB) Create(user *entities.User) error { // implementação para criar um usuário no banco de dados }
Handler (pkg/api/handlers/user_handler.go)
package handlers import ( "net/http" "meu_projeto/internal/usecases" ) type UserHandler struct { userManager *usecases.UserManager } func (h *UserHandler) CreateUser(w http.ResponseWriter, r *http.Request) { // lógica para manipular a requisição e criar um usuário }
Conclusão
Implementar uma estrutura baseada em arquitetura limpa requer uma cuidadosa organização de pastas e arquivos, juntamente com a aplicação de princípios de design sólidos. Essa estrutura não apenas torna o código mais legível e manutenível, mas também facilita a testabilidade e a extensibilidade.
No próximo post abordaremos a refatoração do seu código para um padrão de Arquitetura Limpa.
Let’s code!
1 comment