Buku Masakan Pengembang: Resep DDD (Bagian 3, Arsitektur Aplikasi)

Pendahuluan


Dalam artikel sebelumnya, kami mengidentifikasi ruang lingkup pendekatan dan memeriksa prinsip-prinsip metodologis dasar Desain Domain Driven .


Dalam artikel ini, saya ingin menguraikan pendekatan modern utama untuk membangun arsitektur sistem perusahaan: Lentur, Menjerit, Bersih dan memberi mereka interpretasi saya yang jelas dalam bentuk solusi turnkey lengkap.


WM


Di masa mendatang, kami akan mempertimbangkan setiap pola desain secara terperinci: kami menunjukkan cakupan, memberikan contoh kode, menyoroti praktik yang direkomendasikan. Sebagai hasilnya, kami akan menulis microservice yang sudah jadi.


Arsitektur yang fleksibel


Dalam artikel terakhir, kami fokus pada fakta bahwa DDD mencakup praktik implementasi melalui model. Area subjek harus dijelaskan melalui kode Anda. Mari kita coba mencari tahu bagaimana melakukan ini.


Dalam bukunya, Eric Evans memberikan serangkaian pola desain yang direkomendasikan dan menunjuk pendekatan ini sebagai fleksibel:


Atas nama fleksibilitas arsitektur, banyak konstruksi yang tidak perlu ditumpuk dalam program. Tingkat abstraksi yang berlebihan dan hubungan tidak langsung lebih cenderung mengganggu daripada membantu dalam hal ini. Lihatlah arsitektur yang benar-benar menginspirasi programmer untuk memperbaikinya, dan Anda biasanya akan melihat sesuatu yang sangat sederhana. Namun sederhana bukan berarti mudah dijalankan. Untuk menciptakan elemen-elemen seperti itu yang dapat dirangkai menjadi sistem yang kompleks dan pada saat yang sama mudah dipahami, perlu untuk menggabungkan "dedikasi" untuk merancang sesuai model dengan gaya arsitektur yang cukup ketat. Keterampilan desain tertentu diperlukan tidak hanya untuk membuat sesuatu, tetapi bahkan untuk menggunakan yang sudah jadi.

Eric Evans, Desain Berbasis Domain: Mengatasi Kompleksitas di Jantung Perangkat Lunak

Rangkaian pola desain yang disajikan bukan arsitektur yang ketat atau solusi siap pakai, melainkan makanan yang dipikirkan.


Arsitektur yang mencolok


Pikiran serupa muncul di benak banyak pengembang dan perancang sistem yang kompleks.


Pada tahun 2011, sebuah artikel oleh Robert Martin - Screaming Architecture diterbitkan, yang mengatakan bahwa kode Anda tidak harus hanya menggambarkan area subjek, tetapi berteriak tentang hal itu, lebih baik tidak sopan.


Jadi apa yang berteriak dari arsitektur aplikasi Anda? Ketika Anda melihat struktur direktori tingkat atas, dan file sumber dalam paket tingkat tertinggi; apakah mereka berteriak: Sistem Perawatan Kesehatan, atau Sistem Akuntansi, atau Sistem Manajemen Inventaris? Atau apakah mereka berteriak: Rails, atau Spring / Hibernate, atau ASP?

Robert C. Martin, 30 September 2011

Robert mengatakan bahwa kode aplikasi Anda harus mencerminkan aktivitas aplikasi, alih-alih beradaptasi dengan aturan kerangka kerja. Struktur kerangka kerja seharusnya tidak membatasi arsitektur Anda. Aplikasi, pada gilirannya, tidak boleh dilampirkan ke database atau protokol http, ini hanya mekanisme penyimpanan dan pengiriman. Kotak pembatas adalah alat. Anda seharusnya tidak menjadi penganut kerangka kerja tersebut. Tes aplikasi Anda adalah tes logika operasinya, dan tidak menguji protokol http.


Arsitektur bersih


