Kapan kita harus menggunakan injeksi ketergantungan (C #) [ditutup]


8

Saya ingin memastikan bahwa saya memahami konsep injeksi ketergantungan (DI). Yah, saya benar-benar mengerti konsepnya, DI tidak rumit: Anda membuat antarmuka lalu melewati implementasi antarmuka saya ke kelas yang menggunakannya. Cara umum untuk melewatinya adalah dengan konstruktor tetapi Anda juga dapat melewatinya dengan setter atau metode lain.

Yang saya tidak yakin untuk mengerti adalah kapan harus menggunakan DI.

Penggunaan 1: Tentu saja menggunakan DI jika Anda memiliki beberapa implementasi antarmuka Anda tampaknya logis. Anda memiliki repositori untuk SQL Server Anda kemudian yang lain untuk database Oracle Anda. Keduanya berbagi antarmuka yang sama dan Anda "menyuntikkan" (ini adalah istilah yang digunakan) yang Anda inginkan saat runtime. Ini bahkan bukan DI, ini adalah pemrograman OO dasar di sini.

Penggunaan 2: Ketika Anda memiliki lapisan bisnis dengan banyak layanan dengan semua metode spesifiknya, praktik terbaiknya adalah membuat antarmuka untuk setiap layanan dan juga menyuntikkan implementasinya walaupun ini unik. Karena ini lebih baik untuk pemeliharaan. Ini penggunaan kedua yang tidak saya mengerti.

Saya memiliki sekitar 50 kelas bisnis. Tidak ada yang umum di antara mereka. Beberapa repositori mendapatkan atau menyimpan data dalam 3 database berbeda. Beberapa membaca atau menulis file. Beberapa melakukan tindakan bisnis murni. Ada juga validator dan pembantu khusus. Tantangannya adalah manajemen memori karena beberapa kelas dipasang dari lokasi yang berbeda. Validator dapat memanggil beberapa repositori dan validator lain yang dapat memanggil repositori yang sama lagi.

Contoh: Lapisan bisnis

public class SiteService : Service, ICrud<Site>
{
    public Site Read(Item item, Site site)
    {
        return beper4DbContext.Site
            .AsNoTracking()
            .SingleOrDefault(y => y.SiteId == site.Id && y.ItemId == item.Id)
    }

    public Site Read(string itemCode, string siteCode)
    {       
        using (var itemService = new ItemService())
        {
            var item = itemService.Read(itemCode);
            return Read(item, site);
        }
    }
}
public class ItemSiteService : Service, ICrud<Site>
{
    public ItemSite Read(Item item, Site site)
    {
        return beper4DbContext.ItemSite
            .AsNoTracking()
            .SingleOrDefault(y => y.SiteId == site.Id && y.ItemId == item.Id)
    }

    public ItemSite Read(string itemCode, string siteCode)
    {        
        using (var itemService = new ItemService())
        using (var siteService = new SiteService())
        {
            var item = itemService.Read(itemCode);
            var site = siteService.Read(itemCode, siteCode);
            return Read(item, site);
        }
    }
}

Pengendali

public class ItemSiteController : BaseController
{
    [Route("api/Item/{itemCode}/ItemSite/{siteCode}")]
    public IHttpActionResult Get(string itemCode, string siteCode)
    {
        using (var service = new ItemSiteService())
        {
            var itemSite = service.Read(itemCode, siteCode);
            return Ok(itemSite);
        }
    }
}

Contoh ini sangat mendasar tetapi Anda melihat bagaimana saya dapat dengan mudah membuat 2 instance itemService untuk mendapatkan itemSite. Kemudian juga setiap layanan datang dengan konteks DB-nya. Jadi panggilan ini akan membuat 3 DbContext. 3 Koneksi.

Ide pertama saya adalah membuat singleton untuk menulis ulang semua kode ini seperti di bawah. Kode lebih mudah dibaca dan yang paling penting sistem singleton hanya membuat satu instance dari setiap layanan yang digunakan dan membuatnya pada panggilan pertama. Sempurna, kecuali saya masih memiliki konteks berbeda tetapi saya dapat melakukan sistem yang sama untuk konteks saya. Sudah selesai.

Lapisan bisnis

public class SiteService : Service, ICrud<Site>
{
    public Site Read(Item item, Site site)
    {
        return beper4DbContext.Site
            .AsNoTracking()
            .SingleOrDefault(y => y.SiteId == site.Id && y.ItemId == item.Id)
    }

    public Site Read(string itemCode, string siteCode)
    {       
            var item = ItemService.Instance.Read(itemCode);
            return Read(item, site);
    }
}
public class ItemSiteService : Service, ICrud<Site>
{
    public ItemSite Read(Item item, Site site)
    {
        return beper4DbContext.ItemSite
            .AsNoTracking()
            .SingleOrDefault(y => y.SiteId == site.Id && y.ItemId == item.Id)
    }

    public ItemSite Read(string itemCode, string siteCode)
    {        
            var item = ItemService.Instance.Read(itemCode);
            var site = SiteService.Instance.Read(itemCode, siteCode);
            return Read(item, site);       
    }
}

Pengendali

public class ItemSiteController : BaseController
{
    [Route("api/Item/{itemCode}/ItemSite/{siteCode}")]
    public IHttpActionResult Get(string itemCode, string siteCode)
    {
            var itemSite = service.Instance.Read(itemCode, siteCode);
            return Ok(itemSite);
    }
}

Beberapa orang mengatakan kepada saya sesuai dengan praktik yang baik saya harus menggunakan DI dengan contoh tunggal dan menggunakan singleton adalah praktik yang buruk. Saya harus membuat antarmuka untuk setiap kelas bisnis dan instantiate dengan bantuan wadah DI. Betulkah? DI ini menyederhanakan kode saya. Sulit untuk dipercaya.


4
DI tidak pernah tentang keterbacaan.
Robert Harvey

Jawaban:


14

Use case yang paling "populer" untuk DI (terlepas dari penggunaan pola "strategi" yang telah Anda jelaskan) mungkin adalah unit testing.

Bahkan jika Anda berpikir hanya akan ada satu implementasi "nyata" untuk antarmuka yang disuntikkan, jika Anda melakukan pengujian unit, biasanya ada yang kedua: implementasi "tiruan" dengan satu-satunya tujuan membuat tes terisolasi mungkin dilakukan. Itu memberi Anda keuntungan karena tidak harus berurusan dengan kompleksitas, bug yang mungkin, dan mungkin dampak kinerja komponen "nyata".

Jadi tidak, DI bukan untuk meningkatkan keterbacaan, itu digunakan untuk meningkatkan testabilitas (- tentu saja, tidak secara eksklusif).

Ini bukan tujuan itu sendiri. Jika kelas Anda ItemServicesangat sederhana, yang tidak membuat jaringan eksternal atau akses basis data, sehingga tidak menghalangi tes unit penulisan untuk sesuatu seperti SiteService, menguji yang terakhir dalam isolasi mungkin sepadan dengan usaha, sehingga DI tidak akan perlu. Namun, jika ItemServicemengakses situs lain dengan jaringan, Anda mungkin ingin unit tes SiteServicedipisahkan dari itu, yang dapat dicapai dengan mengganti "nyata" ItemServicedengan MockItemService, yang memberikan beberapa barang palsu kode keras.

Izinkan saya menunjukkan hal lain: dalam contoh Anda, orang mungkin berpendapat bahwa seseorang tidak perlu DI di sini untuk menguji logika bisnis inti - contoh selalu menunjukkan dua varian Readmetode, satu dengan logika bisnis nyata yang terlibat (yang dapat berupa unit diuji tanpa DI), dan yang hanya kode "lem" untuk menghubungkan ItemServiceke logika sebelumnya. Dalam kasus yang ditunjukkan, itu memang argumen yang valid terhadap DI - pada kenyataannya, jika DI dapat dihindari tanpa mengorbankan testabilitas seperti itu, maka lanjutkan. Tetapi tidak semua kode dunia nyata sangat sederhana, dan seringkali DI adalah solusi paling sederhana untuk mencapai unit testability yang "cukup".


1
Saya benar-benar mendapatkannya tetapi bagaimana jika saya tidak melakukan pengujian unit. Saya melakukan pengujian integrasi dengan database palsu. Perubahan beroperasi terlalu sering untuk mempertahankan pengujian unit dan data produksi kami berubah setiap saat. Jadi pengujian dengan salinan data nyata adalah satu-satunya cara kita dapat menguji dengan serius. Sebagai ganti Unit Testing kami melindungi semua metode kami dengan kontrak kode. Saya tahu ini tidak sama dan saya tahu pengujian unit dalam plus tetapi saya tidak punya waktu untuk memprioritaskan pengujian unit. Itu adalah fakta, bukan pilihan.
Bastien Vandamme

1
@BastienVandamme: ada ruang besar antara "tidak ada pengujian unit sama sekali" dan "kami unit menguji segalanya". Dan saya belum pernah melihat proyek besar yang tidak dapat menemukan beberapa manfaat dalam menggunakan unit test setidaknya untuk beberapa bagian. Identifikasi bagian-bagian itu, lalu periksa apakah DI diperlukan untuk membuat mereka dapat diuji.
Doc Brown

4

Dengan tidak menggunakan injeksi dependensi, Anda membiarkan diri membuat koneksi permanen ke objek lain. Koneksi yang bisa Anda sembunyikan di dalam mana mereka akan mengejutkan orang. Koneksi yang hanya dapat diubah dengan menulis ulang apa yang Anda buat.

Daripada itu, Anda dapat menggunakan injeksi dependensi (atau referensi yang lewat jika Anda sudah tua seperti saya) untuk membuat apa yang dibutuhkan suatu objek secara eksplisit tanpa memaksanya untuk menentukan bagaimana kebutuhannya harus dipenuhi.

Ini memaksa Anda untuk menerima banyak parameter. Bahkan yang dengan standar yang jelas. Dalam C # Anda beruntung memiliki argumen nama dan opsional . Itu berarti Anda memiliki argumen default. Jika Anda tidak keberatan terikat secara statis dengan default Anda, bahkan ketika Anda tidak menggunakannya, Anda dapat mengizinkan DI tanpa kewalahan dengan pilihan. Ini mengikuti konvensi tentang konfigurasi .

Pengujian bukanlah pembenaran yang baik untuk DI. Saat Anda berpikir itu adalah seseorang akan menjual kerangka kerja mengejek ahli yang menggunakan refleksi atau sihir lain untuk meyakinkan Anda bahwa Anda dapat kembali ke cara Anda bekerja sebelumnya dan menggunakan sihir untuk melakukan sisanya.

Digunakan dengan benar, pengujian bisa menjadi cara yang baik untuk menunjukkan apakah suatu desain terisolasi. Tapi bukan itu intinya. Itu tidak menghentikan tenaga penjualan untuk mencoba membuktikan bahwa dengan sihir yang cukup semuanya terisolasi. Pertahankan sihir seminimal mungkin.

Maksud dari isolasi ini adalah untuk mengelola perubahan. Sangat menyenangkan jika satu perubahan dapat dilakukan di satu tempat. Tidak baik harus mengikuti file demi file berharap bahwa kegilaan akan berakhir.

Tempatkan saya di toko yang menolak untuk melakukan pengujian unit dan saya masih akan melakukan DI. Saya melakukannya karena itu memungkinkan saya memisahkan apa yang diperlukan dari bagaimana hal itu dilakukan. Pengujian atau tidak ada pengujian Saya ingin isolasi itu.


2
Bisakah Anda menguraikan mengapa pengujian bukanlah pembenaran yang baik untuk DI? Anda tampaknya menggabungkannya dengan kerangka refleksi magis - dan saya mengerti tidak suka itu - tetapi tidak membuat tandingan dengan ide itu sendiri.
Jacob Raihle

1
Argumen mengejek itu tampak seperti lereng yang licin. Saya tidak menggunakan kerangka mengejek, tapi saya mengerti manfaat DI.
Robert Harvey

2
Itu hanya ekor peringatan. Ketika orang berpikir bahwa mengaktifkan pengujian otomatis adalah satu-satunya alasan untuk melakukan DI, mereka tidak hanya kehilangan pemahaman tentang manfaat untuk merancang fleksibilitas, mereka juga menjadi rentan terhadap promosi penjualan untuk produk yang menjanjikan manfaat tanpa pekerjaan. DI adalah pekerjaan. Tidak ada makan siang gratis.
candied_orange

3
Dengan kata lain, decoupling adalah alasan sebenarnya untuk DI. Pengujian hanyalah salah satu bidang yang paling umum di mana manfaat decoupling terbukti.
StackOverthrow

2
Hei, jangan bercanda. Jika DI tidak membantu Anda mempertahankan kode Anda jangan menggunakannya.
candied_orange

2

Pandangan helikopter DI hanya kemampuan untuk menukar implementasi untuk antarmuka . Meskipun ini tentu saja merupakan anugerah untuk pengujian, ada manfaat potensial lainnya:

Implementasi versi objek

Jika metode Anda menerima parameter antarmuka di lapisan tengah, Anda bebas untuk melewati implementasi apa pun yang Anda suka di lapisan atas yang mengurangi jumlah kode yang perlu ditulis untuk menukar implementasi. Memang ini adalah manfaat dari antarmuka, tetapi jika kode ditulis dengan DI dalam pikiran, Anda akan mendapatkan manfaat ini di luar kotak.

Mengurangi jumlah objek yang perlu melewati lapisan

Meskipun ini terutama berlaku untuk kerangka kerja DI, jika objek A membutuhkan instance objek B , dimungkinkan untuk melakukan query kernel (atau apa pun) untuk menghasilkan objek B dengan cepat daripada meneruskannya melalui lapisan. Ini mengurangi jumlah kode yang perlu ditulis dan diuji. Itu juga membuat lapisan yang tidak peduli tentang objek B bersih.


2

Tidak perlu menggunakan antarmuka untuk menggunakan DI. Tujuan utama DI adalah untuk memisahkan konstruksi dan penggunaan objek.

Menggunakan lajang sangat disukai dalam banyak kasus. Salah satu alasannya adalah menjadi sangat sulit untuk mendapatkan gambaran umum tentang dependensi yang dimiliki suatu kelas.

Dalam contoh Anda, ItemSiteController dapat dengan mudah mengambil ItemSiteService sebagai argumen konstruktor. Ini memungkinkan Anda menghindari biaya pembuatan objek, tetapi menghindari ketidakfleksibelan singleton. Hal yang sama berlaku untuk ItemSiteService, jika membutuhkan ItemService dan SiteService, masukkan mereka ke dalam konstruktor.

Manfaatnya paling besar ketika semua benda menggunakan injeksi ketergantungan. Ini memungkinkan Anda untuk memusatkan konstruksi ke modul khusus, atau mendelegasikannya ke wadah DI.

Hirarki ketergantungan mungkin terlihat seperti ini:

public interface IStorage
{
}

public class DbStorage : IStorage
{
    public DbStorage(string connectionString){}
}

public class FileStorage : IStorage
{
    public FileStorage(FileInfo file){}
}

public class MemoryStorage : IStorage
{
}

public class CachingStorage : IStorage
{
    public CachingStorage(IStorage storage) { }
}

public class MyService
{
    public MyService(IStorage storage){}
}

public class Controller
{
    public Controller(MyService service){}
}

Perhatikan bahwa hanya ada satu kelas tanpa parameter konstruktor, dan hanya satu antarmuka. Saat mengkonfigurasi wadah DI, Anda dapat memutuskan penyimpanan apa yang akan digunakan, atau apakah caching harus digunakan, dll. Pengujian lebih mudah karena Anda dapat memutuskan basis data apa yang akan digunakan, atau menggunakan jenis penyimpanan lain. Anda juga dapat mengkonfigurasi wadah DI untuk memperlakukan objek sebagai lajang jika diperlukan, dalam konteks objek wadah.


"Dalam contoh Anda, ItemSiteController dapat dengan mudah mengambil ItemSiteService sebagai argumen konstruktor." Tentu saja tetapi pengontrol dapat menggunakan dari 1 hingga 10 layanan. Lalu kadang-kadang saya dapat menambahkan satu layanan baru yang memaksa saya untuk mengubah tanda tangan konstruktor. Bagaimana Anda bisa mengatakan ini lebih baik untuk pemeliharaan? Dan tidak, ini mungkin akan membuat saya menghabiskan banyak waktu karena saya tidak memiliki mekanisme tunggal lagi. Jadi saya harus meneruskannya ke setiap pengontrol yang menggunakannya. Bagaimana saya bisa memastikan pengembang tidak selalu membuatnya kembali. Sistem apa yang dapat memastikan saya hanya membuatnya sekali?
Bastien Vandamme

Saya pikir, seperti kebanyakan orang, Anda mencampur pola DI dengan Fitur Wadah. Contoh Anda adalah Penggunaan saya 1. Saya tidak menentang yang ini. Ketika Anda memiliki beberapa implementasi antarmuka, Anda harus menggunakan apa yang Anda sebut DI. Saya menyebutnya OOP. Masa bodo. Saya menantang Penggunaan 2 di mana sebagian besar orang tampaknya menggunakannya untuk pengujian dan pemeliharaan. Saya mengerti tetapi ini tidak menyelesaikan permintaan satu contoh saya. Semoga Container sepertinya menawarkan solusi. Kontainer… tidak hanya DI. Saya pikir saya perlu DI dengan fitur instance tunggal dan saya dapat menemukannya di wadah (perpustakaan pihak ke-3).
Bastien Vandamme

@ bastien-vandamme Jika Anda perlu menambahkan layanan baru maka Anda harus menambahkannya ke konstruktor, ini seharusnya tidak menjadi masalah. Jika Anda perlu menyuntikkan banyak layanan ini dapat menunjukkan masalah dengan arsitektur, bukan ide untuk menyuntikkan dependensi. Anda memastikan bahwa contoh yang sama digunakan kembali oleh pengembang lain dengan desain yang bagus dan melatih kolega Anda. Tetapi secara umum harus dimungkinkan untuk memiliki beberapa instance kelas. Sebagai contoh, saya mungkin memiliki beberapa contoh basis data dan memiliki layanan untuk masing-masingnya.
JonasH

Euh tidak. Saya memiliki database dengan 50 tabel, saya perlu 50 repositori, 50 layanan. Saya dapat bekerja dengan repositori generik tetapi database saya jauh dari normal dan bersih sehingga apapun repositori atau layanan saya pada suatu saat harus memiliki kode spesifik karena sejarah. Jadi saya tidak bisa melakukan semua generik. Setiap layanan memiliki aturan bisnis spesifik yang harus saya pertahankan secara terpisah.
Bastien Vandamme

2

Anda mengisolasi sistem eksternal.

Penggunaan 1: Tentu saja menggunakan DI jika Anda memiliki beberapa implementasi antarmuka Anda tampaknya logis. Anda memiliki repositori untuk SQL Server Anda kemudian yang lain untuk database Oracle Anda. Keduanya berbagi antarmuka yang sama dan Anda "menyuntikkan" (ini adalah istilah yang digunakan) yang Anda inginkan saat runtime. Ini bahkan bukan DI, ini adalah pemrograman OO dasar di sini.


Ya, gunakan DI sini. Jika masuk ke jaringan, basis data, sistem file, proses lain, input pengguna, dll. Anda ingin mengisolasinya.

Menggunakan DI akan memudahkan pengujian karena Anda akan dengan mudah mengejek sistem eksternal ini. Tidak, saya tidak mengatakan itu adalah langkah pertama menuju unit testing. Anda juga tidak dapat melakukan pengujian tanpa melakukan ini.

Lebih lanjut, bahkan jika Anda hanya memiliki satu database, menggunakan DI akan membantu Anda pada hari Anda ingin bermigrasi. Jadi, ya, DI.

Penggunaan 2: Ketika Anda memiliki lapisan bisnis dengan banyak layanan dengan semua metode spesifiknya, praktik terbaiknya adalah membuat antarmuka untuk setiap layanan dan juga menyuntikkan implementasinya walaupun ini unik. Karena ini lebih baik untuk pemeliharaan. Ini penggunaan kedua yang tidak saya mengerti.

Tentu, DI dapat membantu Anda. Saya akan berdebat tentang wadah.

Mungkin, sesuatu yang patut dicatat, adalah bahwa ketergantungan injeksi dengan jenis beton masih injeksi ketergantungan. Yang penting adalah Anda dapat membuat instance kustom. Itu tidak harus injeksi antarmuka (meskipun injeksi antarmuka lebih fleksibel, itu tidak berarti Anda harus menggunakannya di mana-mana).

Gagasan membuat antarmuka eksplisit untuk masing-masing dan setiap kelas harus mati. Bahkan, jika Anda hanya memiliki satu implementasi antarmuka ... YAGNI . Menambahkan antarmuka relatif murah, bisa dilakukan saat Anda membutuhkannya. Bahkan, saya sarankan menunggu sampai Anda memiliki dua atau tiga kandidat implementasi sehingga Anda memiliki gagasan yang lebih baik tentang hal-hal apa yang umum di antara mereka.

Namun, sisi lain dari itu, adalah Anda dapat membuat antarmuka yang cocok dengan yang dibutuhkan kode klien. Jika kode klien hanya membutuhkan beberapa anggota kelas, Anda dapat memiliki antarmuka hanya untuk itu. Itu akan menyebabkan pemisahan antarmuka yang lebih baik .


Wadah?

Anda tahu Anda tidak membutuhkannya.

Mari kita bawa ke trade-off. Ada kasus di mana mereka tidak layak. Anda akan meminta kelas Anda mengambil dependensi yang diperlukan pada konstruktor. Dan itu cukup bagus.

Saya benar-benar bukan penggemar atribut anotasi untuk "setter injection", apalagi yang pihak ketiga, saya mengerti mungkin diperlukan untuk implementasi di luar kendali Anda ... namun, jika Anda memutuskan untuk mengubah perpustakaan, ini harus diubah.

Akhirnya Anda akan mulai membangun rutinitas untuk membuat objek-objek ini, karena untuk membuatnya, pertama-tama Anda perlu membuat yang lain ini, dan bagi yang Anda perlukan lagi ...

Nah, ketika itu terjadi, Anda ingin meletakkan semua logika itu di satu tempat dan menggunakannya kembali. Anda ingin satu sumber kebenaran tentang bagaimana Anda membuat objek Anda. Dan Anda mendapatkannya dengan tidak mengulangi diri Anda sendiri . Itu akan menyederhanakan kode Anda. Masuk akal, bukan?

Nah, di mana Anda menempatkan logika itu? Insting pertama adalah memiliki Service Locator . Implementasi sederhana adalah singleton dengan kamus read-only dari pabrik . Implementasi yang lebih kompleks dapat menggunakan refleksi untuk membuat pabrik ketika Anda belum menyediakannya.

Namun, menggunakan pelacak tunggal atau statis akan berarti bahwa Anda akan melakukan sesuatu seperti var x = IoC.Resolve<?>setiap tempat Anda perlu membuat instance. Yaitu menambahkan kopling yang kuat ke pelacak lokasi Anda / wadah / injektor. Itu benar-benar dapat membuat unit test lebih sulit.

Anda menginginkan injektor yang Anda instantiate, dan simpan hanya untuk digunakan pada controller. Anda tidak ingin itu masuk jauh ke dalam kode. Itu sebenarnya bisa membuat pengujian lebih sulit. Jika beberapa bagian dari kode Anda memerlukannya untuk instantiate sesuatu, itu harus mengharapkan contoh (atau sebagian besar pabrik) pada konstruktornya.

Dan jika Anda memiliki banyak parameter pada konstruktor ... lihat apakah Anda memiliki parameter yang bepergian bersama. Kemungkinannya adalah Anda dapat menggabungkan parameter menjadi tipe deskriptor (tipe nilai idealnya).


Terima kasih atas penjelasan yang jelas ini. Jadi menurut Anda, saya harus membuat kelas injektor yang berisi daftar semua layanan saya. Saya tidak menyuntikkan layanan dengan layanan. Saya menyuntikkan kelas injektor saya. Kelas ini mengelola juga instance tunggal dari setiap layanan saya?
Bastien Vandamme

@BastienVandamme Anda dapat memasangkan Anda pengendali dengan injektor. Jadi, jika Anda bermaksud meneruskannya ke controller, maka saya setuju. Dan ya, dapat menangani memiliki satu contoh layanan. Di sisi lain, saya akan khawatir jika controller melewati injector ... dapat melewati pabrik jika diperlukan. Bahkan, idenya adalah memisahkan layanan dari inisialisasi dependensi mereka. Jadi, idealnya, layanan tidak menyadari injektor.
Theraot

"Menggunakan DI akan memudahkan pengujian karena Anda akan dengan mudah mengejek sistem eksternal ini." Saya telah menemukan bahwa mengandalkan mengejek sistem ini dalam pengujian unit tanpa terlebih dahulu meminimalkan kode yang memiliki koneksi ke mereka sangat mengurangi utilitas memiliki unit test. Pertama, maksimalkan jumlah kode yang dapat diuji melalui pengujian input / output saja. Kemudian lihat apakah mengejek itu perlu.
jpmc26

@ jpmc26 setuju. Tambahan: kita harus mengisolasi sistem eksternal itu.
Theraot

@BastienVandamme Saya telah memikirkan hal ini. Saya pikir jika Anda tidak kehilangan kemampuan untuk membuat untuk membuat injektor khusus untuk diedarkan, melakukannya harus baik-baik saja.
Theraot
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.