
Pendahuluan
Dalam artikel pertama, kami menyoroti ruang lingkup praktik yang ditunjukkan, untuk proyek mana mereka dapat diterapkan, dan untuk mana mereka tidak boleh.
Dalam artikel ini, saya ingin memberikan tinjauan singkat tentang prinsip-prinsip dasar DDD, serta berbagi pengalaman pribadi saya dengan aplikasi mereka. Kami akan berbicara lebih rinci tentang komunikasi dan pendekatan struktural dengan contoh-contoh implementasinya.
Dalam artikel berikut ini saya akan menuliskan kemungkinan kombinasi pola desain yang diterapkan dengan mempertimbangkan implementasinya, dan pada akhirnya saya akan memberikan contoh implementasi spesifik dari satu layanan mikro kecil.
DDD
Ingat definisi sebelumnya:
Domain-driven design (DDD) adalah pendekatan pengembangan perangkat lunak untuk kepuasan kebutuhan yang komprehensif, dengan secara ketat menghubungkan implementasi dengan model bisnis utama yang berada dalam pengembangan konstan.
Buku referensi yang menggambarkan praktik membangun sistem yang rumit adalah Eric Evans ' Domain Driven Dedign (Buku Biru Besar). Jika Anda membaca artikel ulasan tentang topik ini, Anda sudah mengetahuinya. Pada saat Anda menggunakan DDD dalam praktek, Anda harus membacanya. Ini bukan buku termudah untuk dibaca:
Sumber kanonik untuk DDD adalah buku Eric Evans. Ini bukan yang paling mudah dibaca dalam literatur perangkat lunak, tetapi itu adalah salah satu dari buku-buku yang cukup membayar investasi yang cukup besar.
Martin Fowler: 15 Januari 2014
Jika Anda menggulir isi buku, bagi Anda itu tampaknya tidak cukup terstruktur. Tapi peta itu akan membantu kita.

