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 publish this job!

Login or register
to save this job!

Login or register
to save interesting jobs!

Login or register
to get access to all your job applications!

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!

Login or register
to save articles!

Login to see the application

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

You will be redirected back to this page right after signin

Blog hero image

Go (golang) service options (dependencies)

Roman Romadin 26 October, 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.
Join our newsletter
Join over 111,000 others and get access to exclusive content, job opportunities and more!

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

Related Issues

open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Started
  • 0
  • 1
  • Intermediate
  • HTML
open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Started
  • 0
  • 2
  • Intermediate
  • HTML
open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Open
  • 0
  • 0
  • Intermediate
  • HTML
open-editions / corpus-joyce-ulysses-tei
open-editions / corpus-joyce-ulysses-tei
  • Open
  • 0
  • 0
  • Intermediate
  • HTML

Get hired!

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

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

Start with GitHubStart with Stack OverflowStart with Email