Buku Masakan Pengembang: Resep DDD (Bagian 4, Struktur)

Pendahuluan


Jadi, kami telah memutuskan ruang lingkup , metodologi dan arsitektur . Mari kita beralih dari teori ke praktik, ke menulis kode. Saya ingin memulai dengan pola desain yang menggambarkan logika bisnis - Layanan dan Interaktor . Tetapi sebelum memulai, kita akan memeriksa pola struktural - ValueObject dan Entity . Kami akan berkembang dalam bahasa ruby . Dalam artikel selanjutnya, kami akan menganalisis semua pola yang diperlukan untuk pengembangan menggunakan Arsitektur Variabel . Semua pengembangan yang merupakan aplikasi untuk seri artikel ini akan dikumpulkan dalam kerangka kerja yang terpisah.


Blacjack & hockers


Dan kami telah mengambil nama yang cocok - LunaPark .
Perkembangan saat ini diposting di Github .
Setelah memeriksa semua templat, kami akan merakit satu layanan microsoft lengkap.


Jadi secara historis


Ada kebutuhan untuk memperbaiki aplikasi perusahaan yang rumit yang ditulis dalam Ruby on Rails. Ada tim pengembang ruby ​​yang sudah jadi. Metodologi Pengembangan Domain Driven sempurna untuk tugas-tugas ini, tetapi tidak ada solusi turnkey dalam bahasa yang digunakan. Terlepas dari kenyataan bahwa pilihan bahasa terutama ditentukan oleh spesialisasi kami, ternyata cukup berhasil. Di antara semua bahasa yang biasa digunakan untuk aplikasi web, ruby, menurut saya, adalah yang paling ekspresif. Dan karenanya, lebih dari yang lain cocok untuk memodelkan objek nyata. Ini bukan hanya pendapat saya.


Itu adalah dunia Jawa. Maka Anda memiliki pendatang baru seperti Ruby. Ruby memiliki sintaks yang sangat ekspresif, dan pada level dasar ini seharusnya merupakan bahasa yang sangat baik untuk DDD (walaupun saya belum pernah mendengar banyak penggunaan aktualnya dalam aplikasi semacam itu). Rails telah menghasilkan banyak kegembiraan karena akhirnya membuat pembuatan UI Web semudah UI kembali pada awal 1990-an, sebelum Web. Saat ini, kemampuan ini sebagian besar telah diterapkan untuk membangun sejumlah besar aplikasi Web yang tidak memiliki banyak kekayaan domain di belakangnya, karena bahkan ini sangat sulit di masa lalu. Tetapi harapan saya adalah bahwa, ketika bagian implementasi UI dari masalah berkurang, orang-orang akan melihat ini sebagai kesempatan untuk lebih memfokuskan perhatian mereka pada domain. Jika penggunaan Ruby mulai mengarah ke sana, saya pikir itu bisa menyediakan platform yang sangat baik untuk DDD. (Beberapa infrastruktur mungkin harus diisi.)

Eric Evans 2006

Sayangnya, selama 13 tahun terakhir, tidak ada yang berubah banyak. Di Internet Anda dapat menemukan upaya untuk mengadaptasi Rails untuk ini, tetapi semuanya terlihat mengerikan. Kerangka Rails berat, lambat, dan tidak SOLID. Sangat sulit untuk menonton tanpa air mata bagaimana seseorang mencoba menggambarkan implementasi pola Repositori berdasarkan ActiveRecord . Kami memutuskan untuk mengadopsi mikro dan memodifikasinya untuk kebutuhan kami. Kami mencoba Grape , gagasan dengan dokumentasi otomatis sepertinya berhasil, tetapi jika tidak ditinggalkan dan kami dengan cepat meninggalkan gagasan untuk menggunakannya. Dan segera mereka mulai menggunakan solusi lain - Sinatra . Kami masih terus menggunakannya untuk Pengendali dan Titik Akhir REST.


SISA?