Di peta adalah praktik-praktik yang akan kita pertimbangkan hari ini.
Ruang lingkup praktik yang dicakup dalam buku ini sangat besar. Lingkup praktik yang dapat diterapkan di luar buku ini bahkan lebih besar. Sebelum Anda melayani setidaknya sebagian dari mereka, identifikasi tujuan Anda. Saya akan memberikan contoh saya sendiri.
- Tingkatkan produktivitas.
- Tulis kode yang dapat dipahami.
- Penskalaan pada tingkat pengembangan perangkat lunak.
Bahasa tunggal
Pengembangan perangkat lunak jarang mengarah pada penciptaan sesuatu yang baru, sebagai aturan, ini adalah simulasi dari sesuatu yang sudah ada.
Model adalah representasi dari objek nyata, yang hanya mencakup properti dan fungsi yang diperlukan.
Kami tidak dapat membuat produk perangkat lunak yang mencakup seluruh area subjek. Dimungkinkan untuk mereproduksi hanya bagian itu yang akan mereproduksi fungsionalitas yang diperlukan.
Contoh model yang baik adalah peta topografi. Dia adalah model medan. Peta tidak mengandung padang rumput bidang dan sungai, hanya mencerminkan lokasi objek nyata relatif satu sama lain.
Untuk membangun model yang jelas dan jelas untuk semua orang, Anda perlu berbicara bahasa yang sama. Tidak hanya Eric Evans yang memberi tahu kita hal ini, tetapi juga akal sehat. Jika pemrogram menggunakan istilah mereka, dan mengatur 'slang' mereka sendiri, maka yang pertama tidak akan mengerti apa yang perlu dilakukan. Bisnis dalam hal ini tidak akan dapat mewujudkan biaya nyata untuk mengembangkan satu atau "fitur" yang lain. Berapa kali Anda mendengar: "Ya, itu hanya sebuah tombol untuk ditambahkan"?
Tujuan Anda sebagai perancang sistem haruslah untuk mendapatkan pemahaman maksimal satu sama lain dari seluruh tim. Bagaimana cara mencapai ini? Mulailah berbicara. Jika orang-orang mulai berkomunikasi dalam kelompok dekat mana pun, mereka memiliki serangkaian istilah tertentu yang diterima secara umum. Di perusahaan yang berbeda, proses pengenalan bahasa yang sama cenderung berbeda. Ini bisa berupa keputusan yang berkemauan keras atau prosedur yang demokratis. Bahasa dapat diindikasikan secara eksplisit, dan itu tidak dimasukkan secara eksplisit, dalam hal ini mereka hanya mulai berbicara itu. Teknik yang baik untuk memperkenalkan bahasa umum adalah dokumentasi umum.
Bagaimana cara menyimpan dokumentasi proyek
- Setiap komunikasi antara bisnis dan pengembangan harus meningkatkan model Anda.
- Setelah pertemuan, catat hasilnya dalam bentuk dokumentasi (Scrum artifact), dan tunjukkan dokumentasi ini kepada semua peserta dalam proses pengembangan.
- Gunakan satu bahasa dalam dokumentasi.
- Paling penting: jangan buang waktu pada dokumentasi. Anda masih harus menulis kode, dan dokumentasinya akan ditulis ulang berkali-kali, menghabiskan sumber daya mahal. Daripada bermain-main dengan aplikasi charting UML untuk waktu yang lama, gunakan serbet, pena, dan kamera di ponsel Anda.
- Dokumentasi membutuhkan disiplin, Anda tidak dapat menulisnya dari waktu ke waktu.
- Pisahkan dokumentasi:
- Komentar dalam kode - jelaskan momen yang tidak dapat dipahami secara langsung dalam kode, biarkan
#ODO:
(hapus saat menggabungkan kode menjadi master). Ungkapkan pendapat Anda dalam komentar, misalnya, Anda harus menggunakan satu atau beberapa penopang lain saat bekerja dengan kode legasy. - Komentar pada proyek
README.md
di direktori root proyek Anda harus berisi informasi teknis: cara memulai proyek, cara menjalankan tes, dll. Ini juga merupakan ide bagus untuk mendapatkan peta tempat Anda memiliki semua proyek dan di server mana mereka menjalankannya. Catat semua perjanjian yang diterima secara terpisah. - Dan yang paling penting, basis pengetahuan. Kumpulan dokumen yang menjelaskan proses bisnis, ini adalah bagian dari dokumen yang tersedia untuk Anda dan bisnis.
- Kesalahan utama dari mereka yang menulis dokumentasi adalah redundansi. Jangan mencoba untuk menutupi segalanya dan segalanya, sampaikan hanya makna umum. Dokumentasi harus melengkapi proyek Anda, tetapi tidak menggantinya dengan cara apa pun. Jangan menuliskan semua istilah yang hanya ambigu. Jika sebuah definisi membutuhkan lebih dari dua kalimat, itu adalah definisi yang buruk.
Contoh dokumentasi:
# . # : : - - email - ## : ### , email , 1 ( email ). ### . email . ### email email . , email. . ### , , . . ### email, , . 2 . ### . , , .
Perhatikan bahwa dalam contoh ini kami tidak menentukan kamus eksplisit, namun kami memperbaiki konsep Pengguna , Otorisasi , Registrasi . Menulis dokumentasi semacam itu tidak akan membutuhkan waktu lebih dari 20 menit oleh pakar.
Bagi seseorang yang bukan ahli dalam bidang subjek, proses penulisan dokumentasi dianggap sebagai sesuatu yang rumit. Perlu untuk memisahkan koleksi pengetahuan dan catatan pengetahuan yang dikumpulkan. != + .
"Apa yang Anda sebut alam semesta," kata yang keempat, "sebenarnya, adalah akumulasi dari dunia yang, seperti kulit busur, berada di atas satu sama lain dan secara bertahap terpisah satu sama lain."
- Tidak jelas dinyatakan! - Mengagumi para abderites. - Sangat jelas! "Mereka pikir mereka mengerti filsuf itu, karena mereka tahu betul apa bawang itu."
Cerita Aberdeen, Cristov Martin Wieland
Konteks dan domain terbatas
Bayangkan kita bertindak sebagai perancang startup progresif. Kita semua suka pizza dingin, mengutuk kurir dan mengisi formulir di situs selama berjam-jam. Oleh karena itu, kami membuat startup yang luar biasa, βEmpat kura-kura dan satu tikusβ:
- Ada situs tempat pizza terdaftar dan memposting hidangan mereka yang sebenarnya.
- Pizza ini tidak memiliki layanan kurir sendiri.
- Ada pelanggan yang tidak dapat mencapai restoran pizza, tetapi mereka siap melakukan pemesanan melalui situs web atau aplikasi seluler.
- 'Fitur' pembunuh: kurir tidak khusus mempekerjakan orang, tetapi orang-orang biasa yang mendaftar melalui aplikasi mobile
- Kurir menerima pesanan, setelah eksekusi mereka menerima pembayaran untuk pekerjaan yang dilakukan.
- Butuh waktu lebih lama untuk menunggu kurir seperti itu, tetapi pengiriman, dan pizza yang sesuai, lebih murah.
Mari kita ingat kembali dokumentasi yang telah kita uraikan di bab sebelumnya. Di sana, dalam kamus tunggal kami, istilah pendaftaran digunakan . Tetapi dalam proyek ini kami memiliki beberapa di antaranya:
- Registrasi pelanggan
- Pendaftaran Pizzeria
- Registrasi Kurir
- Registrasi Pesanan
Bahasa terpadu milik konteks terbatas. Domain dari dokumentasi di atas adalah 'Sistem Otorisasi'. Mari kita coba mengalokasikan domain untuk startup kita.
Tetapi sebelum kita mulai, mari kita lihat sedikit terminologi tentang apa domain itu dan apa konteks yang terbatas itu.
Domain (Domain) - representasi dari struktur bisnis nyata yang memecahkan masalah tertentu.
Sebagai contoh: Sistem logistik, sistem pembayaran, sistem otorisasi, sistem manajemen pesanan.
Domain dibagi menjadi subdomain, yang menggambarkan struktur yang lebih kecil, misalnya: keranjang pesanan, sistem untuk membangun rute.
Setiap domain memiliki area tanggung jawab terbatas - fungsi terbatas.
Bounded context - satu set pembatasan domain yang membantu domain untuk fokus hanya pada satu tugas untuk solusi terbaiknya.
Saya suka menyajikan istilah ini sebagai abstraksi. Domain adalah lingkaran. Konteks terbatas adalah lingkaran.

Bahkan dalam terminologi DDD, kernel dialokasikan.
Inti (Core domain) - domain paling penting yang paling menjadi ciri bisnis Anda.
Jadi, domain dari proyek "Empat kura-kura dan satu tikus":
Bekerja dengan pizzeria (Pizzaria)
Konteks : b2b semuanya terkait dengan pizza
Subdomain :
- pendaftaran pizza baru
- menambahkan bermacam-macam
- memperbarui status ketersediaan suatu produk
Bekerja dengan klien (Klien)
Konteks : b2c, semua yang berhubungan dengan bekerja dengan pelanggan pizza
Subdomain :
- lihat bermacam-macam
- bahan informasi
Bekerja dengan kurir (Sistem pengiriman)
Konteks : b2e, semua yang berhubungan dengan bekerja dengan kurir
Subdomain :
- pendaftaran kurir
- penugasan tugas
- pendaftaran aplikasi untuk penarikan dana yang diperoleh kurir.
Sistem pemesanan
Konteks : Kernel. Memungkinkan Anda mengoordinasikan semua domain individu, memberikan siklus lengkap mulai dari menerima pesanan hingga pengiriman pizza kepada pengguna. Ini bukan pemain, tetapi memainkan peran sebagai konduktor.
Subdomain :
- penerimaan pesanan
- eksekusi pesanan
- pelacakan status pesanan
Sistem Penyelesaian (Tagihan)
Konteks : Berisi semua transaksi keuangan. Ini menyediakan interaksi dengan pusat pemrosesan.
Subdomain :
- menerima uang untuk pesanan
- memberikan uang kepada kurir untuk pekerjaan yang dilakukan
Sistem Statistik
Konteks : Pengumpulan dan pemrosesan (tidak mengeluarkan) informasi analitik.
Subdomain :
- statistik dana
- statistik aplikasi
Sistem Manajemen (panel Manajemen)
Konteks : Penerbitan informasi analitis. Toolkit keputusan manajemen.
- analisis berdasarkan statistik yang dikumpulkan
- pra-moderasi pembayaran ke kurir
Berdasarkan pada domain, mari memetakannya.
Peta domain (Context map) adalah alat grafis yang memungkinkan Anda untuk menggambarkan hubungan antara masing-masing domain.

