Skip to content

Instantly share code, notes, and snippets.

@andrsj
Created March 28, 2025 07:45
Show Gist options
  • Save andrsj/836e91afdc622771dc829a2dbb96092a to your computer and use it in GitHub Desktop.
Save andrsj/836e91afdc622771dc829a2dbb96092a to your computer and use it in GitHub Desktop.

Структура проекта

myapp/
│── domain/                # Чистый домен (сущности + бизнес-логика)
│   ├── user.go
│   ├── user_repository.go
│   ├── user_service.go
│── adapter/               # Адаптеры для инфраструктуры
│   ├── user_repository.go
│   ├── user_event_publisher.go
│── infrastructure/        # Реализации
│   ├── postgres.go
│   ├── kafka.go
│── main.go                # Главная точка входа
package adapter
import "myapp/domain"
type MessageBrokerClient interface {
Publish(topic string, message []byte) error
}
type UserEventPublisherAdapter struct {
client MessageBrokerClient
}
func NewUserEventPublisherAdapter(client MessageBrokerClient) *UserEventPublisherAdapter {
return &UserEventPublisherAdapter{client: client}
}
func (p *UserEventPublisherAdapter) PublishUserCreated(user *domain.User) error {
msg := []byte("User created: " + user.Name)
return p.client.Publish("user.events", msg)
}
package adapter
import (
"myapp/domain"
)
type DatabaseClient interface {
QueryUserByID(id int) (*domain.User, error)
InsertUser(user *domain.User) error
}
type UserRepositoryAdapter struct {
client DatabaseClient
}
func NewUserRepositoryAdapter(client DatabaseClient) *UserRepositoryAdapter {
return &UserRepositoryAdapter{client: client}
}
func (r *UserRepositoryAdapter) GetByID(id int) (*domain.User, error) {
return r.client.QueryUserByID(id)
}
func (r *UserRepositoryAdapter) Save(user *domain.User) error {
return r.client.InsertUser(user)
}
package domain
type User struct {
ID int
Name string
}
package domain
type UserRepository interface {
GetByID(id int) (*User, error)
Save(user *User) error
}
package domain
type UserService struct {
repo UserRepository
publisher EventPublisher
}
type EventPublisher interface {
PublishUserCreated(user *User) error
}
func NewUserService(repo UserRepository, publisher EventPublisher) *UserService {
return &UserService{repo: repo, publisher: publisher}
}
func (s *UserService) RegisterUser(name string) (*User, error) {
user := &User{Name: name}
err := s.repo.Save(user)
if err != nil {
return nil, err
}
err = s.publisher.PublishUserCreated(user)
if err != nil {
return nil, err
}
return user, nil
}
package infrastructure
import (
".../kafka"
)
type KafkaClient struct {
producer *kafka.Producer
}
func NewKafkaClient(brokers string) (*KafkaClient, error) {
producer, err := kafka.NewProducer(&kafka.ConfigMap{"bootstrap.servers": brokers})
if err != nil {
return nil, err
}
return &KafkaClient{producer: producer}, nil
}
func (k *KafkaClient) Publish(topic string, message []byte) error {
return k.producer.Produce(&kafka.Message{
TopicPartition: kafka.TopicPartition{Topic: &topic, Partition: kafka.PartitionAny},
Value: message,
}, nil)
}
package infrastructure
import (
"database/sql"
"myapp/domain"
_ "github.com/lib/pq"
)
type PostgresClient struct {
db *sql.DB
}
func NewPostgresClient(connString string) (*PostgresClient, error) {
db, err := sql.Open("postgres", connString)
if err != nil {
return nil, err
}
return &PostgresClient{db: db}, nil
}
func (p *PostgresClient) QueryUserByID(id int) (*domain.User, error) {
var user domain.User
err := p.db.QueryRow("SELECT id, name FROM users WHERE id = $1", id).
Scan(&user.ID, &user.Name)
if err != nil {
return nil, err
}
return &user, nil
}
func (p *PostgresClient) InsertUser(user *domain.User) error {
_, err := p.db.Exec("INSERT INTO users (id, name) VALUES ($1, $2)", user.ID, user.Name)
return err
}
package main
import (
"log"
"myapp/adapter"
"myapp/domain"
"myapp/infrastructure"
)
func main() {
dbClient, err := infrastructure.NewPostgresClient("postgres://user:password@localhost:5432/mydb?sslmode=disable")
if err != nil {
log.Fatal(err)
}
kafkaClient, err := infrastructure.NewKafkaClient("localhost:9092")
if err != nil {
log.Fatal(err)
}
userRepo := adapter.NewUserRepositoryAdapter(dbClient)
eventPublisher := adapter.NewUserEventPublisherAdapter(kafkaClient)
userService := domain.NewUserService(userRepo, eventPublisher)
user, err := userService.RegisterUser("Andrii")
if err != nil {
log.Fatal(err)
}
log.Println("Created user:", user)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment