Traffine I/O

Bahasa Indonesia

2022-05-19

Prinsip Inversi Ketergantungan

Apa itu Prinsip Inversi Ketergantungan (DIP)

Prinsip Inversi Ketergantungan (Dependency Inversion Principle atau DIP) berkaitan dengan hubungan dan ketergantungan antara modul tingkat tinggi dan tingkat rendah dalam suatu sistem perangkat lunak. Prinsip ini mengemukakan dua poin utama:

  • Modul tingkat tinggi tidak boleh bergantung pada modul tingkat rendah. Keduanya harus bergantung pada abstraksi.
    Modul tingkat tinggi mengkapsulasi aturan bisnis dari suatu sistem - logika kritis dan kompleks yang memberikan nilai unik pada perangkat lunak. Modul tingkat rendah, di sisi lain, mengurus operasi seperti akses database, jaringan, operasi I/O, dan lain-lain. Dengan DIP, kedua jenis modul berinteraksi melalui abstraksi (seperti antarmuka atau kelas abstrak), memastikan bahwa perubahan pada detail modul tingkat rendah tidak akan memengaruhi modul tingkat tinggi, sehingga membuat kode lebih tangguh dan mudah untuk dipelihara.

  • Abstraksi tidak boleh bergantung pada detail. Detail harus bergantung pada abstraksi.
    Secara tradisional, abstraksi (antarmuka atau kelas abstrak) dirancang berdasarkan detail (implementasi konkret). DIP membalikkan hubungan ini. Implementasi konkret harus dibangun berdasarkan abstraksi. Pendekatan ini menghasilkan sistem yang lebih fleksibel, di mana fungsionalitas baru dapat diperkenalkan dengan hanya membuat implementasi baru dari abstraksi, tanpa mengubah kode yang ada.

DIP
Dependency Inversion Principle(DIP)

Inversi Ketergantungan dalam DDD

Domain-Driven Design (DDD) adalah pendekatan pengembangan perangkat lunak yang menekankan kolaborasi antara ahli teknis dan ahli domain untuk memenuhi kebutuhan bisnis yang kompleks. Salah satu aspek sentral dalam DDD adalah pemisahan yang jelas antara lapisan domain dan lapisan infrastruktur. Dalam bab ini, saya akan menjelajahi bagaimana Prinsip Inversi Ketergantungan (DIP) memainkan peran penting dalam memastikan pemisahan ini dan menciptakan solusi perangkat lunak yang tangguh dan mudah dipelihara.

Peran Lapisan Domain dan Infrastruktur dalam DDD

Sebelum membahas DIP dalam konteks DDD, penting untuk memahami peran lapisan domain dan infrastruktur dalam DDD:

  • Lapisan Domain
    Lapisan ini mengkapsulasi logika bisnis dan aturan sistem. Lapisan ini dianggap sebagai inti perangkat lunak dan sepenuhnya independen dari teknologi atau masalah infrastruktur tertentu.

  • Lapisan Infrastruktur
    Lapisan ini mencakup elemen seperti database, antarmuka pengguna (UI), layanan eksternal, dll. Elemen-elemen ini bertanggung jawab atas masalah teknis yang mendukung fungsi lapisan domain, tetapi tidak terkait dengan logika bisnis itu sendiri.

Dalam DDD, penting untuk menjaga pemisahan yang jelas antara lapisan ini untuk memastikan bahwa perubahan di satu lapisan tidak memengaruhi lapisan lainnya, sehingga memberikan arsitektur yang mudah dipelihara dan fleksibel.

Mengaplikasikan Prinsip Inversi Ketergantungan dalam DDD

Prinsip Inversi Ketergantungan dapat menjadi alat yang kuat untuk menjaga pemisahan antara lapisan domain dan lapisan infrastruktur, memastikan bahwa lapisan domain tetap terisolasi dari perubahan infrastruktur.

