Skip to content

Instantly share code, notes, and snippets.

  • Select an option

  • Save diki-haryadi/2c2bfd181299eadcf781f2ea82d872df to your computer and use it in GitHub Desktop.

Select an option

Save diki-haryadi/2c2bfd181299eadcf781f2ea82d872df to your computer and use it in GitHub Desktop.
Mau liat contoh ๐“๐ข๐ ๐ก๐ญ ๐‚๐จ๐ฎ๐ฉ๐ฅ๐ข๐ง๐  vs ๐‹๐จ๐จ๐ฌ๐ž ๐‚๐จ๐ฎ๐ฉ๐ฅ๐ข๐ง๐  pake ๐†๐จ๐ฅ๐š๐ง๐ ?

๐“๐ข๐ ๐ก๐ญ ๐‚๐จ๐ฎ๐ฉ๐ฅ๐ข๐ง๐ 

Di contoh ini, UserService langsung terikat sama DataSource tertentu. Kalo kita mau ganti dari PostgreSQL ke MySQL misalnya, kita harus rombak banyak hal di UserService.

package main

import "fmt"

// DataSource contohnya "koneksi" ke DB tertentu
type DataSource struct {
	// misal ada config dsb.
}

// Contoh method yg "nempel" ke DataSource
func (ds *DataSource) Connect() {
	fmt.Println("Connected to a specific DB (e.g., PostgreSQL)")
}

type UserService struct {
	ds DataSource
}

func (us *UserService) GetUser(username string) {
	// Kalo kita ubah detail DataSource, disini juga bisa ikut berubah
	us.ds.Connect()
	fmt.Printf("Fetching user '%s' from a specific DB\n", username)
}

func main() {
	userService := UserService{
		ds: DataSource{},
	}
	userService.GetUser("JohnDoe")
}

Kenapa dibilang ๐“๐ข๐ ๐ก๐ญ ๐‚๐จ๐ฎ๐ฉ๐ฅ๐ข๐ง๐ ?

Karena UserService bergantung langsung ke implementasi DataSource itu sendiri. Ganti engine DB bakal bikin UserService turut dirombak.

๐‹๐จ๐จ๐ฌ๐ž ๐‚๐จ๐ฎ๐ฉ๐ฅ๐ข๐ง๐ 

Nah, kalo yang ini UserService cuma tau โ€œkontrakโ€ data store-nya lewat interface. Dalemannya mau PostgreSQL, MySQL, atau bahkan NoSQL juga bisa, asal implementasinya sesuai interface. Hasilnya, maintenance dan scaling jadi lebih enak.

package main

import "fmt"

// Interface yang cuma tau "kontrak"-nya aja
type DataStore interface {
	Connect() error
	FetchUser(username string) (string, error)
}

// Implementasi DataStore untuk PostgreSQL
type PostgresStore struct{}

func (ps *PostgresStore) Connect() error {
	fmt.Println("Connected to PostgreSQL")
	return nil
}

func (ps *PostgresStore) FetchUser(username string) (string, error) {
	// misal di sini ada query ke PostgreSQL
	return fmt.Sprintf("Data user '%s' dari PostgreSQL", username), nil
}

// Kalo mau implementasi MySQL, bikin struct & method mirip2 PostgresStore

type UserService struct {
	ds DataStore
}

func NewUserService(store DataStore) *UserService {
	return &UserService{
		ds: store,
	}
}

func (us *UserService) GetUser(username string) {
	err := us.ds.Connect()
	if err != nil {
		fmt.Println("Error connecting:", err)
		return
	}
	data, err := us.ds.FetchUser(username)
	if err != nil {
		fmt.Println("Error fetching user:", err)
		return
	}
	fmt.Println(data)
}

func main() {
	// Mau PostgresStore atau MySQLStore, silakan
	store := &PostgresStore{}
	userService := NewUserService(store)

	userService.GetUser("JaneDoe")
}

Kenapa dibilang ๐‹๐จ๐จ๐ฌ๐ž ๐‚๐จ๐ฎ๐ฉ๐ฅ๐ข๐ง๐ ?

Karena UserService cuma tau โ€œkontrakโ€ DataStore. Dalemannya si PostgresStore bisa berubah, atau kita ganti ke MySQLStore, tapi UserService tetep jalan tanpa perlu diotak-atik.

Intinya, kalo kita pengen bikin sistem yang gampang di-maintenance dan di-scale, ๐‹๐จ๐จ๐ฌ๐ž ๐‚๐จ๐ฎ๐ฉ๐ฅ๐ข๐ง๐  jauh lebih enak. Tapi pasti ada trade-off juga, kayak nambah overhead desain, interface, dsb.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment