Dependency Injection #
Dalam perjalanan karier sebagai software engineer, hampir semua dari kita pernah menulis kode yang awalnya terlihat rapi, tapi beberapa bulan kemudian berubah menjadi mimpi buruk saat harus diuji, diubah, atau dikembangkan. Salah satu akar masalah yang paling sering saya temui adalah ketergantungan (dependency) yang saling mengikat terlalu kuat.
Di sinilah Dependency Injection (DI) muncul — bukan sebagai tren, tapi sebagai solusi nyata terhadap masalah desain software yang sudah ada sejak lama.
Apa itu Dependency Injection? #
Dependency Injection (DI) adalah sebuah design pattern di mana sebuah objek tidak membuat sendiri dependency yang ia butuhkan, melainkan dependency tersebut “disuntikkan” dari luar.
Contoh masalah tanpa DI #
type UserService struct {}
func (s *UserService) Register() {
repo := NewUserRepository()
repo.Save()
}
Di sini:
UserServicesecara langsung membuatUserRepositoryUserServiceterikat kuat ke implementasi konkret
Artinya:
- Sulit dites
- Sulit diganti
- Sulit dikembangkan
Dengan Dependency Injection #
type UserService struct {
repo UserRepository
}
func NewUserService(repo UserRepository) *UserService {
return &UserService{repo: repo}
}
Sekarang:
UserServicetidak peduli bagaimanaUserRepositorydibuat- Ia hanya peduli pada kontrak (interface)
Intinya: Dependency Injection memindahkan tanggung jawab pembuatan dependency ke luar objek.
Kenapa ada Dependency Injection? #
Dependency Injection tidak muncul karena teori, tapi karena rasa sakit (pain) yang nyata dalam software development.
Masalah klasik tanpa DI #
Tight Coupling
- Class/service terlalu bergantung pada detail implementasi
Sulit di-test
- Unit test berubah jadi integration test
Perubahan kecil → efek domino
- Ganti database → ubah banyak kode
Kode sulit dirawat
- Engineer baru butuh waktu lama memahami alur
Dependency Injection hadir untuk menjawab: #
- Bagaimana memisahkan business logic dari infrastructure
- Bagaimana membuat kode fleksibel tanpa chaos
- Bagaimana mendukung scalability tim, bukan hanya aplikasi
DI bukan tentang “lebih canggih”, tapi tentang mengurangi biaya perubahan.
Bagaimana DI mempengaruhi software development? #
Dampak DI tidak langsung terasa di awal, tapi sangat terasa di jangka menengah dan panjang.
Testability meningkat drastis #
Dengan DI:
mockRepo := new(MockUserRepository)
service := NewUserService(mockRepo)
- Unit test benar-benar unit test
- Tidak perlu database
- Tidak perlu network
Tim yang serius soal testing hampir pasti menggunakan DI.
Separation of Concerns lebih jelas #
Dengan DI, biasanya arsitektur menjadi:
- Controller / Handler
- Service (business logic)
- Repository (data access)
- Infrastructure (DB, API, cache)
Setiap layer:
- Fokus ke tanggung jawabnya
- Tidak tahu detail layer lain
Ini membuat:
- Kode lebih mudah dibaca
- Diskusi desain lebih objektif
- Refactor lebih aman
Perubahan jadi lebih murah #
Misalnya:
- Ganti MySQL → PostgreSQL
- Ganti REST → gRPC
- Ganti third-party service
Dengan DI:
- Yang berubah implementasi
- Kontrak tetap sama
Tanpa DI:
- Perubahan menyebar ke mana-mana
Skala tim lebih sehat #
DI memaksa kita berpikir dalam:
- Interface
- Kontrak
- Boundary
Ini sangat membantu ketika:
- Tim bertambah
- Modul dikerjakan paralel
- Ownership dibagi
Kenapa Dependency Injection adalah best practice? #
Dependency Injection disebut best practice bukan karena semua orang memakainya, tapi karena ia:
Selaras dengan prinsip SOLID #
- S: Single Responsibility
- O: Open/Closed
- D: Dependency Inversion
DI adalah implementasi praktis dari Dependency Inversion Principle:
High-level modules should not depend on low-level modules.
Mendorong desain yang eksplisit #
Dengan DI:
- Dependency terlihat jelas di constructor
- Tidak ada “magic dependency” tersembunyi
- Kode lebih jujur tentang kebutuhannya
Ini sangat penting untuk:
- Code review
- Onboarding engineer baru
- Debugging
Industri sudah membuktikannya #
Framework besar menggunakan DI secara eksplisit atau implisit:
- Spring (Java)
- NestJS (Node.js)
- ASP.NET Core
- Uber FX (Go)
- Google Wire (Go)
Bukan kebetulan — DI adalah fondasi arsitektur modern.
DI bukan over-engineering (jika digunakan benar) #
Kesalahan umum:
- Menganggap DI = container kompleks
- Menganggap DI selalu butuh framework
Padahal:
- Constructor injection sederhana sudah DI
- Tidak perlu container jika belum perlu
DI adalah soal mindset desain, bukan soal library.
Penutup #
Dependency Injection bukan solusi untuk semua masalah. Namun, tanpa DI, hampir semua sistem yang tumbuh akan:
- Sulit diuji
- Sulit diubah
- Mahal dirawat
Sebagai software engineer, kita tidak dibayar hanya untuk membuat kode berjalan hari ini, tetapi untuk membuat sistem yang masih bisa diubah besok.
Dan di situlah Dependency Injection benar-benar menunjukkan nilainya.