Sesuai dengan DIP, lapisan domain yang tingkat tinggi tidak boleh bergantung pada lapisan infrastruktur yang tingkat rendah. Sebaliknya, keduanya harus bergantung pada abstraksi. Mari kita lihat lebih detail bagaimana ini dilakukan:

  • Ketergantungan pada Abstraksi
    Dalam konteks DDD, lapisan domain mendefinisikan antarmuka (abstraksi) untuk layanan apa pun yang dibutuhkannya dari lapisan infrastruktur. Layanan ini dapat mencakup repositori untuk menyimpan objek domain, layanan untuk mengirim email, dll.

  • Membalikkan Ketergantungan
    Lapisan infrastruktur menyediakan implementasi konkret untuk antarmuka ini, tetapi yang penting, lapisan domain tetap tidak mengetahui implementasi-implementasi tersebut. Dengan demikian, arah ketergantungan dibalikkan: bukan lapisan domain yang bergantung pada lapisan infrastruktur, tetapi lapisan infrastruktur yang bergantung pada lapisan domain.

Mengimplementasikan DIP dalam DDD

Dalam bab ini, saya akan melihat implementasi Python yang menunjukkan Prinsip Inversi Ketergantungan (DIP) dalam konteks Domain-Driven Design (DDD).

Untuk demonstrasi ini, mari kita pertimbangkan sebuah sistem sederhana di mana UserService di lapisan domain memerlukan UserDataAccess dari lapisan infrastruktur untuk mengambil informasi pengguna dari database.

Kasus Tanpa Inversi Ketergantungan

Pertama, mari kita lihat situasi di mana DIP tidak diimplementasikan.

infrastructure_layer.py
class UserDataAccess:
    def get_user(self, user_id):
        # Implementation to fetch user from the database
        pass
domain_layer.py
from infrastructure_layer import UserDataAccess

class UserService:
    def __init__(self):
        self.user_data_access = UserDataAccess()

    def get_user_details(self, user_id):
        return self.user_data_access.get_user(user_id)

Dalam contoh ini, kelas UserService secara langsung bergantung pada kelas UserDataAccess dari lapisan infrastruktur. Desain ini melanggar DIP karena modul tingkat tinggi UserService bergantung langsung pada modul tingkat rendah UserDataAccess.

Mengimplementasikan Invers Ketergantungan

Sekarang, mari modifikasi sistem di atas agar sesuai dengan DIP.

domain_layer.py
from abc import ABC, abstractmethod

class IUserRepository(ABC):
    @abstractmethod
    def get_user(self, user_id):
        pass

class UserService:
    def __init__(self, user_repository: IUserRepository):
        self.user_repository = user_repository

    def get_user_details(self, user_id):
        return self.user_repository.get_user(user_id)

Pada contoh yang diperbarui ini, kita telah mendefinisikan antarmuka IUserRepository di lapisan domain. Antarmuka ini menyediakan metode abstrak get_user, yang akan digunakan oleh UserService untuk mengambil data pengguna.

UserService sekarang bergantung pada antarmuka IUserRepository, bukan pada kelas konkret UserDataAccess. Saat membuat objek UserService, kita memberikan objek dari kelas yang mengimplementasikan IUserRepository.

infrastructure_layer.py
from domain_layer import IUserRepository

class UserDataAccess(IUserRepository):
    def get_user(self, user_id):
        # Implementation to fetch user from the database
        pass

Di lapisan infrastruktur, UserDataAccess sekarang mengimplementasikan antarmuka IUserRepository. Dengan demikian, UserDataAccess sesuai dengan abstraksi yang dibutuhkan oleh UserService.

main.py
from domain_layer import UserService
from infrastructure_layer import UserDataAccess

def main():
    user_repository = UserDataAccess()
    user_service = UserService(user_repository)
    user_service.get_user_details("user_id")

if __name__ == "__main__":
    main()

Di bagian utama aplikasi, kita membuat instance dari UserDataAccess dan memberikannya kepada UserService. Desain ini sesuai dengan DIP: modul tingkat tinggi (UserService) tidak bergantung pada modul tingkat rendah (UserDataAccess); keduanya bergantung pada abstraksi (IUserRepository).

Ryusei Kakujo

researchgatelinkedingithub

Focusing on data science for mobility

Bench Press 100kg!