• Зачем нужны интерфейсы в go?

    vabka
    @vabka
    Токсичный шарпист
    Интерфейсы нужны для полиморфизма.
    Конкретно в твоём случае да - разницы нет.
    Но чисто в теории ты бы мог сделать вот так:
    type Numbers struct {
      Num1 int
      Num2 int
    }
    
    type ThreeNumbers struct {
      Num1 int
      Num2 int
      Num3 int
    }
    
    func (n Numbers) Sum() int {
      return n.Num1 + n.Num2
    }
    
    func (n ThreeNumbers) Sum() int {
      return n.Num1 + n.Num2 + n.Num3
    }
    
    func SumAll(numbers NumberInterface) int {
      return numbers.Sum()
    }

    Функция SumAll будет работать с любыми типами, которые реализуют интерфейс NumberInterface, причём даже если они сами об этом не в курсе, благодаря утиной типизации.
    Ответ написан
    3 комментария
  • Как в коде в стиле "clean architecture" использовать транзакции?

    @deliro
    Нужно понимать, что orderRepository и paymentRepository — это абстракции, а фактически данные могут храниться как в одной базе, так и в совершенно разных. Например, orderRepository находится на сервере S1 в базе Redis, а paymentRepository — на серверах S2, S3, S4 в базе PostgreSQL. Поэтому, классические транзакции здесь неприменимы. Этим можно пренебречь в большинстве случаев и не переусложнять систему, а можно пойти "правильным" путём и использовать распределённые транзакции, например, саги https://microservices.io/patterns/data/saga.html
    Ответ написан
    1 комментарий
  • Как в коде в стиле "clean architecture" использовать транзакции?

    @Akela_wolf
    Extreme Programmer
    Тут все довольно просто. У нас есть слой бизнес-логики, который имеет 3 интерфейса:
    TransactionManager - собственно менеджер транзакций
    OrderRepository - репозиторий заказов
    PaymentRepository - репозиторий платежей

    И, допустим, нам нужно транзакционно сделать следующий сценарий: "при получении платежа записать его в БД и изменить статус заказа на PAID" (пишу пример на Kotlin, надеюсь понятно)
    transactionManager.inTransaction {
      order.status = PAID
      paymentRepository.save(payment)
      orderRepository.save(order)
    }

    Собственно дальше - это уже вопрос реализации TransactionManager. Если мы имеем дело с простым случаем, таким как хранение данных в SQL Database, то его реализация должна быть понятна. Если более сложный случай - то распределенные транзакции, либо пустая реализация (транзакционность не поддерживается). Разумеется, при инжекции зависимостей в модуль бизнес-логики реализация менеджера транзакций должна соответствовать реализации репозиториев (мало толку будет если менеджер транзакций реализует транзакционность в БД, а репозитории - хранение в файлах). Но это уже слегка другой разговор, тут на помощь приходят фабрики и подобные шаблоны.
    Ответ написан
    6 комментариев
  • Как узнать когда горутины закончили запись, чтобы закрыть канал?

    @falconandy
    Примерно так: https://goplay.tools/snippet/TciyGAE8dyn
    Ответ написан
    Комментировать
  • Mutex RWMutex отличия?

    RWMutex нужен, когда у нас есть объект, который нельзя параллельно писать, но можно параллельно читать. Например, стандартный тип map.
    Перед записью в защищаемый мьютексом объект делается .Lock(), а вызовы .Lock() и .RLock() в других горутинах будут ждать, пока вы не отпустите мьютекс через .Unlock().
    Перед чтением защищаемого объекта делается .RLock() и только вызовы .Lock() в других горутинах блокируются, вызовы .RLock() спокойно проходят. Когда отпускаете мьютекс через .RUnlock(), ждущие вызовы .Lock() по-очереди могут забирать мьютекс на себя.
    Таких образом обеспечивается параллельное чтение объекта несколькими горутинами, что улучшает производительность.
    Ответ написан
    4 комментария
  • В чём разница между json.Unmarshal и json.NewDecoder?

    @ghostiam
    На Go писатель, серверов пинатель.
    json.Unmarshal использует массив байт, а json.NewDecoder это потоковый парсер, которому не нужно сразу хранить в памяти все данные для парсинга.

    Для парсинга json из файла или из запроса, я бы советовал json.NewDecoder, так как он будет меньше потреблять памяти (не нужно заранее считывать в память массив байт).
    Ответ написан
    Комментировать