Jika Anda mengembangkan aplikasi web, maka Anda sudah memiliki gagasan tentang teknologi tersebut. Ini memiliki pro dan kontra, daftar lengkap yang berada di luar cakupan artikel ini. Tetapi bagi kami, sebagai pengembang aplikasi perusahaan, kelemahan terpenting adalah bahwa REST (ini jelas bahkan dari namanya) tidak mencerminkan prosesnya, melainkan keadaannya. Dan keuntungannya adalah dapat dimengerti - teknologinya jelas bagi pengembang back-end dan front-end.
Tapi kemudian mungkin tidak fokus pada REST, tetapi mengimplementasikan solusi http + json Anda? Bahkan jika Anda berhasil mengembangkan API layanan Anda, kemudian memberikan deskripsinya kepada pihak ketiga Anda akan menerima banyak pertanyaan. Jauh lebih daripada jika Anda memberikan REST yang akrab.
Kami akan mempertimbangkan untuk menggunakan REST sebagai solusi kompromi. Kami menggunakan JSON untuk keringkasan dan standar jsonapi agar tidak membuang waktu pengembang pada perang suci mengenai format permintaan.
Di masa depan, ketika kita menganalisis Endpoint , kita akan melihat bahwa untuk menghilangkan istirahat, cukup menulis ulang hanya satu kelas. Jadi REST tidak perlu repot sama sekali jika ada keraguan tentang hal itu.


Dalam perjalanan menulis beberapa layanan microser, kami telah memperoleh dasar - satu set kelas abstrak. Setiap kelas dapat ditulis dalam setengah jam, kodenya mudah dimengerti jika Anda tahu untuk apa kode ini.


Di sini kesulitan utama muncul. Karyawan baru yang tidak berurusan dengan praktik DDD dan arsitektur bersih tidak dapat memahami kode dan tujuannya. Jika saya sendiri melihat kode ini untuk pertama kalinya sebelum membaca Evans, saya akan menganggapnya sebagai warisan, rekayasa berlebihan.


Untuk mengatasi kendala ini, diputuskan untuk menulis dokumentasi (pedoman) yang menggambarkan filosofi dari pendekatan yang digunakan. Garis besar dokumentasi ini tampaknya berhasil dan diputuskan untuk menempatkannya di HabrΓ©. Kelas abstrak yang diulang dari proyek ke proyek, diputuskan untuk dimasukkan ke dalam permata yang terpisah.


Filsafat


cara warisan
Jika Anda mengingat beberapa film klasik tentang seni bela diri, maka akan ada seorang pria keren yang sangat cekatan menangani tiang. Yang keenam pada dasarnya adalah tongkat, alat yang sangat primitif, salah satu yang pertama jatuh ke tangan manusia. Namun di tangan tuannya, ia menjadi senjata yang tangguh.
Anda dapat menghabiskan waktu membuat pistol yang tidak menembak kaki Anda, atau Anda dapat menghabiskan waktu mempelajari teknik menembak. Kami telah mengidentifikasi 4 prinsip dasar:


  • Anda perlu membuat hal-hal rumit menjadi sederhana.
  • Pengetahuan lebih penting daripada teknologi. Dokumentasi lebih mudah dipahami seseorang daripada kode, seseorang tidak boleh mengganti yang satu dengan yang lain.
  • Pragmatisme lebih penting daripada dogmatisme. Standar harus memandu jalan, bukan menetapkan kotak pembatas.
  • Strukturalitas dalam arsitektur, fleksibilitas dalam pilihan solusi.

Filosofi serupa dapat ditelusuri, misalnya, di ArchLinux OS - The Arch Way . Di laptop saya, Linux tidak berakar untuk waktu yang lama, cepat atau lambat ia rusak dan saya harus menginstalnya kembali. Ini menyebabkan sejumlah masalah, kadang-kadang masalah serius seperti gangguan tenggat waktu untuk bekerja. Tapi setelah menghabiskan 2-3 hari setelah menginstal Arch, saya menemukan cara kerja OS saya. Setelah itu, ia mulai bekerja lebih stabil, tanpa kegagalan. Catatan saya membantu saya menginstalnya di PC baru dalam beberapa jam. Dokumentasi yang banyak membantu saya memecahkan masalah baru.


