Bagaimana cara menggabungkan TDD dan DDD yang ketat?

15

TDD adalah tentang merancang kode, dipandu oleh tes.
Jadi, lapisan tipikal biasanya tidak dibangun di muka; mereka akan sedikit muncul melalui langkah-langkah refactoring.

Desain berbasis domain melibatkan banyak pola teknis, mendefinisikan lapisan mapan seperti lapisan Aplikasi, lapisan Infrastruktur, Lapisan Domain, lapisan Persistensi.

Untuk memulai bagian pengkodean proyek DDD dari awal, bagaimana caranya?
Haruskah saya dengan tegas membiarkan desain muncul dari pengujian, yang berarti tidak ada pemisahan kekhawatiran (tanpa lapisan) dan refactor agar sesuai dengan pola teknis DDD?

Atau haruskah saya membuat lapisan kosong itu (aplikasi, entitas / layanan domain, infrastruktur) dan membiarkan TDD cocok di masing-masing secara mandiri (menggunakan tiruan untuk mengisolasi antara lapisan)?

Mik378
sumber

Jawaban:

12

Pastikan Anda meninjau komentar terakhir Paman Bob tentang peran desain di TDD .

Desain berbasis domain melibatkan banyak pola teknis, mendefinisikan lapisan mapan seperti lapisan Aplikasi, lapisan Infrastruktur, Lapisan Domain, lapisan Persistensi.

Udi Dahan: "Ya Tuhan, betapa aku benci layering." Dia menghabiskan waktu mendiskusikannya dalam ceramahnya CQRS - tetapi berbeda (layering dimulai pada 18m30-an)

Saya akan mengeja kalimat Anda sedikit berbeda; "DDD mengakui bahwa ada sejumlah masalah yang umum pada sebagian besar aplikasi bisnis dan bahwa solusi untuk masalah tersebut memiliki masa hidup yang berbeda" .

Misalnya masalah domain, sebagai suatu peraturan, harus fleksibel - terutama ketika Anda menyesuaikan solusi untuk bisnis tertentu. Lagi pula, domain itu menyangkut bagaimana perusahaan melakukan bisnis, yaitu, bagaimana perusahaan menghasilkan uang dan mampu memberikan perbaikan bisnis dengan cepat adalah pendapatan gratis.

Di sisi lain, Anda mungkin tidak perlu sering mengganti komponen kegigihan. Solusi database yang berfungsi rilis terakhir mungkin juga akan bekerja rilis ini.

Kekhawatiran aplikasi ada di suatu tempat di tengah; mereka cenderung stabil sehingga pengguna tidak perlu mempelajari aplikasi baru dengan setiap rilis.

Juga, bisa ada beberapa implementasi untuk menyelesaikan masalah yang diberikan. Misalnya, aplikasi mungkin hanya memerlukan snapshot dari kondisi saat ini - cukup menyimpan file ke disk sudah cukup. Dan dalam beberapa iterasi pertama Anda, itu mungkin semua kebutuhan domain juga. Tetapi pada akhirnya muncul cerita yang meminta dukungan permintaan ad-hoc, dan Anda menyadari bahwa mengonfigurasi basis data relasional akan jauh lebih mudah daripada menerapkannya dari awal. Dan kemudian ada satu fitur ini yang akan bekerja lebih baik dalam basis data grafik.

Sementara itu, CTO menginginkan versi aplikasi yang berjalan di ponselnya; CEO baru saja mendengar dari seorang lelaki bahwa penerbitan API adalah hal besar.

Juga, tim penjualan menggunakan model yang berbeda, jadi beri kami aplikasi yang sama, dengan model yang berbeda. Oh, tapi kami sering bepergian, jadi versi kami perlu berfungsi saat offline dan disinkronkan nanti ...

Dengan kata lain, Anda menerapkan pola taktis dari bukan dengan menerapkan placeholder kosong dan dengan asumsi mereka akan diisi nanti, tetapi dengan mengenali ketika Anda sedang melintasi aliran "Hei, itu kode kegigihan dalam model domain saya, saya tidak boleh belum melakukan refactoring. "

VoiceOfUnreason
sumber
11

Test Driven Development (TDD) bukan desain. Ini adalah persyaratan yang memengaruhi desain Anda. Sama seperti jika Anda dituntut aman dari benang, itu bukan desain. Sekali lagi, ini adalah persyaratan yang memengaruhi desain Anda.

Jika Anda dengan gembira mengabaikan semua masalah desain lainnya dan tetap mematuhi aturan TDD jangan salahkan TDD ketika kode Anda berubah menjadi omong kosong. Ini akan menjadi omong kosong yang dapat diuji tetapi akan menjadi omong kosong.

Satu hal yang menyenangkan tentang omong kosong yang dapat diuji adalah bahwa itu omong kosong yang reaktif sehingga bagi sebagian orang itu cukup baik. Kami akan menjadi mewah hanya saat dibutuhkan. Yang lain membenci ini dan menyalahkan TDD untuk itu. Tidak. Ini ulahmu.

Domain Driven Design (DDD) adalah sesuatu yang Anda lakukan sebelum siklus refactor merah hijau TDD.

DDD adalah upaya untuk menciptakan dan melestarikan ruang dalam kode di mana seorang ahli domain, yang sebagian besar tidak menyadari detail sistem, dapat memahami bagaimana mengendalikan sistem. Ini dilakukan dengan abstraksi dan pemodelan domain masalah dengan cara yang akrab.

Sistem DDD dapat memiliki arsitektur yang terlihat seperti ini:

masukkan deskripsi gambar di sini

Arsitektur DDD ini memiliki banyak nama: Bersih , Bawang , Heksagonal , dll

Inilah yang saya lihat banyak orang miliki ketika mereka melihat desain ini. Ini tidak konkret. Saya dapat mengikuti desain ini dan tidak pernah menulis apa pun yang Anda lihat diagram di sini. Saya melihat orang lain bersikeras harus ada objek use case atau kelas entitas. Apa ini adalah seperangkat aturan yang memberi tahu Anda kepada siapa Anda bisa berbicara dan bagaimana caranya.

Itu dia. Ikuti aturan desain ini dan Anda dapat TDD hati kecil Anda keluar. TDD tidak peduli dengan siapa Anda berbicara. Itu peduli bahwa segala sesuatu yang melakukan sesuatu dapat terbukti berfungsi atau tidak dengan mengklik tombol. Tidak, sesuatu di suatu tempat rusak. Ini memberitahu Anda apa yang rusak.

Masih kabur? Lihatlah diagram Controler- Use Case Interactor- Presenterdi sudut kanan bawah. Berikut adalah tiga hal konkret yang saling berkomunikasi. Tentu ini DDD tetapi bagaimana Anda menambahkan TDD di sini? Hanya mengejek hal-hal konkret. Presenter harus menerima informasi. Sebuah PresenterMockkelas akan menjadi cara yang baik untuk memeriksa bahwa itu mendapatkan apa yang Anda harapkan untuk mendapatkan. Tangan yang Use Case Interactorsatu PresenterMockdan mendorong Use Case Interactorseolah-olah Anda adalah Controllerdan Anda memiliki cara yang bagus untuk menguji unit Use Case Interactorsejak mock akan memberitahu Anda jika mendapatkan apa yang Anda harapkan untuk mendapatkan.

Lihat itu. TDD puas dan kami tidak perlu menggunakan desain DDD kami. Bagaimana itu bisa terjadi? Kami mulai dengan desain yang dipisahkan dengan baik.

Jika Anda menggunakan TDD untuk mendorong desain (tidak hanya D PEMBANGUNAN) Anda mendapatkan desain yang mencerminkan upaya Anda masukkan ke dalamnya. Jika itu yang Anda inginkan baik-baik saja. Tapi itu tidak pernah dimaksudkan untuk TDD. Apa yang akhirnya kurang ini tentu bukan kesalahan TDD.

TDD bukan tentang desain. Jika Anda harus membuat perubahan desain untuk menggunakan TDD Anda memiliki masalah lebih besar daripada pengujian.

candied_orange
sumber
Saya tidak pernah mengatakan bahwa TDD adalah desain, tetapi ini tentang desain.
Mik378
1
Paman Bob menyuruhmu mendesain. Dia tidak memberitahumu "hei kalau kamu tes pekerjaan yang peduli tentang sisanya".
candied_orange
1
Seperti yang sudah saya katakan, ikuti saja aturan tentang siapa yang boleh Anda ajak bicara. Arsitektur yang bersih bukanlah sesuatu untuk diperdebatkan dengan BDUF. Identifikasi saja bagian mana Anda dan pikirkan tentang siapa dan bagaimana Anda harus berkomunikasi. Ini lebih gesit daripada yang mungkin Anda pikirkan. Setelah itu tanyakan apakah itu dapat diuji oleh TDD. Jika bukan Anda melakukan sesuatu yang salah. Jika itu saya harap Anda memperhatikan karena desain yang baik lebih dari sekadar dapat diuji.
candied_orange
6
Ugh ... Saya benar-benar tidak tahan dengan kesalahan "Test Driven Design". Anda masih harus mendesain sedikit sebelum mulai memukul keyboard Anda dengan senang hati, baik Anda menulis tes atau tidak.
RubberDuck
1
Mengutip Paman Bob pada titik yang tepat ini, "Anda harus mendesain periode" . Klik di sana dan jika Anda terlalu tidak sabar untuk membaca semuanya, cari kata-kata itu. Anda akan menemukan Tn. Martin sangat bersikeras bahwa TDD bukanlah peluru ajaib dan bahwa Anda harus merancang tidak hanya kode Anda tetapi juga tes Anda jika Anda tidak ingin hidup dalam basis kode yang sangat rapuh.
candied_orange
4

TDD memastikan kode Anda memiliki semua kasus uji yang diperlukan yang ditulis secara paralel dengan pengembangan. Ini seharusnya tidak mempengaruhi desain tingkat tinggi. Pikirkan lebih dalam pekerjaan parit.

DDD adalah tentang desain tingkat tinggi, bahasa antara pakar & insinyur domain, pemetaan konteks, dll. Ini harus menjadi pendorong aplikasi desain tingkat tinggi.

Ini adalah penjelasan dangkal dari dua metodologi pemrograman yang kuat. Tetapi pada akhirnya mereka benar-benar mencapai dua hal yang sangat berbeda.

Mulailah dengan pemetaan bahasa & konteks DDD kemudian pada akhirnya ketika Anda pergi untuk menulis kode, mulailah praktik TDD. Tetapi praktek TDD seharusnya tidak mempengaruhi desain tingkat tinggi, tetapi harus memastikan hal-hal dapat diuji. Ada sedikit peringatan di sini.

Saya pikir mungkin penting untuk diperhatikan: Anda hanya boleh berlatih DDD jika aplikasinya cukup kompleks.

Matt Oaxaca
sumber
1
Saya tidak setuju, TDD bukan tentang pengujian, ini tentang merancang.
Mik378
Saya mendasarkan semuanya pada 3 aturan TDD seperti yang dijelaskan oleh Paman Bob.
Matt Oaxaca
Steve Freeman, penulis buku GOOS menyatakan: Anda tidak harus menentukan lapisan atau infrastruktur apa pun sebelum memulai siklus TDD.
Mik378
Saya tidak terbiasa dengan buku itu, tetapi saya harus tidak setuju. Saya tidak ingin TDD membentuk grafik DI & kelas saya.
Matt Oaxaca
3
@ Mik378: TDD bukan tentang pengujian, tetapi juga bukan terutama tentang merancang - satu-satunya desain yang disebabkan oleh TDD adalah desain untuk unit-testability. Setiap bagian lain dari desain harus berasal dari tempat lain. Saya melihat TDD lebih sebagai teknik implementasi.
Doc Brown
3