Setahun kemudian, artikel berikutnya oleh Robert Martin - Arsitektur Bersih . Di dalamnya, penulis memberi tahu cara membuat kode menjerit. Setelah mempelajari beberapa arsitektur, ia mengidentifikasi prinsip-prinsip dasar:


  1. Bingkai Kemerdekaan. Arsitekturnya tidak tergantung pada perpustakaan yang ada. Ini memungkinkan Anda untuk menggunakan kerangka kerja sebagai alat, alih-alih kendala yang mengikat tangan Anda.
  2. Testabilitas. Aturan bisnis dapat diuji tanpa antarmuka pengguna, basis data, server web atau cara teknis lainnya.
  3. Independensi UI. Antarmuka pengguna dapat dengan mudah diubah tanpa mengubah sisa sistem. Misalnya, antarmuka web dapat diganti dengan antarmuka konsol tanpa mengubah logika bisnis.
  4. Independensi basis data. Anda dapat menukar Oracle atau SQL Server dengan Mongo, BigTable, CouchDB atau yang lainnya. Logika aplikasi Anda tidak boleh terikat database.
  5. Bebas dari pengaruh lingkungan. Bahkan, aturan bisnis Anda tidak tahu apa-apa tentang dunia luar.

Pada habr sudah menerbitkan artikel yang sangat bagus Kesalahpahaman Arsitektur Bersih . Penulisnya, Jeevuz sangat mengunyah seluk-beluk memahami pendekatan ini. Saya sangat menyarankan agar Anda membiasakan diri dengan bahan dan materi aslinya.


Arsitektur Variabel


Deskripsi pendekatan di atas tidak terlihat begitu jelas. Sebagai bagian dari pengembangan arsitektur sejumlah sistem perusahaan yang kompleks, saya dan kolega saya telah mengembangkan interpretasi yang cukup jelas tentang pendekatan yang diuraikan, yang ingin saya sampaikan di bawah ini.


Sebelum munculnya komputer dan bahasa pemrograman, alur kerja kertas digunakan untuk membangun dan mengelola sistem dengan logika bisnis yang kompleks. Hasil dari setiap proses adalah dokumen yang pada akhirnya menggambarkan objek bisnis tertentu. Akibatnya, dokumen menjadi tiga Tindakan sederhana:


  1. Pembuatan dokumen
  2. Pemrosesan dokumen
  3. Bekerja dengan arsip dokumen
  4. Pengiriman dokumen

Dokumen - merekam informasi tentang kegiatan ekonomi dari objek bisnis nyata tertentu.

Harap dicatat bahwa dokumen itu sendiri bukan objek bisnis nyata, tetapi hanya Modelnya . Saat ini, dokumen kertas sedang diganti dengan yang elektronik. Suatu dokumen dapat berupa catatan dalam sebuah tabel, gambar, file, surat yang dikirim atau informasi lain apa pun.
Saya tidak ingin menggunakan kata dokumen di masa depan, karena akan lebih membingungkan, kita akan menggunakan konsep Entity dari terminologi DDD. Tetapi Anda dapat membayangkan bahwa sekarang seluruh sistem Anda adalah sistem manajemen dokumen elektronik yang melakukan empat Tindakan sederhana.


  1. Mengumpulkan
  2. Pengolahan
  3. Penyimpanan
  4. Representasi

Aksi - unit struktural aktivitas model bisnis; tindakan terpisah yang relatif lengkap dari tujuan sadar, kesewenang-wenangan dan kesengajaan dari aktivitas individu dari objek bisnis, dibedakan oleh pengguna akhir.

Contoh yang baik dari Aksi adalah aksi teater. Teater memodelkan peristiwa dari kehidupan nyata. Tindakan itu adalah bagian yang berarti dari drama itu. Tetapi, untuk membuat cerita lengkap, Anda perlu memainkan beberapa aksi dalam urutan yang ditentukan secara ketat. Perintah seperti itu dalam arsitektur kita akan kita sebut Mode .


Mode (Konduksi) - serangkaian Tindakan dalam urutan tertentu, memiliki makna lengkap, bermanfaat bagi pengguna akhir.

konduksi


Untuk Mode Operasi semacam itu, konduktor atau Pemilih selektif ditemukan. Lebih tepatnya, "Mekanisme pengaturan waktu untuk melakukan yang dipilih dari sejumlah urutan operasi", yang diperoleh paten US2870278A . Kita tahu perangkat ini sebagai "putaran" dari mesin cuci. Sentuhan arsitektur diberikan pada awal artikel.


Keragaman pendekatan dimanifestasikan dalam kenyataan bahwa dengan arsitektur ini Anda dapat memilih salah satu dari empat Mode , yang lewat yang Anda tidak akan melakukan Tindakan yang tidak perlu.


Saat memulai mesin cuci, Anda dapat memilih mode: mencuci, membilas, atau memutar. Jika Anda memilih untuk mencuci, mesin Anda masih akan membilas cucian, lalu memerasnya. Dengan bilas di kit Anda yakin akan mendapatkan putaran. Putar - tindakan terakhir dalam proses pencucian, ini adalah yang paling "sederhana". Dalam arsitektur kami, Tindakan paling sederhana adalah Representasi , dan kami akan mulai dengannya.


Representasi


Jika kita berbicara tentang presentasi murni tanpa menggunakan database atau sumber eksternal, maka kita memberikan beberapa informasi statis: halaman html, file, direktori yang terletak dalam bentuk json. Kami bahkan dapat memberikan respons Kode saja - 200:


Mari kita menulis "pemeriksa kesehatan" yang paling sederhana


module Health class Endpoints < Sinatra::Base get '/check' do; end end end 

Dalam bentuknya yang paling primitif, skema kami akan terlihat seperti ini:


Representasi


Penyimpangan liris

Saya meminta Anda untuk mencatat bahwa dalam kerangka kerja Sinatra, kelas Endpoints menggabungkan Router dan Controller dalam satu kelas. Apakah ini melanggar prinsip tanggung jawab tunggal? Sebenarnya, Endpoint bukan kelas, tetapi lapisan yang diekspresikan melalui kelas, dan area tanggung jawabnya di tingkat yang lebih tinggi.


Ok, bagaimana dengan Router dan Controller ? Mereka diwakili bukan oleh satu set kelas, tetapi dengan nama dan implementasi suatu fungsi. File statis umumnya adalah file. Satu kelas bertanggung jawab atas satu tanggung jawab, tetapi jangan mencoba untuk mengekspresikan setiap tanggung jawab melalui kelas. Gunakan kepraktisan, bukan dogmatisme.


Bekerja dengan sistem penyimpanan


Bisnis menuntut ketersediaan aplikasi Anda. Mengapa ada orang yang membutuhkan layanan Anda jika kami tidak dapat menggunakannya pada waktu yang tepat? Untuk memastikan integritas data, kami mencatat perubahan dalam status objek bisnis setelah setiap pemrosesan.


Untuk mengambil objek dari penyimpanan tidak memerlukan akses ke logika bisnis. Bayangkan bahwa kita mengotomatiskan kegiatan jaringan hotel dan kita memiliki majalah tamu di resepsi. Kami memutuskan untuk melihat informasi tentang pengunjung.


  module Reception class Endpoints < Sinatra::Base # Show item get '/residents/:id', provides: :json do resident = Repository::Residents.find params[:id] status 200 serialize(resident) end end end 

Bekerja dengan sistem penyimpanan dalam bentuk diagram grafik:


Penyimpanan


Seperti yang dapat kita lihat, komunikasi antara lapisan yang bertanggung jawab untuk menyimpan dan lapisan yang bertanggung jawab untuk menyajikan data diimplementasikan melalui model Respon. Model ini bukan milik salah satu lapisan ini. Sebenarnya, ini adalah objek bisnis dan terletak di lapisan yang bertanggung jawab atas logika bisnis.


Pengolahan


