Задать вопрос
@nano_e_t_4

Как в goшном SOA сервисе работать с базой данных?

Всем привет
Пишу сервис, по SOA. В немуже накопилось достаточно большое количество методов - добавление\изменение\удаления сущностей, вроде пользователей, ивентов, адресов и тд. В итоге все эти методы обращаются к бд, к своим табличкам, запросы там тоже разные. Где то нада обновить 1 поле, где то нада обновить всю записись и тд.
Сейчас дошло до того, что у меня отдельный интерфейс с базой, прокинут в каждый сервис, и для каждого сервиса с есть метод, вынесенный в интерфейс model. Но это стало уже не очень удобным, потому что запросов много, и все их нада выносить в интерфейс.
Если у кого есть хорошие советы, или гит репозитории где можно посмотреть различные практики, как в гошке, в больших сервисах работать с бд, как разбивать большой интерфейc, покидайте пожалуйста
  • Вопрос задан
  • 377 просмотров
Подписаться 1 Простой Комментировать
Пригласить эксперта
Ответы на вопрос 2
Не знаю, какая у вас архитектура, но когда какая-то библиотека обрастает огромным количеством методов, то Go - это один из редких языков программирования, который, благодаря своей утиной типизации позволяет использовать шаблон проектирования "consumer interfaces", т.е. объявлять интерфейсы в месте, где они используются и включать в эти интерфейсы только те методы из огромной структуры базы данных, которые именно тут, на месте, и используются. Таким образом ваши интерфейсы будут минимальными, понятными, и искать их не придётся. Ну, и в добавок, старый добрый Dependency Injection решит массу наших проблем

База данных:
package db

import "fmt"

// Стуктура базы данных. Здесь нам даже и не нужно объявлять никаких интерфейсов
type Service struct {
	// ...
}

func NewDbService() (*Service, error) {
	return &Service{}, nil
}

func (d *Service) CreateUser(username string, email string) {
	fmt.Println(fmt.Sprintf("user %s with email %s is created", username, email))
}

func (d *Service) CreateProduct(name string) {
	fmt.Println(fmt.Sprintf("product  %s is created", name))
}


Пользователь:
package user

// Тот самый интерфейс, который нам позволяет выбрать из структуры базы данных
// только нужные нам здесь методы
type dbUser interface {
	CreateUser(username string, email string)
}

type Service struct {
	db dbUser
	// ...
}

func NewService(db dbUser) (*Service, error) {
	return &Service{db}, nil
}

func (c *Service) New(username string, email string) {
	c.db.CreateUser(username, email)
}


Товар:
package product

// Тот самый интерфейс, который нам позволяет выбрать из структуры базы данных
// только нужные нам здесь методы
type dbProduct interface {
	CreateProduct(name string)
}

type Service struct {
	db dbProduct
	// ...
}

func NewService(db dbProduct) (*Service, error) {
	return &Service{db}, nil
}

func (p *Service) New(name string) {
	p.db.CreateProduct(name)
}


main.go
package main

import (
	"test2/db"
	"test2/product"
	"test2/user"
)

func main() {
        // Инициализируем базу данных
	dbService, _ := db.NewDbService()
        // Структура базы данных реализует интерфейс dbProduct, инжектим её
	productService, _ := product.NewService(dbService)
        // Структура базы данных реализует интерфейс dbUser, инжектим её
	userService, _ := user.NewService(dbService)

        // Пользуемся на здоровье...
	userService.New("user1", "uswr1@example.com")
	productService.New("product1")
}
Ответ написан
Комментировать
@12rbah
Но это стало уже не очень удобным, потому что запросов много, и все их нада выносить в интерфейс.
А точно это нужно? Просто если это интерфейс на 20+ методов, то в этом нет смысла, интерфейс нужен для кода, который может быть обобщенным, просто так выносить метод в интерфейс не имеет смысла.
Сейчас дошло до того, что у меня отдельный интерфейс с базой, прокинут в каждый сервис, и для каждого сервиса с есть метод, вынесенный в интерфейс model
В общем не используйте интерфейсы ради интерфейсов и не получите лишних проблем.
Есть код среднего по размерам проекта, можете оценить как в нём писали код. еще код
спойлер
они не пихают всё в интерфейс

В редких случаях такой подход имеет смысл, например когда пишут кроссплатформенную либу для GUI или у вас на беке будет гарантированно несколько баз с одинаковыми методами, если у вас ситуация не требует этого, то не пихайте всё в один интерфейс. Интерфейс создан для удобства а не для того чтобы мучаться.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы