We use cookies and other tracking technologies to improve your browsing experience on our site, analyze site traffic, and understand where our audience is coming from. To find out more, please read our privacy policy.

By choosing 'I Accept', you consent to our use of cookies and other tracking technologies.

We use cookies and other tracking technologies to improve your browsing experience on our site, analyze site traffic, and understand where our audience is coming from. To find out more, please read our privacy policy.

By choosing 'I Accept', you consent to our use of cookies and other tracking technologies. Less

We use cookies and other tracking technologies... More

Login or register
to apply for this job!

Login or register
to save this job!

Login or register to start contributing with an article!

Login or register
to see more jobs from this company!

Login or register
to boost this post!

Show some love to the author of this blog by giving their post some rocket fuel πŸš€.

Login or register to search for your ideal job!

Login or register to start working on this issue!

Engineers who find a new job through Golang Works average a 15% increase in salary πŸš€

Blog hero image

Go (golang) service options (dependencies)

Roman Romadin 18 February, 2020 | 2 min read

About me: I am mostly backend developer and looking for new opportunities in Europe/US as Software Engineer / Backend Developer. My Linkedin: https://www.linkedin.com/in/roman-romadin/

How to dynamically inject dependencies into "Service" in Go?

This solution (approach) is based on:

  1. variadic functions (https://yourbasic.org/golang/variadic-function/) and
  2. self-referential functions (https://www.geeksforgeeks.org/self-referential-structures/).

At first glance, this seems a bit confusing, but it's actually a simple solution. This approach can be used to initialize the application as a whole and to load configuration and other services.

Using variadic function:

type Option func(*accs)

func (f *accs) AddOptions(opts ...Option) {
    for _, opt := range opts {
        opt(f)
    }
}

Using self-referential functions:

func BindSubscriptions(v subscriptions.Client) Option {
    return func(f *accs) {
        f.srvSubscriptions = v
    }
}

First of all you should create main service. In our snippet it is accounts:

accs := accounts.New()

Init the second service (it will be property for main service):

srvSubscriptions := subscriptions.New(111)

After that you should bind second service and set properties for first service:

sbs := accounts.BindSubscriptions(srvSubscriptions)
accs.AddOptions(sbs)

And finally we process business logic (process):

accs.Process(222)

As well we can change any properties in second service (accounts or billing in our snippet): set value = 222

And in addition by using variadic functions we can add one or more properties into first service:

accs.AddOptions(sbs, bl)

or by this way:

accs.AddOptions(sbs)
accs.AddOptions(bl)

Full code:

.
β”œβ”€β”€ cmd
β”‚Β Β  └── main.go
β”œβ”€β”€ pkg
β”‚Β Β  β”œβ”€β”€ accounts
β”‚Β Β  β”‚Β Β  └── service.go
β”‚Β Β  β”œβ”€β”€ billing
β”‚Β Β  β”‚Β Β  └── service.go
β”‚Β Β  └── subscriptions
β”‚Β Β      └── service.go
└── README.md
package main

import (
    "../pkg/billing"
    "../pkg/subscriptions"
    "../pkg/accounts"
    "fmt"
)

func main() {
    fmt.Println("Variant_1:")
    variant1()

    fmt.Println("Variant_2:")
    variant2()

    fmt.Println("Variant_3:")
    variant3()
}


func variant1() {
    accs := accounts.New()

    srvAccounts := subscriptions.New(111)

    sbs := accounts.BindSubscriptions(srvAccounts)

    accs.AddOptions(sbs)

    accs.Process(222)
}

func variant2() {
    accs := accounts.New()

    srvAccounts := subscriptions.New(333)
    srvBilling := billing.New()

    sbs := accounts.BindSubscriptions(srvAccounts)
    bl := accounts.BindBilling(srvBilling)

    accs.AddOptions(sbs, bl)

    accs.Process(444)
}

func variant3() {
    accs := accounts.New()

    srvAccounts := subscriptions.New(555)
    srvBilling := billing.New()

    sbs := accounts.BindSubscriptions(srvAccounts)
    bl := accounts.BindBilling(srvBilling)

    accs.AddOptions(sbs)
    accs.AddOptions(bl)

    accs.Process(777)
}


Output result:

Variant_1:
        a.Prop (before): 111
        a.Prop (after): 222

Variant_2:
        a.Prop (before): 333
        a.Prop (after): 444

Variant_3:
        a.Prop (before): 555
        a.Prop (after): 777

Thank you for reading.

All sources you can find in my repository:https://github.com/romanitalian/go-service-options

PR's are welcome.

Any questions: https://twitter.com/romanitalian are also welcome!

Originally published on dev.to

    HTML
    PHP
    javascript
    CSS
    Shell
    Java
    golang
    Linux

Related Articles

Related Issues

viebel / klipse-clj
viebel / klipse-clj
  • Open
  • 0
  • 0
  • Intermediate
  • Clojure
viebel / klipse
  • Open
  • 0
  • 0
  • Intermediate
  • Clojure
viebel / klipse
  • 1
  • 0
  • Intermediate
  • Clojure
viebel / klipse
  • Started
  • 0
  • 1
  • Intermediate
  • Clojure
  • $80
viebel / klipse
  • Open
  • 0
  • 0
  • Advanced
  • Clojure
  • $80
viebel / klipse
  • Started
  • 0
  • 2
  • Advanced
  • Clojure
  • $180
viebel / klipse
  • Started
  • 0
  • 1
  • Intermediate
  • Clojure
viebel / klipse
  • 1
  • 1
  • Advanced
  • Clojure
  • $300
viebel / klipse
  • Open
  • 0
  • 0
  • Intermediate
  • Clojure

Get hired!

Sign up now and apply for roles at companies that interest you.

Engineers who find a new job through Golang Works average a 15% increase in salary.

Start with GitHubStart with Stack OverflowStart with Email