Jika sampai pada kenyataan bahwa model objek berubah berdasarkan propertinya tanpa memasukkan data baru, maka kita beralih ke lapisan Interactor secara langsung. Lapisan Interactor adalah kunci dalam aplikasi kita, itu menggambarkan seluruh logika bisnis dalam bentuk Use Use terpisah, dan di atasnya perubahan Entitas .


Pertimbangkan kasus penggunaan ini. Pengunjung sudah terdaftar di hotel kami, tetapi kami merayakan setiap kedatangan atau keberangkatannya.


  module Reception class Endpoints < Sinatra::Base # Register resident arrival post '/residents/:uid/arrival', provides: :json do result = Interactors::Arrival.call(resident_id: params[:id]) check!(result) do status 201 serialize result.data end end # Register resident departure post '/residents/:uid/departure', provides: :json do result = Interactors::Departure.call(resident_id: params[:id]) check!(result) do status 201 serialize result.data end end end end 

Mari kita berhenti sebentar. Mengapa tidak menjadikan implementasi metode tunggal dengan parameter status ? Para interaktator Arrival dan Departure pada dasarnya berbeda. Jika seorang tamu datang kepada kami, maka kami harus memeriksa apakah pembersihan sudah selesai, apakah ada pesan baru untuknya, dll. Dengan kepergiannya, kita, sebaliknya, harus melakukan pembersihan jika perlu. Pada gilirannya, kami bahkan tidak ingat tentang pesan-pesan itu, karena jika dia berada di sebuah hotel, kami akan segera memanggilnya. Ini semua logika bisnis yang kami resepkan pada lapisan Interactor .


Pengolahan


Tetapi apa yang harus kita lakukan jika kita memiliki data dari luar? Di sini aksi Pengumpulan Data terhubung.


Mengumpulkan data


Selama pendaftaran awal tamu di hotel, ia mengisi formulir pendaftaran. Formulir ini sedang diverifikasi. Jika datanya benar, maka proses pendaftaran bisnis berlangsung. Proses mengembalikan data - model bisnis "penyewa" yang dibuat. Kami menyajikan model ini kepada tamu dalam bentuk yang dapat dibaca:


 module Reception class Endpoints < Sinatra::Base # Register new resident post '/residents', provides: [:json] do form = Forms::Registration.new(params) complete! form do check! form.result do status 201 serialize form.result.data end end end end end 

Secara skematis, tampilannya seperti ini:


Mengumpulkan


Aturan main (Aturan)


  • Sistem variatif dari sudut pandang proses dibagi menjadi Tindakan .
  • Urutan Tindakan ditentukan oleh Mode .
  • Mode bersifat inkremental.
  • Mode yang lebih "kompleks" melengkapi yang lebih "sederhana" untuk satu tindakan.
  • Setiap aksi berlangsung dalam kerangka satu Layer .
  • Setiap lapisan diwakili oleh Kelas .
  • Di dalam lapisan, mungkin ada Kelas Lapisan dan Kelas Tanggung Jawab .
  • Komunikasi hanya terjadi antara Layer dan Kelas Interlayer .
  • Model representasi adalah pengecualian.
  • Penanganan kesalahan harus dilakukan di level Class-Layer .

Pohon


Skema umum


Pendekatan ini memiliki ambang masuk yang tinggi. Penerapannya membutuhkan banyak pengalaman dari perancang untuk pemahaman yang jelas tentang tugas yang harus diselesaikan. Kompleksitas juga mewakili beragam pilihan alat yang dibutuhkan. Tetapi, terlepas dari kompleksitas strukturnya, implementasi pada level kode sangat sederhana dan ekspresif. Meski mengandung sejumlah konvensi dan surat kuasa. Di masa mendatang, kami akan menganalisis setiap templat desain secara terpisah, menjelaskan cara membuatnya, mengujinya, dan menentukan cakupannya. Dan agar tidak bingung dalam keanekaragamannya, ditawarkan peta lengkap:


Peta Resolusi Tinggi




Source: https://habr.com/ru/post/id429750/


All Articles