Pendahuluan
Dalam artikel sebelumnya, kami menjelaskan: ruang lingkup , fondasi metodologis , contoh arsitektur dan struktur . Dalam artikel ini, saya ingin memberi tahu cara menggambarkan proses, tentang prinsip-prinsip persyaratan pengumpulan, bagaimana persyaratan bisnis berbeda dari yang fungsional, bagaimana cara beralih dari persyaratan ke kode. Bicarakan tentang prinsip-prinsip menggunakan Case Use dan bagaimana mereka dapat membantu kami. Jelajahi contoh opsi implementasi untuk pola desain Interactor dan Layer Layanan.

Contoh-contoh yang diberikan dalam artikel diberikan menggunakan solusi LunaPark kami, ini akan membantu Anda dengan langkah-langkah pertama dalam pendekatan yang dijelaskan.
Pisahkan persyaratan fungsional dari persyaratan bisnis.
Berkali-kali, banyak ide bisnis yang tidak benar-benar berubah menjadi produk akhir yang diinginkan. Hal ini sering disebabkan oleh ketidakmampuan untuk memahami perbedaan antara persyaratan bisnis dan persyaratan fungsional, yang pada akhirnya menyebabkan pengumpulan persyaratan yang tidak memadai, dokumentasi yang tidak perlu, penundaan proyek dan kegagalan proyek besar.
Atau kadang-kadang kita dihadapkan pada situasi di mana, meskipun solusi akhir memenuhi kebutuhan pelanggan, tetapi entah bagaimana tujuan bisnis tidak tercapai.
Oleh karena itu, sangat penting untuk memisahkan persyaratan bisnis dari persyaratan fungsional hingga Anda mulai mendefinisikannya. Mari kita ambil contoh.
Misalkan kita sedang menulis aplikasi untuk perusahaan pengiriman pizza, dan kami memutuskan untuk membuat sistem pelacakan kurir. Persyaratan bisnis adalah sebagai berikut:
"Memperkenalkan sistem berbasis web dan sistem pelacakan karyawan berbasis karyawan yang menangkap kurir pada rute mereka dan meningkatkan efisiensi dengan memantau aktivitas kurir, ketidakhadiran mereka dari pekerjaan dan produktivitas tenaga kerja."
Di sini kita dapat membedakan sejumlah fitur karakteristik yang akan menunjukkan bahwa ini adalah persyaratan dari bisnis:
- persyaratan bisnis selalu ditulis dari sudut pandang klien;
- Ini adalah persyaratan luas, tingkat tinggi, tetapi masih berorientasi sebagian;
- mereka bukan tujuan perusahaan, tetapi membantu perusahaan mencapai tujuan;
- jawab pertanyaan " mengapa " dan " apa ". Apa yang ingin diterima perusahaan? Dan mengapa dia membutuhkannya.
Persyaratan fungsional adalah Tindakan yang harus dilakukan sistem untuk melaksanakan persyaratan bisnis. Dengan demikian, persyaratan fungsional terkait dengan solusi atau perangkat lunak yang dikembangkan. Kami merumuskan persyaratan fungsional untuk contoh di atas:
- sistem harus menampilkan garis bujur dan garis lintang karyawan melalui GPS / GLONASS;
- sistem harus menampilkan posisi karyawan di peta;
- sistem harus memungkinkan manajer untuk mengirim pemberitahuan kepada bawahannya.
Kami menyoroti fitur-fitur berikut:
- persyaratan fungsional selalu ditulis dari sudut pandang sistem;
- mereka lebih spesifik dan terperinci;
- itu berkat pemenuhan persyaratan fungsional yang dikembangkan solusi efektif yang memenuhi kebutuhan bisnis dan tujuan klien;
- jawab pertanyaan " bagaimana ." Bagaimana sistem memecahkan persyaratan bisnis.
Beberapa kata harus dikatakan tentang persyaratan non-fungsional (juga dikenal sebagai "persyaratan kualitas") yang memberlakukan pembatasan pada desain atau implementasi (misalnya, persyaratan untuk kinerja, keamanan, ketersediaan, keandalan). Persyaratan seperti itu menjawab pertanyaan " apa yang harus" menjadi sistem.
Pengembangan adalah terjemahan persyaratan bisnis menjadi fungsional. Pemrograman terapan adalah implementasi persyaratan fungsional, dan sistem - non-fungsional.
Gunakan kasing
Menerapkan persyaratan fungsional seringkali merupakan yang paling kompleks dalam sistem komersial. Dalam arsitektur murni, persyaratan fungsional diimplementasikan melalui lapisan Use Case .
Tapi sebagai permulaan, saya ingin beralih ke sumbernya. Ivar Jacobson - penulis definisi Use Case , salah satu penulis UML, dan metodologi RUP, dalam artikelnya Use-Case 2.0 Hub Pengembangan Perangkat Lunak mengidentifikasi 6 prinsip untuk menggunakan kasus-kasus Penggunaan:
- membuatnya sederhana melalui mendongeng;
- punya rencana strategis, waspadai keseluruhan gambaran;
- fokus pada makna;
- berbaris sistem dalam lapisan;
- mengirimkan sistem langkah demi langkah;
- memenuhi kebutuhan tim.
Kami mempertimbangkan secara singkat masing-masing prinsip ini, mereka berguna bagi kami untuk pemahaman lebih lanjut. Di bawah ini adalah terjemahan gratis saya, dengan singkatan dan sisipan, saya sangat menyarankan Anda membiasakan diri dengan yang asli.
Kesederhanaan melalui bercerita
Narasi adalah bagian dari budaya kita; Ini adalah cara termudah dan paling efektif untuk mentransfer pengetahuan, informasi dari satu orang ke orang lain. Ini adalah cara terbaik untuk mengkomunikasikan apa yang harus dilakukan sistem dan membantu tim fokus pada tujuan bersama.
Kasus penggunaan mencerminkan tujuan sistem. Untuk memahami Use Case, kami memberi tahu, menceritakan kisah tertentu. Ceritanya menceritakan bagaimana mencapai tujuan dan bagaimana menyelesaikan masalah yang muncul di sepanjang jalan. Gunakan kasing, seperti buku cerita, menyediakan cara untuk mengidentifikasi dan meliput semua cerita yang berbeda tetapi terkait dengan cara yang sederhana dan komprehensif. Ini membuatnya mudah untuk mengumpulkan, mendistribusikan, dan memahami persyaratan sistem.
Prinsip ini berkorelasi dengan bahasa Ubiques dari pendekatan DDD.
Memahami keseluruhan gambar
Terlepas dari sistem mana yang Anda kembangkan, besar, kecil, perangkat lunak, perangkat keras atau bisnis, memahami gambaran besar sangat penting. Tanpa memahami sistem secara keseluruhan, Anda tidak dapat membuat keputusan yang tepat tentang apa yang akan dimasukkan ke dalam sistem, apa yang harus dikesampingkan, berapa biayanya, dan manfaat apa yang akan dihasilkannya.
Ivar Jacobson menyarankan menggunakan diagram use case , yang sangat nyaman untuk mengumpulkan persyaratan. Jika persyaratan dikompilasi dan dihapus, maka peta Konteks Eric Evans adalah pilihan terbaik. Seringkali, pendekatan Scrum ditafsirkan sehingga orang tidak menghabiskan waktu untuk rencana strategis, mengingat perencanaan, lebih dari dua minggu kemudian, peninggalan masa lalu. Propaganda Jeff Sutherland jatuh pada aliran air, dan orang-orang yang menyelesaikan kursus pelatihan dua minggu untuk Scrum Masters yang diizinkan untuk mengelola proyek melakukan pekerjaan mereka. Tetapi akal sehat mengakui pentingnya perencanaan strategis. Tidak perlu membuat rencana strategis yang terperinci, tetapi haruslah demikian.
Fokus pada nilai
Ketika mencoba memahami bagaimana sistem akan digunakan, selalu penting untuk fokus pada nilai yang akan diberikannya kepada penggunanya dan pihak-pihak lain yang berkepentingan. Nilai terbentuk hanya ketika sistem digunakan. Oleh karena itu, jauh lebih baik untuk fokus pada bagaimana sistem akan diterapkan daripada pada daftar panjang fitur atau kemampuan yang dapat ditawarkannya.
Use case menyediakan fokus ini, membantu Anda berkonsentrasi pada bagaimana sistem akan digunakan oleh pengguna tertentu untuk mencapai tujuannya. Use cases mencakup banyak cara untuk menggunakan sistem: yang berhasil mencapai tujuan mereka, dan yang memecahkan kesulitan yang muncul.
Selanjutnya, penulis memberikan skema yang luar biasa, yang harus diperhatikan:

Diagram menunjukkan use case, "Penarikan tunai di ATM". Cara termudah untuk mencapai tujuan dijelaskan dalam Arah Dasar (Aliran dasar). Kasus-kasus lain digambarkan sebagai aliran alternatif. Arahan ini membantu bercerita, menyusun sistem, dan membantu menulis tes.
Layering
Sebagian besar sistem membutuhkan banyak pekerjaan sebelum siap digunakan. Mereka memiliki banyak persyaratan, yang sebagian besar tergantung pada persyaratan lain, mereka harus diimplementasikan sebelum persyaratan dipenuhi dan dievaluasi.
Adalah kesalahan besar untuk membuat sistem seperti itu pada suatu waktu. Sistem harus dibangun dari potongan-potongan, yang masing-masing memiliki nilai yang jelas bagi pengguna.
Ide-ide ini beresonansi dengan pendekatan gesit dan dengan ide-ide Domain .
Peluncuran produk langkah demi langkah
Sebagian besar sistem perangkat lunak telah berkembang selama beberapa generasi. Mereka tidak diproduksi pada suatu waktu; mereka dibangun sebagai serangkaian rilis, yang masing-masing dibangun pada rilis sebelumnya. Bahkan rilis itu sendiri sering tidak keluar sekaligus, tetapi berkembang melalui serangkaian versi perantara. Setiap langkah menyediakan versi sistem yang jelas dan dapat digunakan. Ini adalah cara semua sistem harus dibuat.
Memenuhi kebutuhan tim
Sayangnya, tidak ada solusi universal untuk masalah pengembangan perangkat lunak; tim yang berbeda dan situasi yang berbeda memerlukan gaya dan tingkat detail yang berbeda pula. Apa pun metode dan teknik yang Anda pilih, Anda harus memastikan bahwa mereka cukup mudah beradaptasi untuk memenuhi kebutuhan tim saat ini.
Eric Evans dalam bukunya mendesak Anda untuk tidak menghabiskan banyak waktu menjelaskan semua proses melalui UML. Cukup menggunakan skema visual apa pun. Tim yang berbeda, proyek yang berbeda memerlukan tingkat detail yang berbeda, karena penulis UML sendiri membicarakan hal ini.
Implementasi
Dalam arsitektur murni, Robert Martin mendefinisikan kasus Penggunaan berikut:
Use case ini mengatur aliran data ke dan dari entitas, dan mengarahkan entitas tersebut untuk menggunakan Aturan Bisnis Kritis mereka untuk mencapai tujuan use case.
Mari kita coba menerjemahkan ide-ide ini ke dalam kode. Mari kita ingat skema dari prinsip ketiga menggunakan Kasus Penggunaan dan menganggapnya sebagai dasar. Pertimbangkan proses bisnis yang sangat rumit: "Memasak Pai Kubis".
Mari kita coba mendekomposisinya:
- periksa ketersediaan produk;
- ambil dari stok;
- remas adonan;
- biarkan adonan mengembang;
- menyiapkan isian;
- membuat kue;
- membuat kue pai.
Kami menerapkan seluruh urutan ini melalui Interactor , dan setiap langkah akan diimplementasikan melalui fungsi atau Objek Fungsional pada Lapisan Layanan.
Sequence of Actions (Interactor)

