Dependency Injection di Go-Lang Menggunakan Wire

By Rizky Kurniawan - May 19, 2023 ~5 mins read

Dependency injection (DI) adalah konsep penting dalam pengembangan perangkat lunak yang membantu dalam mengatur dependensi antara komponen-komponen dalam sebuah aplikasi. Di bahasa pemrograman Go, terdapat paket (package) yang disebut “Wire” yang memudahkan implementasi DI secara otomatis. Pada tulisan ini, kita akan mencoba menggunakan paket “wire” untuk melakukan DI dalam aplikasi Go.

Apa itu Wire?

Wire adalah paket yang dikembangkan oleh Google untuk mempermudah pengaturan dependensi dalam proyek Go. Dengan menggunakan Wire, kita dapat mendefinisikan dependensi antara komponen-komponen dalam sebuah konfigurasi, dan Wire akan menghasilkan kode penghubung (wiring code) yang diperlukan secara otomatis.

Manfaat Menggunakan Wire

Penggunaan paket Wire untuk melakukan DI dalam aplikasi Go memiliki beberapa manfaat, antara lain adalah sebagai berikut:

  1. Kode Lebih Bersih: Dengan menggunakan Wire, kita dapat memisahkan logika penghubungan dependensi dari kode bisnis utama. Ini membuat kode lebih bersih, lebih mudah dibaca, dan lebih mudah dipelihara.
  2. Pengurangan Kesalahan: Wire menggunakan analisis statis untuk memastikan kesalahan penghubungan dependensi terdeteksi sebelum aplikasi dijalankan. Ini membantu mencegah beberapa kesalahan umum yang terkait dengan pengaturan dependensi manual.
  3. Skalabilitas: Dengan menggunakan Wire, kita dapat dengan mudah menambah atau mengubah dependensi dalam proyek Go. Wire akan menghasilkan kode penghubung yang diperbarui secara otomatis, sehingga mempermudah pengembangan aplikasi yang skalabel.

Install Wire

Untuk menginstal paket “Wire” di Go, Kita dapat mengikuti langkah-langkah berikut:

Pastikan Kita memiliki Go yang terinstal di sistem Kita. Kita dapat mengunduh dan menginstal Go dari situs resmi Go: https://golang.org/

Buka terminal atau command prompt dan ketik perintah berikut untuk menginstal paket “Wire”:

go get github.com/google/wire

Perintah ini akan mendownload dan menginstal paket “Wire” beserta dependensinya ke dalam direktori Go Kita.

Setelah selesai, Kita dapat menggunakan paket “Wire” dalam proyek Go Kita dengan mengimpornya menggunakan import “github.com/google/wire” di file Go yang relevan.

Pastikan sistem Kita terhubung dengan internet saat menjalankan perintah go get untuk mengunduh dan menginstal paket “Wire” serta dependensinya dari repositori GitHub. Jika ada masalah atau kesalahan, pastikan Kita telah mengatur konfigurasi lingkungan Go dengan benar.

Setelah menginstal Wire, Kita dapat mulai menggunakan Wire untuk mengelola dependensi dalam proyek Go Kita.

Contoh Sederhana Penggunaan Wire

Berikut ini adalah contoh kode sederhana untuk mengilustrasikan penggunaan paket “Wire” dalam Go:

Mendefinisikan Provider

Mekanisme utama dalam Wire adalah provider: fungsi yang dapat menghasilkan nilai. Fungsi-fungsi ini adalah kode Go biasa.

package foobarbaz

type Foo struct {
    X int
}

// ProvideFoo mengembalikan sebuah Foo.
func ProvideFoo() Foo {
    return Foo{X: 42}
}

Fungsi provider harus diekspor agar bisa digunakan dari package lain, seperti halnya fungsi biasa.

Provider dapat menentukan dependensi dengan menggunakan parameter:

package foobarbaz

// ...

type Bar struct {
    X int
}

// ProvideBar mengembalikan sebuah Bar: sebuah Foo dengan nilai negatif.
func ProvideBar(foo Foo) Bar {
    return Bar{X: -foo.X}
}

Provider juga dapat mengembalikan error:

package foobarbaz

import (
    "context"
    "errors"
)

// ...

type Baz struct {
    X int
}

