Задать вопрос
  • Как должна выглядит правильная структура "внедрение зависимостей"?

    doflare,
    Не использовать gorm и json теги у моделей, эти теги нужны тольео для структур транспортного уровня (DTO), а не моделей.

    Если вам нужно получать пользователя по id, например, то у репозитория будет метод
    func (r *Repository) GetUserByID(ctx context.Context, id int64) (*User, error)


    То есть, не модель будет возвращать сама себя, а вы из репозитория будете получает нужные модели.
    Так же с методами по update, create, они все в репозитории, а не в модели.

    Модель это чистая структура, которая участвует только в бизнес-логике, нигде более. У вас будут транспортные структуры, с которыми вы будете обращаться на слое репозитория, но когда надо возвращать данные выше, вы будете их конвертировать в чистые модели.
    Написано
  • Как должна выглядит правильная структура "внедрение зависимостей"?

    doflare,
    Лишняя сущность container, вместо этого лучше в main (или другой функции инициализации) формировать все объекты, передавая им напрямую их зависимости. То есть, вместо передачи контейнера в handlers.NewAuthHandler и взятия всего что нужно внутри хендлера, лучше передавать в хендлер ограниченный список того, что хендлеру реально нужно для работы.
    У вас сейчас внутри NewAuthHandler, например, контейнер просто складывается в поле структуры и не используется нигде. В конструкторе при этом создается services.NewAuthServices(container).
    По-хорошему в хендлер нужно передавать уже созданный и готовый сервис авторизации, а не создавать его внутри.
    Внутри AuthService у вас в куче мест дергается GetRepository() и GetLogger(), вместо этого нужно в NewAuthServices принимать готовые логгер и репозиторий, складывать их в поля структуры authServices.
    Структура authServices не должна быть приватной, а конструктор NewAuthServices не должен возвращать интерфейс, а должен возвращать указатель на публичную структуру AuthServices (почитать тут).
    Каждый хендлер должен быть в своем пакете для более удобной изоляции.
    AuthService должен принимать интерфейсы, которые объявлены внутри самого AuthService. Например, тот же репозиторий. Причем, все методы репозитория должны работать с моделями, а не с sql. У вас сейчас работа с sql внутри пакета моделей, не надо так. Работа с sql только внутри пакетов репозитория и ничего из этого не должно импортироваться в другие пакеты. Если надо проверить, что пользователь существует, то делаете для этого метод в репозитории и прописываете его в интерфейсе в том сервисе, которому этот метод нужен.

    Тогда у вас будет хороший dependency injection. Глазу сразу будет видно, что использует сервис или хендлер, не нужно будет гадать, что же он берет из контейнера. Даже все используемые методы репозитория видны будут. Для тестов нужно будет меньше усилий, чтобы сделать моки, не надо мокать весь container, а только пару используемых интерфейсов с маленьким числом методов.
    Написано
  • Как должна выглядит правильная структура "внедрение зависимостей"?

    Роман, кидайте код. Для диплома на самом деле сойдет и без запары с чистой архитектурой )))
    Написано
  • Почему не кэшируются страницы на клиенте?

    Михаил Ливач, curl точно всегда будет у вас брать ресурс, потому что у него нет кэша. Покажите как в браузере выглядит запрос и как настроены девтулзы
    Написано
  • Почему не кэшируются страницы на клиенте?

    Вы пытаетесь заставить браузер кэшить html, который вводите в url. Так работать не будет. Если бы это был ресурс, подключаемый к странице, например css или картинка, оно бы работало.
    Написано
  • Какой софт позволяет логично разобрать модель?

    Вороной же разорвет деталь на кусочки, а автору надо чтобы она по-деталям четким разлетелась, как делают на образовательных плакатах различных.
    Написано
  • Golang путь как использовать паттерн Фабрику без наследования?

    AstRonin, так не получится, я потому и предложил сразу вынести действия с пользователем в отдельные функции, которые принимают интерфейс. Потому что вложенный композицией тип не может знать о типах, в которые он вложен.

    Выйдет только так: https://go.dev/play/p/GoyGNd52kxN
    Написано
  • Golang путь как использовать паттерн Фабрику без наследования?

    AstRonin, код довольно абстрактный, не ясно, что за действия нужно делать с пользователями и зачем тут приседания с разделением на типы.

    В целом в Го не получится полностью сделать все по DRY, язык очень простой и нет достаточного количества абстракций. Поэтому с копипастой придется смириться.

    Использовать паттерны, которые хорошо работали в Джаве не выйдет, они очень плохо ложатся на Го. Так что не используйте фабрики, синглтоны и прочее.

    Ваш код выше, например, нарушает одно из гошных правил. Не принято возвращать интерфейс из функции, всегда надо возвращать конкретную структуру. Интерфейсы мы только принимаем как аргументы.

    Нужно переписать фабрику, использовать вместо нее набор конструкторов, один конструктор под каждый тип пользователя. Заодно получите гарантию того, что при неверном типе не свалитесь на рантайме с паникой.

    Если очень хочется иметь какую-то базовую реализацию и переопределять часть ее методов, можно использовать композицию, которая в Го есть. Я накидал пример кода, тоже абстрактный. https://go.dev/play/p/jqbcPx30SrU

    spoiler
    type BaseUser struct {
    	id   int64
    	name string
    }
    
    type WorkingUser struct {
    	BaseUser
    	WorkingHours string
    }
    
    type SlackingUser struct {
    	BaseUser
    	TimeOfSlacking time.Duration
    }
    
    func newBaseUser(id int64, name string) BaseUser {
    	// Тут какая-то общая логика для создания любого пользователя
    	return BaseUser{
    		id:   id,
    		name: name,
    	}
    }
    
    func NewWorkingUser(id int64, name string, workingHours string) *WorkingUser {
    	// Тут добавочная логика создания для рабочего
    	return &WorkingUser{
    		BaseUser:     newBaseUser(id, name),
    		WorkingHours: workingHours,
    	}
    }
    
    func NewSlackingUser(id int64, name string, timeOfSlacking time.Duration) *SlackingUser {
    	// Тут добавочная логика для создания лентяя
    	return &SlackingUser{
    		BaseUser:       newBaseUser(id, name),
    		TimeOfSlacking: timeOfSlacking,
    	}
    }
    
    func (b BaseUser) GetName() string {
    	// Какая-то работа с данными, которая одинакова для всех
    	return b.name
    }
    
    func (b BaseUser) GetDescr() string {
    	// Какая-то работа с данными, для которой нужна базовая реализация,
    	// но для некоторых пользователей она может быть другой
    	return "a base user with the name " + b.name
    }
    
    func (u *WorkingUser) GetDescr() string {
    	// Если хотим переопределить базовую реализацию для этого типа пользователя
    	return fmt.Sprintf("working user with hours %s", u.WorkingHours)
    }
    
    type Doer interface {
    	GetName() string
    	GetDescr() string
    }
    
    func Do(user Doer) {
    	// Какие-то действия с пользователем, которые используют и ту и другую логику
    	fmt.Println(user.GetName(), "can be described as", user.GetDescr())
    }
    
    func main() {
    	user1 := NewWorkingUser(1, "Ivan", "from 5 to 19")
    	user2 := NewSlackingUser(2, "Peter", time.Hour*2)
    
    	Do(user1)
    	Do(user2)
    }


    Но предупреждаю, что не стоит слишком глубоко идти в эту сторону, нужно стараться писать код проще, чем в других языках.
    Написано
  • Golang путь как использовать паттерн Фабрику без наследования?

    Но так абстрактно рассуждать сложно. Было бы проще иметь более четкое представление, что хотите сделать.
    Написано
  • Golang путь как использовать паттерн Фабрику без наследования?

    AstRonin, делаете if в методе, который работает с данными (который не в методе пользователя, а в пакете действий с пользователем)
    Написано
  • Golang путь как использовать паттерн Фабрику без наследования?

    AstRonin,
    метод Do придется писать в каждом типе пользователя


    Нет, метод Do как раз будет не в пользователе, а в пакете, который будет делать с пользователями какие-то действия. Вы там его один раз напишете и все. У пользователя должны быть только методы для работы с данными пользователя, грубо говоря, нужные геттеры и сеттеры.

    Таким образом, исчезнет проблема переопределения и наследования.
    Написано
  • Golang путь как использовать паттерн Фабрику без наследования?

    AstRonin,
    как мне переопределить какой-то глубоко закопанный метод


    Не нужно переопределять методы
    Написано
  • Как оптимизировать забор в blender 3d?

    Dark_Dexter, тогда прогнать оптимизатор, который во всех плоскостях уберет лишние ребра. На приведенной картинке, например, очень много лишних вертикалей поперек плоских поверхностей. Еще надо оставить только один сегмент забора, потому что они явно повторяются.

    Лучше делать это инструментами того движка, под который планируется игра, потому что эти инструменты оптимизируют то, что важно для конкретного движка.

    Плюс, обычно создают несколько LOD-ов для ассета. Например, в случае забора последний LOD будет скорее всего одной плоскостью с текстуркой низкого разрешения.
    Написано
  • Как оптимизировать забор в blender 3d?

    Подо что идет оптимизация? Забор будет потом использоваться в игре или для рендера в самом Блендере?
    Написано
  • Почему не получается подключить внешние пакеты в golang?

    Maxim_Kossov, сам Голендом не пользуюсь, но у знакомых с этим нет проблем, все сидят без прокси.
    Написано
  • Почему не получается подключить внешние пакеты в golang?

    Maxim_Kossov, выглядит так, что у вас в настройках IDE указан прокси, но он сейчас недоступен (или в настройках системы, но IDE их подхватывает). Может включали прокси, когда обходили блокировки от JetBrains?
    Написано
  • Почему не получается подключить внешние пакеты в golang?

    Без IDE пакет получается поставить и собрать программу?

    Покажите содержимое вашего go.mod
    Написано
  • Почему не работает консьюмер?

    Сергей Ерин, в горутине вы его будете запускать или нет -- это не ключевое тут. Главное, как будете работать с тем каналом, который возвращается.

    Надо обрабатывать данные, которые по этому каналу к вам приходят. Например через range
    Написано