Peta menunjukkan tautan antar domain. Peta ini sangat dangkal, tetapi area subjek tidak dipahami dengan baik. Ini adalah sketsa pertama, penulisan ulang yang Anda akan mendapatkan hasil yang diharapkan.
Yang paling penting di peta adalah kita melihat koneksi antar domain. Struktur seperti itu sangat cocok dengan arsitektur microservice:
Prinsip utama arsitektur layanan-mikro: konektivitas lemah dan daya rekat kuat.
Prinsip ini diberikan dalam buku oleh Sam Newman - Creating Microservices , ini adalah buku kedua yang harus Anda baca untuk memulai penggunaan praktis dari pendekatan yang dijelaskan dalam artikel ini. Apa yang dimaksud: domain harus digabungkan secara longgar, tetapi terkait erat secara internal.
Terjemahan dari istilah-istilah ini diambil dari terjemahan resmi Rusia dan, mungkin, kurang mencerminkan makna yang ditransmisikan. Dalam istilah aslinya adalah: Kopling rendah (konektivitas, keterlibatan, pegangan, konjugasi), kohesi tinggi (konektivitas, kekuatan).
Praktek Implementasi Berbagi Domain
Saya ingin berbagi pengalaman pribadi saya - satu set keputusan berdasarkan informasi. Saya tidak menganjurkan Anda untuk menggunakan solusi ini. Tetapi mereka mungkin merupakan pilihan yang baik jika Anda tidak tahu harus mulai dari mana. Dengan pengalaman pribadi, alat-alat ini akan lebih disesuaikan dengan kebutuhan Anda.
Prinsip-prinsip utama yang memandu kami:
- Kesederhanaan solusinya. Jadikan hal-hal rumit menjadi sederhana, tidak sesederhana itu.
- Pragmatisme Anda selalu perlu melihat situasinya, dan tanpa adanya solusi yang ada, kembangkan yang baru. Cobalah untuk menuliskan semuanya, tetapi hindari dogmatisme.
- Kode! = Dokumentasi. Kode adalah instruksi untuk mesin, dokumentasi adalah instruksi untuk orang. Tidak perlu membingungkan mereka dan memberikan satu demi satu.
- PADAT
Bagaimana cara mengimplementasikan domain?
Sangat mudah untuk memilih domain sebagai layanan microser terpisah.
Microservices adalah aplikasi terpisah yang mengimplementasikan logika satu domain.
Dalam pengembangan DDD, prinsip mengalokasikan layanan-mikro ke dalam aplikasi terpisah akan dibatasi konteksnya. Ini tidak meniadakan prinsip teknis pemisahan layanan (jika ini karena kebutuhan untuk memastikan kinerja tinggi). Tetapi prinsip kontekstual akan dominan dan mengikat.
Bagaimana cara menyoroti hubungan antar domain?
Hubungan antar domain selalu merupakan API. Bisa jadi TETAP api json, gRPC, AMPQ. Dalam kerangka artikel ini, kami tidak akan membandingkan satu protokol dengan yang lain dan menyoroti kelebihan dan kekurangan mereka, masing-masing memiliki bidang aplikasi sendiri. Tapi tetap saja, mari kita memikirkan rekomendasi umum:
Jadilah fleksibel dalam memilih protokol dan kaku dalam keseragaman implementasinya.
Pilih protokol untuk setiap pasangan domain secara individual, jangan mencoba menggunakan http di mana-mana, Anda mungkin perlu antrian yang tidak sinkron di suatu tempat dan keuntungan AMPQ akan menjadi jelas bagi Anda. Jangan abaikan peluang ini karena Anda TETAP di mana-mana.
Di sisi lain, jika Anda menerapkan RESTful json, gunakan satu standar penataan data. Anda dapat bersiap-siap misalnya jsonapi atau openapi. Jika karena alasan tertentu, solusi siap pakai tidak cocok untuk Anda dan Anda merasa dapat mengembangkan standar Anda, jelaskan, dan gunakan. Tapi gunakan di mana-mana, jangan membiakkan standar "kebun binatang". Jika Anda perlu berkomunikasi dengan sistem eksternal di mana mereka tidak tahu apa-apa tentang standar Anda, tulis adaptor layanan-mikro.