DDD adalah tentang desain perangkat lunak.
TDD adalah tentang desain kode.

Dalam DDD, "model" mewakili abstraksi domain, semua pengetahuan dari pakar domain.

Kita dapat menggunakan TDD untuk model desain perangkat lunak awal kode. Domain memiliki aturan bisnis dan model domain yang tesnya tertulis (pertama) harus berwarna hijau.

Akibatnya, kita dapat mengkodekan tes, setelah merancang model berbasis domain.
Buku ini "Tumbuh Perangkat Lunak Berorientasi Objek, Dipandu oleh Tes" tautan-untuk-beli
Ambil pendekatan ini, dengan kerangka berjalan , arsitektur heksagonal , dan TDD.

Sumber dari: DDD cepat - InfoQ

JonyLoscal
sumber
1
baik bagi saya perangkat lunak dan kode adalah hal yang sama
Konrad
1
Itu bisa sama juga. Saya mencoba mengatakan: perangkat lunak sebagai "solusi", "sistem", "tingkat tinggi" dan kode sebagai "implementasi", "tingkat rendah", "perincian".
JonyLoscal
Saya pikir yang penting adalah bahwa "pertama kita menguji, tetapi kita membutuhkan kerangka minimal di mana kita akan mulai menguji". Apakah kamu?
JonyLoscal
1

Haruskah saya secara ketat membiarkan desain muncul dari tes

Tidak. (Didorong oleh Domain) Desain menurut definisi harus muncul dari persyaratan domain. Ini adalah ide yang buruk untuk membiarkan hal lain untuk mendorong desain Anda, apakah itu test suite, skema basis data atau ... (lanjutan)

Atau haruskah saya membuat lapisan kosong itu (aplikasi, entitas / layanan domain, infrastruktur) dan biarkan TDD cocok di masing-masing secara mandiri

(lanjutan) ... atau beberapa lapisan kanonikal kelas / hierarki kelas dalam bahasa pilihan OO favorit Anda, meskipun itu sangat matang dan populer (lagipula "jutaan lalat tidak mungkin salah", kan?) .

Ketika datang ke DDD, OOP gagal mengungkapkan persyaratan dalam bentuk yang dapat dibaca manusia yaitu sesuatu yang akan lebih atau kurang jelas bagi non-programmer. Bahasa FP yang diketik dengan ketat melakukan pekerjaan yang lebih baik. Saya merekomendasikan untuk membaca buku tentang DDD menggunakan pemrograman fungsional "Pemodelan Domain Fungsional" oleh Scott Wlaschin

https://pragprog.com/book/swdddf/domain-modeling-made-functional

Anda tidak harus menggunakan bahasa FP untuk meminjam beberapa ide dari sana (sayangnya tidak semuanya), tetapi jika Anda benar-benar membacanya maka Anda mungkin ingin menggunakan bahasa fungsional.

Ini juga akan menjawab pertanyaan Anda tentang bagaimana TDD cocok dalam gambar DDD. Singkatnya, ketika persyaratan dikodekan dalam gaya fungsional itu menghilangkan kebutuhan untuk sejumlah besar unit test karena membuat sebagian besar negara tidak valid dan skenario tidak terwakili / tidak mungkin untuk dikompilasi. Tentu saja, masih ada tempat untuk pengujian otomatis dalam proyek FP tetapi tes tidak berarti akan mendorong keputusan desain utama.

Untuk membuat lingkaran penuh, mari kita kembali ke pertanyaan judul yaitu "Bagaimana menggabungkan TDD dan DDD yang ketat?". Jawabannya sederhana: tidak ada yang bisa digabungkan / tidak ada konflik kepentingan. Desain sesuai dengan kebutuhan, kembangkan sesuai desain (dengan menulis tes terlebih dahulu jika Anda benar-benar ingin melakukan TDD)

Kola
sumber
+1 untuk buku FP DDD dan penjelasan keseluruhan.
Roman Susi