Kerangka kerja ini memiliki karakter tingkat yang sangat tinggi. Kelas-kelas yang menggambarkannya bertanggung jawab atas struktur aplikasi. Solusi pihak ketiga digunakan untuk berinteraksi dengan basis data, mengimplementasikan protokol http dan hal-hal tingkat rendah lainnya. Kami ingin programmer untuk melihat ke dalam kode ketika sebuah pertanyaan muncul dan memahami cara kerja kelas tertentu, dan dokumentasi akan memungkinkan kami untuk memahami cara mengelolanya. Memahami desain mesin tidak akan memungkinkan Anda mengendarai mobil.


Kerangka kerja


Sulit untuk menyebut LunaPark sebagai kerangka kerja dalam arti biasa. Bingkai - bingkai, Kerja - kerja. Kami mendesak untuk tidak membatasi diri pada ruang lingkup. Satu-satunya frame yang kami nyatakan adalah yang memberi tahu kelas di mana logika ini atau itu harus dijelaskan. Ini lebih merupakan seperangkat alat dengan instruksi luas untuk mereka.
Setiap kelas abstrak dan memiliki tiga tingkatan:


module LunaPark #  module Forms #  class Single # / end end end 

Jika Anda ingin menerapkan formulir yang membuat elemen tunggal, Anda mewarisi dari kelas ini:


 module Forms class Create < LunaPark::Forms::Single 

Jika ada beberapa elemen, kami akan menggunakan Implementasi lain.


 module Forms class Create < LunaPark::Forms::Multiple 

Saat ini, tidak semua perkembangan telah dilakukan dengan sempurna dan permata dalam kondisi alfa. Kami akan mengutipnya secara bertahap, sesuai dengan publikasi artikel. Yaitu jika Anda melihat artikel tentang ValueObject dan Entity , maka kedua templat ini sudah diterapkan. Pada akhir siklus, semuanya akan cocok untuk digunakan pada proyek. Karena kerangka itu sendiri tidak banyak berguna tanpa tautan ke sinatra \ roda, repositori terpisah akan dibuat yang menunjukkan cara "mengacaukan semuanya" untuk memulai proyek Anda dengan cepat.


Kerangka kerja ini terutama merupakan aplikasi untuk dokumentasi. Jangan menganggap artikel-artikel ini sebagai dokumentasi untuk kerangka kerja.


Jadi, mari kita mulai bisnis.


Objek Nilai


- Seberapa tinggi pacar Anda?
- 151
- Anda mulai bertemu dengan patung kebebasan?

Sesuatu seperti ini bisa saja terjadi di Indiana. Pertumbuhan manusia bukan hanya angka, tetapi juga unit pengukuran. Tidak selalu atribut dari suatu objek hanya dapat dijelaskan oleh primitif (Integer, String, Boolean, dll.), Kadang-kadang diperlukan kombinasi dari mereka:


  • Uang bukan hanya angka, itu angka (jumlah) + mata uang.
  • Tanggal terdiri dari satu hari, satu bulan, dan satu tahun.
  • Untuk mengukur berat, satu angka saja tidak cukup untuk kita, itu juga membutuhkan satuan pengukuran.
  • Nomor paspor terdiri dari seri dan, pada kenyataannya, dari nomor tersebut.

Di sisi lain, ini tidak selalu merupakan kombinasi, mungkin itu adalah semacam perpanjangan dari primitif.
Nomor telepon sering diambil sebagai nomor. Di sisi lain, tidak mungkin ia memiliki metode penambahan atau pembagian. Mungkin ada metode yang akan mengeluarkan kode negara dan metode yang mendefinisikan kode kota. Mungkin akan ada metode dekoratif tertentu yang akan menyajikannya tidak hanya sebagai string angka 79001231212 , tetapi sebagai string yang dapat dibaca: 7-900-123-12-12 .


mungkin seorang dekorator?

Berdasarkan dogma, tidak terbantahkan - ya. Jika kita mendekati dilema ini pada bagian dari akal sehat, maka ketika kita memutuskan untuk memanggil nomor ini, kita akan mentransfer objek itu sendiri ke telepon:


 phone.call Values::PhoneNumber.new(79001231212) 

Dan jika kami memutuskan untuk menyajikannya sebagai string, maka ini jelas dilakukan untuk seseorang. Jadi mengapa kita tidak langsung membuat baris ini dapat dibaca oleh seseorang?


 Values::PhoneNumber.new(79001231212).to_s 

Bayangkan kita menciptakan situs kasino online Three Axes dan menjual permainan kartu. Kita akan membutuhkan kelas 'kartu bermain'.


 module Values class PlayingCard < Lunapark::Values::Compound attr_reader :suit, :rank end end 

Jadi, kelas kami memiliki dua atribut read-only:


  • suit - card suit
  • martabat pangkat - kartu

Atribut ini hanya ditetapkan saat membuat peta dan tidak dapat berubah saat menggunakannya. Tentu saja Anda dapat mengambil kartu bermain dan mencoret 8 , tulis Q, tetapi ini tidak dapat diterima. Dalam masyarakat yang baik Anda kemungkinan besar akan ditembak. Ketidakmampuan untuk mengubah atribut setelah membuat objek menentukan properti pertama dari Value Object - immutability.
Properti penting kedua dari Object Value adalah bagaimana kita membandingkannya.


 module Values RSpec.describe PlayingCard do let(:card) { described_class.new suit: :clubs, rank: 10 } let(:other) { described_class.new suit: :clubs, rank: 10 } it 'should be eql' do expect(card).to eq other end end end 

Tes semacam itu akan gagal, karena akan dibandingkan di alamat. Agar tes dapat lulus, kita harus membandingkan Nilai-Obses dengan nilai, untuk ini kita akan menambahkan metode perbandingan:


 def ==(other) suit == other.suit && rank == other.rank end 

Sekarang ujian kami akan berlalu. Kami juga dapat menambahkan metode yang bertanggung jawab untuk perbandingan, tetapi bagaimana kami membandingkan 10 dan K? Seperti yang mungkin sudah Anda tebak, kami juga akan menyajikannya dalam bentuk Objek Nilai . Ok, jadi sekarang kita harus menginisiasi sepuluh klub top seperti ini:


 ten = Values::Rank.new('10') clubs = Values::Suits.new(:clubs) ten_clubs = Values::PlayingCards.new(rank: ten, clubs: clubs) 

Tiga baris sudah cukup untuk ruby. Untuk menghindari batasan ini, kami memperkenalkan properti ketiga dari Object-Value - turnover. Mari kita memiliki metode khusus kelas .wrap , yang dapat mengambil nilai dari berbagai jenis dan mengubahnya menjadi yang benar.


 class PlayingCard < Lunapark::Values::Compound def self.wrap(obj) case obj.is_a? self.class #      PlayingCard obj #      case obj.is_a? Hash #    ,      new(obj) #    case obj.is_a String #    ,     new rank: obj[0..-2], suit:[-1] # ,  -  . else #       raise ArgumentError #  . end end def initialize(suit:, rank:) #     @suit = Suit.wrap(suit) #      @rank = Rank.wrap(rank) end end 

Pendekatan ini memberi keuntungan besar:


 ten = Values::Rank.new('10') clubs = Values::Suits.new(:clubs) from_values = Values::PlayingCard.wrap rank: ten, suit: clubs from_hash = Values::PlayingCard.wrap rank: '10', suit: :clubs from_obj = Values::PlayingCard.wrap from_values from_str = Values::PlayingCard.wrap '10C' #        utf ,  ,  . 

Semua kartu ini akan sama satu sama lain. Jika metode wrap berkembang menjadi praktik yang baik, menempatkannya di kelas yang terpisah akan menjadi. Dari sudut pandang pendekatan dogmatis, kelas yang terpisah juga akan wajib.
Hmm, bagaimana dengan ruang di dek? Bagaimana cara mengetahui apakah kartu ini adalah kartu truf? Ini bukan kartu remi. Ini adalah nilai kartu bermain. Inilah tepatnya prasasti 10 yang Anda pimpin di sudut kardus.
Hal ini diperlukan untuk menghubungkan dengan Object-Value serta primitif, yang karena alasan tertentu tidak diterapkan dalam ruby. Dari sini, properti terakhir muncul - Nilai Objek tidak terikat ke domain mana pun.


Rekomendasi


Di antara seluruh variasi metode dan alat yang digunakan pada setiap momen dari setiap proses, selalu ada satu metode dan alat yang bekerja lebih cepat dan lebih baik daripada yang lain.

Frederick Taylor 1914

Operasi aritmatika harus mengembalikan objek baru

 # GOOD class Money < LunaPark::Values::Compound def +(other) other = self.class.wrap(other) raise ArgumentError unless same_currency? other self.class.new( amount: amount + other.amount, currency: currency ) end end 

Atribut Obyek Nilai hanya dapat berupa primitif atau Objek Nilai lainnya

 # GOOD class Weight < LunaPark::Values::Compound def intialize(value:, unit:) @value = value @unit = Unit.wrap(unit) end end # BAD class PlaingCard < LunaPark::Value def initialize(rank:, suit:, deck:) ... @deck = Entity::Deck.wrap(deck) #    end end 

Simpan operasi sederhana di dalam metode kelas

 # GOOD class Weight < LunaPark::Values::Compound def >(other) value > other.convert_to(unit).value end end 

Jika operasi "konversi" besar, maka mungkin masuk akal untuk memindahkannya ke kelas yang terpisah

 # UGLY class Weight < LunaPark::Values::Compound def convert_to(unit) unit = Unit.wrap(unit) case { self.unit.to_sym => unit.to_sym } when { :kg => :ft } Weight.new(value: 2.2046 * value, unit.to_sym) when # ... end end end # GOOD #./lib/values/weight/converter.rb class Weight class Converter < LunaPark::Services::Simple def initialize(weight, to:) ... end end end #./lib/values/weight.rb class Weight < LunaPark::Values::Compound def convert_to(unit) Converter.call! self, to: unit end end 

Penghapusan logika seperti itu ke dalam Layanan terpisah hanya dimungkinkan dengan syarat Layanan terisolasi: tidak menggunakan data dari sumber eksternal apa pun. Layanan ini harus dibatasi oleh konteks Objek Nilai itu sendiri.


Nilai objek tidak dapat mengetahui apa pun tentang logika domain

Misalkan kita sedang menulis toko online, dan kita memiliki peringkat barang. Untuk mendapatkannya, Anda perlu membuat permintaan ke database melalui Repositori .


 # DEADLY BAD class Rate < LunaPark::Values::Single def top?(10) Repository::Rates.top(first: 10).include? self end end 

Entitas


Kelas Entity bertanggung jawab atas beberapa objek nyata. Itu bisa berupa kontrak, kursi, agen real estat, kue, besi, kucing, kulkas - apa pun. Objek apa pun yang Anda perlukan untuk memodelkan proses bisnis Anda adalah Entitas .
Konsep Entity berbeda untuk Evans dan Martin. Dari sudut pandang Evans, entitas adalah objek yang ditandai oleh sesuatu yang menekankan individualitasnya.