// ProvideBaz mengembalikan sebuah nilai jika Bar tidak nol.
func ProvideBaz(ctx context.Context, bar Bar) (Baz, error) {
    if bar.X == 0 {
        return Baz{}, errors.New("tidak dapat menyediakan baz ketika bar bernilai nol")
    }
    return Baz{X: bar.X}, nil
}

Provider dapat dikelompokkan menjadi set provider. Hal ini berguna jika beberapa provider akan sering digunakan bersama. Untuk menambahkan provider-provider ini ke dalam set baru yang disebut “SuperSet”, gunakan fungsi wire.NewSet:

package foobarbaz

import (
    // ...
    "github.com/google/wire"
)

// ...

var SuperSet = wire.NewSet(ProvideFoo, ProvideBar, ProvideBaz)

Kita juga dapat menambahkan set provider lain ke dalam set provider.

package foobarbaz

import (
    // ...
    "example.com/some/other/pkg"
)

// ...

var MegaSet = wire.NewSet(SuperSet, pkg.OtherSet)

Injector

Sebuah aplikasi menghubungkan provider-provider ini dengan injector: sebuah fungsi yang memanggil provider-provider sesuai dengan urutan dependensi. Dengan Wire, Kita menuliskan tanda tangan injector, kemudian Wire menghasilkan isi fungsi tersebut.

Sebuah injector dideklarasikan dengan menuliskan deklarasi fungsi yang bodinya adalah pemanggilan wire.Build. Nilai kembalian tidak penting selama mereka memiliki tipe yang benar. Nilai-nilai itu sendiri akan diabaikan dalam kode yang dihasilkan. Misalkan provider-provider di atas didefinisikan dalam package dengan nama example.com/foobarbaz. Berikut adalah contoh mendeklarasikan injector untuk mendapatkan sebuah Baz:

// +build wireinject
// Tag build memastikan stub ini tidak dibangun dalam build akhir.

package main

import (
    "context"

    "github.com/google/wire"
    "example.com/foobarbaz"
)

func initializeBaz(ctx context.Context) (foobarbaz.Baz, error) {
    wire.Build(foobarbaz.MegaSet)
    return foobarbaz.Baz{}, nil
}

Seperti provider, injector dapat diberikan parameter masukan (yang kemudian dikirimkan ke provider) dan dapat mengembalikan error. Argumen-argumen untuk wire.Build adalah sama dengan wire.NewSet: mereka membentuk satu set provider. Inilah set provider yang digunakan saat penghasilan kode untuk injector tersebut.

Setiap deklarasi non-injector yang ditemukan dalam file yang memiliki injector akan disalin ke file yang dihasilkan.

Kita dapat menghasilkan injector dengan menjalankan Wire di direktori package:

wire

Wire akan menghasilkan implementasi injector dalam sebuah file bernama wire_gen.go yang terlihat mirip dengan ini:

// Code generated by Wire. DO NOT EDIT.

//go:generate go run -mod=mod github.com/google/wire/cmd/wire
//+build !wireinject

package main

import (
    "example.com/foobarbaz"
)

func initializeBaz(ctx context.Context) (foobarbaz.Baz, error) {
    foo := foobarbaz.ProvideFoo()
    bar := foobarbaz.ProvideBar(foo)
    baz, err := foobarbaz.ProvideBaz(ctx, bar)
    if err != nil {
        return foobarbaz.Baz{}, err
    }
    return baz, nil
}

Seperti yang dapat Kita lihat, outputnya sangat mirip dengan apa yang akan ditulis oleh pengembang secara manual. Selain itu, tidak ada ketergantungan pada Wire saat runtime: semua kode yang ditulis adalah kode Go normal dan dapat digunakan tanpa Wire.

Setelah wire_gen.go dibuat, Kita dapat menghasilkannya kembali dengan menjalankan perintah go generate.

Sumber: https://github.com/google/wire/blob/main/docs/guide.md

Ingin Berdiskusi?

Yuk bergabung di Grup Telegram Ruang Developer atau mulai diskusi melalui GitHub. See You!

Dapatkan contoh source code project backend, frontend, atau fullstack untuk kamu amati, tiru, dan modifikasi sesuka hati. Klik untuk melihat detail!
comments powered by Disqus

Berlangganan Gratis

Kamu akan menerima email update dari Ruang Developer

Beri Dukungan

Beri dukungan, dapatkan full source code project web untuk bahan referensi, tiru, dan modifikasi.
Lightbox