👨‍💻
Sammi
  • Hello
  • About Me
    • Links
    • My Daily Uses
  • PostgreSQL → Partitioning
  • Belajar System Programming Menggunakan Go
    • Mengingat Kembali Tentang Concurrency dan Parallelism
  • Memory Management
  • Explore
    • Testing 1: Load and performance testing
    • Data Structure 1: Bloom Filter
    • System Design 1: Back of The Envelope Estimation
    • System Design 2: A Framework For System Design Interviews
    • System Design 3: Design a URL Shortener
    • Belajar RabbitMQ
  • Belajar Kubernetes
  • Notes
    • Permasalahan Penggunaan JWT dan Solusinya dengan PASETO
    • First Principle Thinking
    • The Over-Engineering Pendulum
    • Data-Oriented Programming
  • CAP Theorem
  • Go Series: Safer Enum
  • Go Series: Different types of for loops in Golang?
  • Go Series: Mutex & RWMutex
  • Setup VM Production Ready Best Practice
  • BEHAVIOUR QUESTION
  • Invert, always invert
  • Mengapa Tidak Menggunakan Auto-Increment ID?
  • I Prefix dan Impl Suffix
  • ACID
  • MVCC Di Postgres
  • Implicit Interface di Go
  • Transaction di Postgres
  • Kriteria Kolom yang Cocok Dijadikan Index
  • Misc
    • Go Project
    • Talks
    • Medium Articles
  • PostgreSQL
    • Introduction
  • English
    • Vocab
Powered by GitBook
On this page

Implicit Interface di Go

1. Konsep Dasar Implementasi Interface di Go

  • Implementasi interface bersifat implisit (duck typing):

    • Jika suatu tipe memiliki semua method yang didefinisikan oleh sebuah interface, maka tipe tersebut dianggap mengimplementasikan interface tersebut.

    • Contoh:

      type KeyValueStore interface {
          Get(ctx context.Context, key string) (string, error)
          Set(ctx context.Context, key string, value string) error
      }
      
      type Client struct{}
      func (c *Client) Get(ctx context.Context, key string) (string, error) { ... }
      func (c *Client) Set(ctx context.Context, key string, value string) error { ... }
      • *Client otomatis mengimplementasikan KeyValueStore tanpa deklarasi eksplisit.

2. Kelebihan Implementasi Implisit

  • Tidak perlu ketergantungan (dependency) pada definisi interface:

    • Interface bisa dibuat belakangan tanpa mengubah implementasi.

    • Berguna saat pola desain belum jelas di awal pengembangan.

  • Cocok untuk interface generik (seperti io.Reader, io.Writer):

    • Implementasi tidak perlu mengimpor package yang mendefinisikan interface.

3. Masalah Utama Implementasi Implisit

a. Semantic Meaning yang Tidak Jelas

  • Interface dengan method sama bisa memiliki makna berbeda:

    • Contoh: cache.KeyValueStore (untuk caching) vs. config.KeyValueStore (untuk penyimpanan persistensi).

    • Di Go, *memcached.Client bisa otomatis memenuhi kedua interface, meskipun seharusnya tidak boleh.

    • Bahasa seperti Java/Rust memerlukan deklarasi eksplisit, sehingga mencegah kesalahan semantik.

b. Error Reporting yang Buruk

  • Error muncul di tempat yang salah:

    • Jika interface berubah, error tidak muncul di implementasi, tapi di lokasi penggunaan interface.

    • Contoh:

      // Interface diubah:
      type KeyValueStore interface {
          Get(ctx context.Context, key []byte) ([]byte, error) // sebelumnya string
      }
      
      // Error tidak muncul di struct Client, tapi di fungsi yang memakai Client sebagai KeyValueStore.
    • Membuat debugging lebih sulit karena root cause tidak langsung terlihat.

c. Kebingungan Saat Refaktor

  • Sulit membedakan implementasi disengaja vs. kebetulan:

    • Jika sebuah struct memiliki method yang cocok dengan beberapa interface, tidak jelas mana yang benar-benar dimaksudkan.

    • Contoh:

      • Saat config.KeyValueStore berubah, apakah *memcached.Client harus diupdate?

      • Tanpa deklarasi eksplisit, developer harus menebak berdasarkan konteks.

d. Ketergantungan Package yang Tidak Terhindarkan

  • "Tidak perlu impor interface" hanya berlaku untuk interface sederhana:

    • Jika interface menggunakan custom struct (contoh: auth.User), implementasi tetap harus mengimpor package-nya.

    • Contoh:

      package auth
      type User struct { ... }
      type UserRepository interface {
          InsertUser(ctx context.Context, user User) error // Memaksa impor package auth
      }

4. Rekomendasi

  • Gunakan implementasi implisit hanya untuk interface generik (seperti io.Reader).

  • Untuk interface spesifik:

    • Dokumentasi dengan jelas tujuan interface.

    • Pertimbangkan untuk menambahkan komentar atau prefix/suffix (misal: CacheKeyValueStore vs. ConfigKeyValueStore) untuk membedakan makna.

  • Hati-hati saat refaktor:

    • Periksa semua penggunaan interface untuk memastikan tidak ada implementasi tidak disengaja.

Kesimpulan

  • Implementasi implisit di Go memudahkan prototyping, tetapi berisiko menyebabkan:

    • Kesalahan semantik.

    • Error reporting yang tidak intuitif.

    • Kebingungan saat refaktor.

  • Gunakan dengan bijak:

    • Manfaatkan untuk kasus sederhana/generik.

    • Hindari untuk interface dengan logika kompleks atau makna spesifik.

  • Dokumentasi dan penamaan yang jelas sangat penting untuk mengurangi kebingungan.

PreviousMVCC Di PostgresNextTransaction di Postgres

Last updated 13 days ago