Esensi oleh Zvans
Jika suatu objek ditentukan oleh keberadaan individu yang unik, dan bukan oleh seperangkat atribut, properti ini harus dibaca sebagai yang utama ketika mendefinisikan objek dalam suatu model. Definisi kelas harus sederhana dan dibangun di sekitar kontinuitas dan keunikan siklus keberadaan objek. Temukan cara untuk membedakan setiap objek terlepas dari bentuk atau sejarah keberadaannya. Berikan perhatian khusus pada persyaratan teknis yang terkait dengan membandingkan objek sesuai dengan atributnya. Tentukan operasi yang akan memberikan hasil unik untuk setiap objek tersebut - mungkin perlu untuk mengaitkan simbol tertentu dengan keunikan yang dijamin untuk ini. Alat identifikasi semacam itu mungkin memiliki asal eksternal, tetapi juga dapat berupa pengidentifikasi sewenang-wenang yang dihasilkan oleh sistem untuk kenyamanannya sendiri. Namun, alat seperti itu harus mematuhi aturan untuk membedakan antara objek dalam model. Model harus memberikan definisi yang tepat tentang apa objek identik itu.

Dari sudut pandang Martin, Entity bukanlah objek, tetapi lapisan. Lapisan ini akan menggabungkan objek dan logika bisnis untuk mengubahnya.


Kesedihan dari Martin
Pandangan saya tentang Entitas adalah bahwa mereka mengandung aturan Bisnis Independen Aplikasi. Mereka bukan hanya objek data. Mereka mungkin memegang referensi ke objek data; tetapi tujuannya adalah untuk mengimplementasikan metode aturan bisnis yang dapat digunakan oleh banyak aplikasi yang berbeda.

Gateways mengembalikan Entitas. Implementasi (di bawah garis) mengambil data dari database, dan menggunakannya untuk membangun struktur data yang kemudian diteruskan ke Entitas. Ini dapat dilakukan baik dengan penahanan atau warisan.

Sebagai contoh:

MyEntity kelas publik {data pribadi MyDataStructure;}

atau

kelas publik MyEntity memperluas MyDataStructure {...}

Dan ingat, pada dasarnya kita semua adalah bajak laut; dan aturan yang saya bicarakan di sini benar-benar lebih seperti pedoman ...

Dengan Essence, yang kami maksud hanya struktur. Dalam bentuknya yang paling sederhana, kelas Entity akan terlihat seperti ini:


 module Entities class MeatBag < LunaPark::Entities::Simple attr_accessor :id, :name, :hegiht, :weight, :birthday end end 

Objek yang bisa berubah yang menggambarkan struktur model bisnis dapat berisi tipe dan Nilai primitif.
LunaPark::Entites::Simple Kelas sederhana sangat sederhana, Anda dapat melihat kodenya, hanya memberi kita satu hal - inisialisasi mudah.


LunaPark :: Entites :: Sederhana
 module LunaPark module Entities class Simple def initialize(params) set_attributes params end private def set_attributes(hash) hash.each { |k, v| send(:"#{k}=", v) } end end end end 

Anda dapat menulis:


 john_doe = Entity::MeatBag.new( id: 42, name: 'John Doe', height: '180cm', weight: '80kg', birthday: '01-01-1970' ) 

Seperti yang mungkin sudah Anda tebak, kami ingin membungkus berat, tinggi dan tanggal lahir di Object Nilai .


 module Entities class MeatBag < LunaPark::Entites::Simple attr_accessor :id, :name attr_reader :heiht, :wight, :birthday def height=(height) @height = Values::Height.wrap(height) end def weight=(height) @height = Values::Weight.wrap(weight) end def birthday=(day) @birthday = Date.parse(day) end end end 

Agar tidak membuang waktu pada konstruktor seperti itu, kami telah menyiapkan implementasi yang lebih kompleks dari LunaPark::Entites::Nested :


 module Entities class MeatBag < LunaPark::Entities::Nested attr :id attr :name attr :heiht, Values::Height, :wrap attr :weight, Values::Weight, :wrap attr :birthday, Values::Date, :parse end end 

Seperti namanya, Implementasi ini memungkinkan Anda membuat struktur pohon.