Saya sangat merekomendasikan memulai pengembangan proses bisnis yang kompleks dengan Sequence of Actions . Lebih tepatnya, tidak demikian, Anda harus menentukan Domain Domain tempat proses bisnis berada. Perjelas semua persyaratan bisnis. Identifikasi semua Entitas yang terlibat dalam proses. Dokumentasikan persyaratan dan definisi masing-masing Entitas dalam basis pengetahuan.
Lukis semuanya di atas kertas dalam beberapa langkah. Terkadang Anda membutuhkan diagram urutan. Penulisnya adalah orang yang sama yang menemukan Use Case - Ivar Jacobson. Diagram itu ditemukan olehnya ketika ia mengembangkan sistem pemeliharaan jaringan telepon untuk Erickson, berdasarkan pada rangkaian relai. Saya sangat suka diagram ini, dan istilah Sequence , menurut pendapat saya, lebih ekspresif daripada istilah Interactor . Namun mengingat prevalensi yang lebih besar dari yang terakhir, kami akan menggunakan istilah yang akrab - Interactor .
Sedikit petunjuk ketika Anda menggambarkan proses bisnis adalah bantuan yang baik untuk Anda, aturan utama manajemen dokumen dapat menjadi: "Sebagai hasil dari aktivitas bisnis apa pun, dokumen harus dibuat". Sebagai contoh, kami sedang mengembangkan sistem diskon. Memberikan diskon, kami, pada kenyataannya, dari sudut pandang bisnis, menyimpulkan kesepakatan antara perusahaan dan klien. Semua persyaratan harus dijabarkan dalam kontrak ini. Yaitu, di domain DiscountSystem, Anda akan memiliki Entites :: Contract. Jangan ikat diskon dengan klien, tetapi buat Kontrak Entitas , yang menjelaskan aturan untuk ketentuannya.
Mari kita kembali ke deskripsi proses bisnis kita, setelah menjadi transparan bagi semua orang yang terlibat dalam pengembangannya, dan semua pengetahuan Anda sudah diperbaiki. Saya sarankan Anda mulai menulis kode dengan Sequence of Actions .
Templat Desain Urutan bertanggung jawab untuk:
- urutan tindakan ;
- koordinasi data yang dikirimkan antar Tindakan ;
- memproses kesalahan yang dilakukan oleh Tindakan selama eksekusi mereka;
- pengembalian hasil dari serangkaian Tindakan yang dilakukan;
- PENTING : tanggung jawab paling penting dari pola desain ini adalah penerapan logika bisnis.
Saya ingin memikirkan tanggung jawab terakhir lebih terinci jika kita memiliki semacam proses yang kompleks - kita harus menggambarkannya sedemikian rupa sehingga jelas apa yang terjadi tanpa masuk ke rincian teknis. Anda harus mendeskripsikannya secara eksplisit sebagaimana kemampuan pemrograman Anda memungkinkan Anda . Percayakan kelas ini kepada anggota tim Anda yang paling berpengalaman.
Mari kita kembali ke pie: mari kita coba menggambarkan proses persiapannya melalui Interactor .
Implementasi
Saya memberikan contoh implementasi dengan solusi LunaPark kami, yang kami sajikan dalam artikel sebelumnya.
module Kitchen module Sequences class CookingPieWithabbage < LunaPark::Interactors::Sequence TEMPERATURE = Values::Temperature.new(180, unit: :cel) def call! Services::CheckProductsAvailability.call list: ingredients dough = Services::BeatDough.call from: Repository::Products.get(beat_ingredients) filler = Services::MakeabbageFiller.call from: Repository::Products.get(filler_ingredients) pie = Services::MakePie.call dough, with: filler bake = Services::BakePie.new pie, temp: TEMPERATURE sleep 5.min until bake.call pie end private attr_accessor :beat_ingredients, :filler_ingredients attr_accessor :pie def ingredients_list beat_ingredients_list + filler_ingredients_list end end end end
Seperti yang bisa kita lihat, call!
menjelaskan seluruh logika bisnis dari proses memanggang kue. Dan lebih mudah digunakan untuk memahami logika aplikasi.
Selain itu, kita dapat dengan mudah menggambarkan proses memanggang kue ikan, menggantikan MakeabbageFiller
dengan MakeFishFiller
. Dengan demikian, kami sangat cepat mengubah proses bisnis, tanpa modifikasi kode yang signifikan. Dan juga, kita dapat meninggalkan kedua Urutan pada saat yang sama, menskalakan kasus bisnis.
Pengaturan
- Metode
call!
adalah metode yang diperlukan, itu menggambarkan urutan Tindakan . - Setiap parameter inisialisasi dapat dijelaskan melalui setter atau
attr_acessor
:
class Foo < LunaPark::Interactors::Sequence
- Sisa metode harus bersifat pribadi.
Contoh penggunaan
beat_ingredients = [ Entity::Product.new :flour, 500, :gr, Entity::Product.new :oil, 50, :gr, Entity::Product.new :salt, 1, :spoon, Entity::Product.new :milk, 150, :ml, Entity::Product.new :egg, 1, :unit, Entity::Product.new :yeast, 1, :spoon ] filler_ingredients = [ Entity::Product.new :cabbage, 500, :gr, Entity::Product.new :salt, 1, :spoon, Entity::Product.new :pepper, 1, :spoon ] cooking = CookingPieWithabbage.call( beat_ingredients: beat_ingredients, filler_ingredients: filler_ingredients )
Proses diwakili melalui objek dan kami memiliki semua metode yang diperlukan untuk memanggilnya - apakah panggilan berhasil, apakah ada kesalahan terjadi selama panggilan, dan jika demikian, yang mana?
Menangani kesalahan
Jika kita sekarang mengingat prinsip ketiga dari aplikasi Case Use, kami memperhatikan fakta bahwa selain jalur Utama , kami juga memiliki arahan Alternatif . Ini adalah kesalahan yang harus kita tangani. Pertimbangkan sebuah contoh: kami tentu tidak ingin acara seperti itu, tetapi kami tidak bisa melakukan apa-apa, kenyataan pahitnya adalah bahwa pai terbakar secara berkala.
Interactor mencegat semua kesalahan yang diwarisi dari LunaPark::Errors::Processing
class.
Bagaimana cara melacak kue? Untuk melakukan ini, tentukan kesalahan Burned
dalam Tindakan BakePie
.
module Kitchen module Errors class Burned < LunaPark::Errors::Processing; end end end
Dan selama memanggang, pastikan pai kami belum habis:
module Kitchen module Services class BakePie < LunaPark::Callable def call
Dalam hal ini, jebakan kesalahan akan berfungsi, dan kami akan dapat mengatasinya di
.
Kesalahan yang tidak diwarisi dari Processing
dianggap sebagai kesalahan sistem dan akan dicegat di tingkat server. Kecuali ditentukan lain, pengguna akan menerima 500 ServerError.
Penggunaan praktik
1. Cobalah untuk menggambarkan semua panggilan dalam metode panggilan!
Anda tidak boleh menerapkan setiap Tindakan dalam metode terpisah, ini membuat kode lebih membengkak. Anda harus melihat seluruh kelas beberapa kali untuk memahami cara kerjanya. Merusak resep untuk membuat kue:
module Service class CookingPieWithabbage < LunaPark::Interactors::Sequence def call! check_products_availability make_cabbage_filler make_pie bake end private def check_products_availability Services::CheckProductsAvailability.call list: ingredients end
Gunakan panggilan aksi langsung di kelas. Dari sudut pandang ruby, pendekatan ini mungkin tampak tidak biasa, sehingga terlihat lebih mudah dibaca:
class DrivingStart < LunaPark::Interactors::Sequence def call! Service::CheckEngine.call Service::StartUpTheIgnition.call car, with: key Service::ChangeGear.call car.gear_box, to: :drive Service::StepOnTheGas.call car.pedals[:right] end end
2. Jika memungkinkan, gunakan metode kelas panggilan
3. Jangan membuat objek Fungsional demi mengetik kode, lihat situasinya
Lapisan Layanan

Interactor, seperti yang kami katakan, menggambarkan logika bisnis di tingkat tertinggi. Lapisan layanan sudah mengungkapkan detail penerapan persyaratan fungsional. Jika kita berbicara tentang membuat pai, maka pada tingkat Interactor kita cukup mengatakan "uleni adonan", tanpa merinci tentang cara meremasnya. Proses pengulungan dijelaskan pada tingkat Layanan . Mari kita kembali ke sumber aslinya, buku biru besar :
Di domain yang diterapkan, ada operasi yang tidak dapat menemukan tempat alami di objek bertipe Entity atau Value Object. Mereka secara inheren bukan objek, tetapi aktivitas. Tetapi karena dasar dari paradigma pemodelan kami adalah pendekatan objek, kami akan mencoba mengubahnya menjadi objek.
Pada titik ini mudah untuk membuat kesalahan umum: meninggalkan upaya untuk menempatkan operasi pada objek yang sesuai untuknya, dan dengan demikian sampai pada pemrograman prosedural. Tetapi jika Anda secara paksa menempatkan operasi pada objek dengan definisi yang asing terhadapnya, ini akan membuat objek itu sendiri kehilangan kemurniannya, membuatnya lebih sulit untuk dipahami dan diperbaiki. Jika Anda menerapkan banyak operasi kompleks dalam objek sederhana, itu bisa berubah menjadi apa yang tidak dapat dipahami, apa yang Anda lakukan tidak jelas apa. Operasi tersebut sering melibatkan objek lain dari area subjek dan koordinasi di antara mereka dilakukan untuk melakukan tugas bersama. Tanggung jawab tambahan menciptakan rantai ketergantungan antar objek, menggabungkan konsep yang dapat dipertimbangkan secara independen.
Saat memilih lokasi untuk implementasi fungsional, selalu gunakan akal sehat. Tugas Anda adalah membuat model lebih ekspresif. Mari kita lihat sebuah contoh, "Kita harus memotong kayu":
module Entities class Wood def chop
Metode ini akan menjadi kesalahan. Kayu bakar tidak akan memotong sendiri, kita membutuhkan kapak:
module Entities class Axe def chop(sacrifice)
Jika kita menggunakan model bisnis yang disederhanakan, itu sudah cukup. Tetapi jika proses perlu dimodelkan secara lebih rinci, kita akan membutuhkan seseorang yang akan memotong kayu bakar ini, dan mungkin beberapa batang kayu yang akan digunakan sebagai dudukan untuk proses tersebut.
module Entities class Human def chop_firewood(wood, axe, chock)
Seperti yang mungkin sudah Anda tebak, ini bukan ide yang baik. Tidak semua dari kita terlibat dalam memotong kayu, ini bukan tugas langsung seseorang. Kita sering melihat betapa kelebihan model di Ruby on Rails, yang mengandung logika serupa: mendapatkan diskon, menambahkan barang ke keranjang, menarik uang ke saldo. Logika ini tidak berlaku untuk entitas, tetapi untuk proses di mana entitas ini terlibat.
module Services class ChopFirewood
Setelah kami menemukan logika apa yang kami simpan di Layanan, kami akan mencoba menerapkan salah satunya. Paling sering, layanan diimplementasikan melalui metode atau objek fungsional.
Objek Fungsional
Objek fungsional memenuhi satu persyaratan fungsional. Dalam bentuknya yang paling primitif, objek fungsional memiliki satu metode publik tunggal - call
.
module Serivices class Sum def initialize(x, y) @x = x @y = y end def call x + y end def self.call(x,y) new(x,y).call end private attr_reader :x, :y end end
Objek semacam itu memiliki beberapa keunggulan: mereka ringkas, sangat mudah untuk diuji. Ada kekurangannya, objek seperti itu bisa berubah menjadi sejumlah besar. Ada beberapa cara untuk mengelompokkan objek yang serupa; di bagian proyek kami, kami membaginya berdasarkan jenis:
- Obyek layanan (Layanan) - suatu objek, menciptakan objek baru;
- Command (Command) - mengubah objek saat ini;
- Guardian (Guard) - mengembalikan kesalahan jika terjadi kesalahan.
Obyek Layanan
Dalam implementasi kami, Layanan - mengimplementasikan persyaratan fungsional dan selalu mengembalikan nilai.
module KorovaMilkBar module Services class FindMilk < LunaPark::Callable GLASS_SIZE = Values::Unit.wrap '200g' def initialize(fridge:) @fridge = fridge end def call fridge.shelfs.find { |shelf| shelf.has?(GLASS_SIZE, of: :milk) } end private attr_reader :fridge end end end FindMilk.call(fridge: the_red_one)
Perintah
Dalam implementasi kami, Perintah - melakukan satu Tindakan , memodifikasi objek, jika benar mengembalikan benar. Sebenarnya, Tim tidak membuat objek, tetapi memodifikasi yang sudah ada.
module KorovaMilkBar module Commands class FillGlass < LunaPark::Callable def initialize(glass, with:) @glass = glass @content = with end def call glass << content true end private attr_reader :fridge end end end glass = Glass.empty milk = Milk.new(200, :gr) glass.empty?
Wali (Penjaga)
Penjaga melakukan pemeriksaan logis dan jika gagal memberikan kesalahan pemrosesan. Jenis objek ini tidak mempengaruhi Arah Utama dengan cara apa pun, tetapi mengalihkan kita ke Arah Alternatif jika terjadi kesalahan.
Saat menyajikan susu, penting untuk memastikan susu segar:
module KorovaMilkBar module Guards class IsFresh < LunaPark::Callable def initialize(product) @products = products end def call products.each do |product| raise Errors::Rotten, "
Anda mungkin merasa nyaman untuk memisahkan objek fungsional berdasarkan jenis. Anda dapat menambahkan milik Anda sendiri, misalnya, Builder - membuat objek berdasarkan parameter.
Pengaturan
- Metode
call
adalah satu-satunya metode publik wajib. - Metode
initialize
adalah satu-satunya metode publik opsional. - Sisa metode harus bersifat pribadi.
- Kesalahan logis harus diwarisi dari kelas
LunaPark::Errors::Processing
.
Menangani kesalahan
Ada 2 jenis kesalahan yang dapat terjadi selama operasi suatu Tindakan .
Kesalahan Runtime
Kesalahan tersebut dapat terjadi sebagai akibat dari pelanggaran logika pemrosesan.
Sebagai contoh:
- saat membuat email pengguna dicadangkan;
- ketika Anda mencoba minum susu, itu sudah berakhir;
- microservice lain menolak tindakan (karena alasan logis, dan bukan karena layanan tidak tersedia).
Kemungkinan besar, pengguna ingin tahu tentang kesalahan ini. Juga, ini mungkin kesalahannya
yang bisa kita ramalkan.
Kesalahan semacam itu harus diwarisi dari LunaPark::Errors::Processing
Kesalahan sistem
Kesalahan yang terjadi sebagai akibat dari sistem crash.
Sebagai contoh:
- database tidak berfungsi;
- sesuatu dibagi dengan nol.
Dalam semua kemungkinan, kami tidak dapat melihat kesalahan ini dan tidak bisa mengatakan apa pun kepada pengguna, kecuali bahwa semuanya sangat buruk, dan mengirimkan laporan kepada pengembang yang meminta tindakan. Kesalahan semacam itu harus diwarisi dari SystemError
Ada juga kesalahan validasi , yang akan kita diskusikan secara lebih rinci di artikel selanjutnya.
Penggunaan praktik
1. Gunakan variabel untuk meningkatkan keterbacaan
module Fishing
2. Lulus objek, bukan parameter
Cobalah untuk membuat penginisialisasi sederhana jika pemrosesan parameter tidak tujuannya.
Lulus objek, bukan parameter.
module Service
3. Gunakan nama Tindakan - kata kerja dari tindakan dan objek pengaruh.
4. Jika memungkinkan, gunakan metode kelas panggilan
Biasanya instance dari kelas Actions , jarang digunakan selain menulis untuk membuat panggilan.
5. Penanganan kesalahan bukan tugas layanan
Modul
Hingga saat ini, kami menganggap implementasi lapisan Layanan sebagai seperangkat objek fungsional. Tetapi kita dapat dengan mudah menempatkan metode pada layer ini:
module Services def sum(a, b) a + b end end
Masalah lain yang menghadang kita adalah sejumlah besar fasilitas layanan. Alih-alih "model lemak rel", yang kami dapatkan di tepi, kami mendapatkan "folder layanan lemak". Ada beberapa cara untuk mengatur struktur untuk mengurangi skala tragedi. Eric Evans memecahkan ini dengan menggabungkan sejumlah fungsi ke dalam satu kelas. Bayangkan kita perlu memodelkan proses bisnis pengasuh, Arina Rodionovna, dia bisa memberi makan Pushkin dan menidurkannya:
class NoonService def initialize(arina_radionovna, pushkin)
Pendekatan ini lebih tepat dari sudut pandang OOP. Namun kami menyarankan untuk mengabaikannya, setidaknya pada tahap awal. Pemrogram yang tidak terlalu berpengalaman mulai menulis banyak kode di kelas ini, yang pada akhirnya mengarah pada peningkatan konektivitas. Sebagai gantinya, Anda dapat menggunakan modul, mewakili aktivitas sebagai beberapa abstraksi:
module Services module Noon class ToFeed def call!
Ketika membaginya menjadi beberapa modul, kopling eksternal rendah (kopling rendah) harus diamati dengan kohesi internal yang tinggi (kohesi tinggi), tetapi kami menggunakan modul seperti Layanan atau Interaktor, ini juga bertentangan dengan gagasan arsitektur murni. Ini adalah pilihan sadar yang memfasilitasi persepsi. Dengan nama file, kami memahami pola desain mana yang diterapkan kelas ini atau itu, jika bagi seorang programmer berpengalaman ini jelas, maka untuk seorang pemula hal ini tidak selalu terjadi. Setelah tim Anda siap, buang kelebihan ini.
Mengutip kutipan kecil lain dari buku biru besar:
Pilih modul yang memberi tahu sejarah sistem dan berisi serangkaian konsep yang koheren. Dari sinilah seringkali ketergantungan modul yang rendah satu sama lain muncul dengan sendirinya. Tetapi jika ini tidak terjadi, cari cara untuk mengubah model sedemikian rupa untuk memisahkan konsep satu sama lain, atau mencari konsep yang hilang dalam model, yang dapat menjadi dasar untuk modul dan dengan demikian menyatukan unsur-unsur model bersama-sama dengan cara alami, bermakna. Mencapai ketergantungan rendah modul satu sama lain dalam arti bahwa konsep dalam modul yang berbeda dapat dianalisis dan dirasakan secara independen satu sama lain. Perbaiki model sampai batas-batas alami muncul di dalamnya sesuai dengan konsep tingkat tinggi dari area subjek, dan kode yang sesuai tidak dibagi sesuai.
Berikan nama modul yang akan dimasukkan dalam BAHASA YANG TIDAK DIKENAL. Baik MODUL itu sendiri maupun namanya harus mencerminkan pengetahuan dan pemahaman tentang bidang subjek.
Topik modulnya besar dan menarik, tetapi secara lengkap melampaui topik artikel ini. Lain kali kami akan berbicara dengan Anda tentang Gudang dan Adaptor . Kami membuka saluran telegram yang nyaman tempat kami ingin berbagi materi tentang topik DDD. Kami menyambut pertanyaan dan umpan balik Anda.