Bagaimana cara mengimplementasikan subdomain?
Sebagai modul terpisah di dalam layanan mikro.
Modul adalah implementasi dari subdomain, dengan menempatkan logika ke dalam namespace yang terpisah (Namespace) dalam satu layanan microser.
Seperti apa bentuknya? Mari kita lihat sebuah contoh. Seingat kami, kami memiliki domain sistem pengiriman - domain ini memiliki tiga subdomain:
- pendaftaran kurir
- masalah tugas (tugas)
- pendaftaran aplikasi untuk penarikan dana yang diperoleh oleh kurir (penarikan)
- memeriksa apakah layanan mikro Anda berfungsi, alat bantu, teknis (healt_checker)
Bayangkan ini semua dalam bentuk struktur folder:
$ tree --dirsfirst delivery_system delivery_system βββ app/ β βββ health_checker/ β β βββ endpoints.rb β βββ registrations/ β β βββ entities/ β β βββ forms/ β β βββ repositories/ β β βββ interactor/ β β βββ services/ β β βββ validations/ β β βββ endpoints.rb β β βββ helpers.rb β βββ tasks β β βββ entities/ β β βββ queries/ β β βββ repositories/ β β βββ endpoints.rb β β βββ helpers.rb β βββ withdrawals β βββ entities/ β βββ forms/ β βββ repositories/ β βββ interactor/ β βββ services/ β βββ validations/ β βββ endpoints.rb β βββ helpers.rb βββ config/ βββ db/ βββ docs/ βββ lib/ β βββ schemas/ β βββ values/ βββ public βββ specs βββ config.ru βββ Gemfile βββ Gemfile.lock βββ Rakefile βββ README.md
Setiap folder di apps/
direktori mengimplementasikan satu atau subdomain lainnya, dalam setiap domain terdapat berbagai pola: entities
, forms
, services
, dll. Kami akan mempertimbangkan masing-masing pola yang diterapkan secara terperinci di salah satu artikel mendatang.
Setiap pola tersebut diimplementasikan dalam namespace yang sesuai (Namespace). Misalnya, formulir untuk membuat aplikasi pembayaran ke kurir:
module Withdrawal
Bagaimana cara menerapkan komunikasi antar subdomain?
Mari kita lihat contoh spesifik. Kami memiliki akun kurir: Registrations::Entities::Account
. Ini merujuk ke subdomain Registrations
- karena kami menganggap domain ini bukan sebagai proses pendaftaran, melainkan sebagai tabel akun dan buku pendaftaran, seperti yang ditunjukkan dalam dokumentasi bisnis kami.
Kami memiliki dua Proses yang dalam pelaksanaannya kami mengakses akun ini.
- Buat akun (Pendaftaran)
- Pembuatan aplikasi untuk penarikan dana yang diperoleh oleh kurir (Wihtdrawal)
Seperti yang kita lihat, dua proses ini milik subdomain yang berbeda - Registrasi dan Wihtdrawal.
module Registrations module Serivices class CreateAccount def call account = Entities::Account.new end end end end module Withdrwals module Serivices class CreateOrder def call account = Registrations::Entities::Account.new end end end end
Dalam kasus pertama, panggilan ke kelas akan dilaksanakan melalui panggilan ke Entities::Account
. Dan dalam kasus kedua, melalui panggilan eksplisit ke Registrations::Entities::Account
. Yaitu jika kita secara eksplisit menentukan subdomain, maka kelasnya berasal dari subdomain lain dan oleh karena itu kami jelas menunjukkan hubungannya.
Jika kelas tidak secara eksplisit diterapkan ke salah satu subdomain, masuk akal untuk memindahkannya ke lib/
folder. Sebagai aturan, ini adalah kelas yang menerapkan pola 'ValueObject'. Kami akan memeriksa pola ini secara lebih rinci di salah satu artikel berikut.
Implementasi melalui model.
Mengutip Eric Evans:
Jika arsitektur program, atau setidaknya beberapa bagian pusatnya, tidak sesuai dengan struktur model domain, maka model seperti itu praktis tidak berguna, dan operasi program yang benar juga harus dipertanyakan. Pada saat yang sama, hubungan yang terlalu kompleks antara model dan fungsi dalam arsitektur perangkat lunak sulit untuk dipahami, dan dalam praktiknya mereka sulit untuk dipertahankan karena perubahan arsitektur.
Mari kita ingat contoh model yang baik yang sudah saya kutip di awal artikel ini - peta topografi. Tujuan kami adalah untuk dapat dengan cepat menemukan jarak antara dua pemukiman. Kita bisa menggunakan tabel referensi yang menunjukkan dua titik antar kota. Dan kita bisa menggunakan kartunya. Baik di sana maupun di sana kita mendapatkan hasil yang sama dalam waktu yang hampir bersamaan. Tetapi peta lebih kompak, lebih akurat menampilkan area subjek, lebih universal. Peta sebagai model sangat ekspresif. Dan jika kita mempertimbangkannya dalam kerangka tugas ini, maka mengukur jarak lebih nyaman di peta daripada di wilayah itu sendiri, yang dicerminkannya. Model yang mencerminkan area subjek dapat melampaui itu di beberapa properti. Sungguh menakjubkan.
Implementasi model selalu merupakan proses kreatif dengan hasil yang tidak terduga. Kualitas kode Anda bukan kinerjanya, atau kompleksitasnya, melainkan kesederhanaan dan ekspresif. Tingkatkan itu melalui refactoring yang konstan, buatlah fleksibel dan potong semua yang tidak perlu. Pisahkan lapisan yang akan bertanggung jawab atas logika bisnis model dari lapisan yang membutuhkannya karena implementasi teknis. Bagaimana kami berhasil melakukan ini akan dijelaskan nanti.