Mari memuaskan hasrat saya untuk peralatan rumah tangga yang besar. Dalam artikel sebelumnya, kami menggambar analogi antara "twist" dari mesin cuci dan arsitektur . Dan sekarang kita akan menggambarkan objek bisnis yang penting seperti kulkas:


Refregerator


 class Refregerator < LunaPark::Entites::Nested attr :id, attr :brand attr :title namespace :fridge do namespace :door do attr :upper, Shelf, :wrap attr :lower, Shelf, :wrap end attr :upper, Shelf, :wrap attr :lower, Shelf, :wrap end namespace :main do namespace :door do attr :first, Shelf, :wrap attr :second, Shelf, :wrap attr :third, Shelf, :wrap end namespace :boxes do attr :left, Box, :wrap attr :right, Box, :wrap end attr :first, Shelf, :wrap attr :second, Shelf, :wrap attr :third, Shelf, :wrap attr :fourth, Shelf, :wrap end attr :last_open_at, comparable: false end 

Pendekatan ini menyelamatkan kita dari menciptakan Entitas yang tidak perlu, seperti pintu kulkas. Tanpa kulkas, itu harus menjadi bagian dari kulkas. Pendekatan ini nyaman untuk menyusun dokumen yang relatif besar, misalnya, aplikasi untuk pembelian asuransi.


The LunaPark::Entites::Nested Kelas LunaPark::Entites::Nested memiliki 2 properti lebih penting:


Keterbandingan:


 module Entites class User < LunaPark::Entites::Nested attr :email attr :registred_at end end u1 = Entites::User.new(email: 'john.doe@mail.com', registred_at: Time.now) u2 = Entites::User.new(email: 'john.doe@mail.com', registred_at: Time.now) u1 == u2 # => false 

Dua pengguna yang ditentukan tidak setara, karena mereka dibuat pada waktu yang berbeda dan karenanya nilai atribut registred_at akan berbeda. Tetapi jika kita mencoret atribut dari daftar yang dibandingkan:


 module Entites class User < LunaPark::Entites::Nested attr :email attr :registred_at, comparable: false end end 

lalu kita mendapatkan dua objek yang sebanding.


Implementasi ini juga memiliki properti omset - kita dapat menggunakan metode kelas


 Entites::User.wrap(email: 'john.doe@mail.com', registred_at: Time.now) 

Anda dapat menggunakan Hash, OpenStruct atau permata apa pun yang Anda suka sebagai Entitas , yang akan membantu Anda mewujudkan struktur entitas Anda.


Entitas adalah model objek bisnis, biarkan itu tetap sederhana. Jika beberapa properti tidak digunakan oleh bisnis Anda, jangan jelaskan.


Perubahan Entitas


Seperti yang Anda perhatikan, kelas Entity tidak memiliki metode perubahannya sendiri. Semua perubahan dilakukan dari luar. Objek nilai juga tidak berubah. Semua fungsi yang ada di dalamnya, pada umumnya, menghiasi esensi atau membuat objek baru. Esensi itu sendiri tetap tidak berubah. Untuk pengembang Ruby on Rails, pendekatan ini tidak biasa. Dari luar sepertinya kita umumnya menggunakan bahasa OOP untuk sesuatu yang lain. Tetapi jika Anda melihat sedikit lebih dalam - ini tidak benar. Bisakah jendela terbuka sendiri? Dapatkan mobil untuk bekerja, pesan hotel, kucing lucu dapatkan pelanggan baru? Ini semua adalah pengaruh eksternal. Sesuatu terjadi di dunia nyata, dan kami merefleksikannya dalam diri kami. Untuk setiap permintaan, kami membuat perubahan pada model kami. Dan dengan demikian kami mempertahankannya tetap terbaru, cukup untuk tugas-tugas bisnis kami. Adalah perlu untuk memisahkan keadaan model dan proses yang menyebabkan perubahan dalam keadaan ini. Cara melakukan ini, akan kita bahas di artikel selanjutnya.

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


All Articles