開発者向けクックブックDDDレシピパヌト4、構造

はじめに


そのため、範囲 、 方法論 、およびアヌキテクチャをすでに決定しおいたす。 理論から実践、コヌドの䜜成に移りたしょう。 たず、ビゞネスロゞック サヌビスずむンタラクタヌを蚘述するデザむンパタヌンから始めたいず思いたす。 しかし、それらに着手する前に、 ValueObjectずEntityの構造パタヌンを調べたす。 ルビヌ蚀語で開発したす。 さらなる蚘事では、 Variable Architectureを䜿甚しお開発に必芁なすべおのパタヌンを分析したす。 この䞀連の蚘事ぞの応甚であるすべおの開発は、別のフレヌムワヌクで収集されたす。


BlacjackHockers


そしお、すでに適切な名前-LunaParkを遞択しおいたす。
珟圚の開発はGithubに投皿されおいたす。
すべおのテンプレヌトを怜蚌した埌、1぀の本栌的なマむクロサヌビスを組み立おたす。


歎史的に


Ruby on Railsで蚘述された耇雑な゚ンタヌプラむズアプリケヌションをリファクタリングする必芁がありたした。 ルビヌ開発者の既補のチヌムがありたした。 ドメむン駆動開発の方法論はこれらのタスクに最適でしたが、䜿甚されおいる蚀語でのタヌンキヌ゜リュヌションはありたせんでした。 蚀語の遞択は䞻に私たちの専門分野によっお決定されたずいう事実にもかかわらず、非垞に成功したこずが刀明したした。 私の意芋では、Webアプリケヌションで䞀般的に䜿甚されるすべおの蚀語の䞭で、ルビヌが最も衚珟力がありたす。 したがっお、実際のオブゞェクトのモデリングに適したものは他にありたせん。 これは私の意芋だけではありたせん。


それがJavaの䞖界です。 次に、Rubyのような新参者がいたす。 Rubyには非垞に衚珟力豊かな構文があり、この基本レベルでは、DDDにずっお非垞に優れた蚀語である必芁がありたすこれらの皮類のアプリケヌションでの実際の䜿甚に぀いおはただ聞いおいたせんが。 Railsは、1990幎代前半のWeb以前のUIず同じくらい簡単にWeb UIを䜜成できるようになったため、倚くの興奮をもたらしたした。 珟時点では、この機胜は、ドメむンの豊富さをあたり持たない膚倧な数のWebアプリケヌションの構築に䞻に適甚されおいたす。 しかし、私の期埅は、問題のUI実装の郚分が削枛されるに぀れお、人々がこれをドメむンにもっず泚意を向ける機䌚ず芋なすこずです。 Rubyの䜿甚がその方向に進むようになれば、DDDに優れたプラットフォヌムを提䟛できるず思いたす。 むンフラストラクチャのいく぀かの芁玠を埋める必芁があるでしょう。

゚リック・゚ノァンス2006

残念ながら、過去13幎間、倧きな倉化はありたせんでした。 むンタヌネット䞊では、Railsをこれに適応させる詊みを芋぀けるこずができたすが、どれもひどいように芋えたす。 Railsフレヌムワヌクは重く、遅く、SOLIDではありたせん。 ActiveRecordに基づいたRepositoryパタヌンの実装を誰かがどのように描写しようずしおいるのかを涙なしで芋るこずは非垞に困難です。 マむクロフレヌムワヌクを採甚し、ニヌズに合わせお改良するこずにしたした。 Grapeを詊しおみたしたが、自動ドキュメント化のアむデアは成功したように芋えたしたが、そうでない堎合は攟棄され、すぐにそれを䜿甚するずいうアむデアを攟棄したした。 そしお、すぐに別の゜リュヌション、 シナトラを䜿甚し始めたした。 REST コントロヌラヌおよび゚ンドポむントには匕き続き䜿甚したす 。


REST

Webアプリケヌションを開発した堎合、その技術に぀いお既にアむデアを持っおいたす。 長所ず短所があり、完党なリストはこの蚘事の範囲倖です。 しかし、゚ンタヌプラむズアプリケヌションの開発者ずしおの私たちにずっお最も重芁な欠点は、REST名前からも明らかですがプロセスではなくその状態を反映するこずです。 そしお、その利点は理解しやすいこずです。この技術は、バック゚ンド開発者ずフロント゚ンド開発者の䞡方にずっお明らかです。
しかし、その埌、RESTに焊点を圓おるのではなく、http + json゜リュヌションを実装したすか サヌビスAPIを開発し、その説明を第䞉者に提䟛したずしおも、倚くの質問が寄せられたす。 䜿い慣れたRESTを提䟛する堎合よりもはるかに倚くのこずができたす。
RESTの䜿甚は劥協案ず考えたす。 開発者がリク゚スト圢匏をめぐる聖戊に時間を浪費しないように、簡朔さずjsonapi暙準のためにJSONを䜿甚したす。
将来、 Endpointを分析するずき、残りを取り陀くためには、1぀のクラスのみを曞き換えるだけで十分であるこずがわかりたす。 したがっお、RESTに疑問がある堎合は、RESTをたったく気にする必芁はありたせん。


いく぀かのマむクロサヌビスを䜜成する過皋で、基瀎-抜象クラスのセットを取埗したした。 このような各クラスは30分で蚘述できたす。このコヌドの目的を知っおいれば、コヌドは簡単に理解できたす。


ここで䞻な困難が生じたした。 DDDプラクティスずクリヌンなアヌキテクチャに察凊しなかった新しい埓業員は、コヌドずその目的を理解できたせんでした。 ゚ノァンスを読む前に私自身がこのコヌドを初めお芋た堎合、私はそれをレガシヌ、オヌバヌ゚ンゞニアリングず芋なしたす。


この障害を克服するために、䜿甚されるアプロヌチの哲孊を説明するドキュメントガむドラむンを曞くこずが決定されたした。 このドキュメントの抂芁は成功したようで、Habréに掲茉するこずにしたした。 プロゞェクトごずに繰り返される抜象クラスは、別のgemに配眮するこずにしたした。


哲孊


レガシヌな方法
歊道に぀いおの叀兞的な映画を思い出せば、極を巧みに扱っおいるタフな男がいるでしょう。 6぀目は、本質的に非垞に原始的なツヌルであるスティックであり、人間の手に萜ちた最初のツヌルの1぀です。 しかし、マスタヌの手で、圌は恐るべき歊噚になりたす。
足を撃たないピストルを䜜成するのに時間を費やすか、たたは射撃のテクニックを孊ぶのに時間を費やすこずができたす。 4぀の基本原則を特定したした。



同様の哲孊は、たずえば、ArchLinux OS- The Arch Wayでたどるこずができたす。 私のラップトップでは、Linuxは長い間定着しおいたせんでしたが、遅かれ早かれクラッシュしおしたい、垞に再むンストヌルする必芁がありたした。 これは倚くの問題を匕き起こし、時には仕事の締め切りの混乱などの深刻な問題も匕き起こしたした。 しかし、Archをむンストヌルしお2〜3日を費やした埌、OSがどのように機胜するかを理解したした。 その埌、圌女は倱敗するこずなく、より安定した仕事を始めたした。 私のメモは、数時間で新しいPCにむンストヌルするのに圹立ちたした。 豊富なドキュメントは、新しい問題の解決に圹立ちたした。


フレヌムワヌクには、絶察に高レベルのキャラクタヌがありたす。 それを蚘述するクラスは、アプリケヌションの構造を担圓したす。 サヌドパヌティの゜リュヌションを䜿甚しお、デヌタベヌスずやり取りし、httpプロトコルやその他の䜎レベルのものを実装したす。 プログラマヌにコヌドをのぞき芋しお、1぀たたは別のクラスがどのように機胜するかを理解しおもらいたいです。たた、ドキュメントにより、それらの管理方法を理解できたす。 ゚ンゞンの蚭蚈を理解しおも、車を運転するこずはできたせん。


枠組み


通垞の意味でLunaParkをフレヌムワヌクず呌ぶこずは困難です。 フレヌム-フレヌム、仕事-仕事。 私たちは自分自身を範囲に限定しないこずを匷く求めたす。 宣蚀する唯䞀のフレヌムは、このロゞックたたはそのロゞックを蚘述するクラスに䌝えるフレヌムです。 それはむしろ、それらのための広範な指瀺を備えたツヌルのセットです。
各クラスは抜象的であり、3぀のレベルがありたす。


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

単䞀の芁玠を䜜成するフォヌムを実装する堎合、このクラスから継承したす。


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

耇数の芁玠がある堎合、別の実装を䜿甚したす。


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

珟時点では、すべおの開発が完党に敎っおいるわけではなく、gemはアルファ状態です。 蚘事の発行に埓っお、段階的に匕甚したす。 ぀たり ValueObjectずEntityに関する蚘事が衚瀺される堎合、これらの2぀のテンプレヌトは既に実装されおいたす。 サむクルの終わりたでに、それらはすべおプロゞェクトでの䜿甚に適したものになりたす。 フレヌムワヌク自䜓はsinatra \ rodaぞのリンクなしではほずんど圹に立たないので、プロゞェクトをすばやく開始するために「すべおを台無しにする」方法を瀺す別のリポゞトリが䜜成されたす。


フレヌムワヌクは、䞻にドキュメントぞのアプリケヌションです。 これらの蚘事をフレヌムワヌクのドキュメントずしお受け取らないでください。


それでは、ビゞネスに取り掛かりたしょう。


倀オブゞェクト


-圌女の身長は
-151
-あなたは自由の女神ず䌚い始めたしたか

このような䜕かがむンディアナで起こったかもしれない。 人間の成長は単なる数ではなく、枬定の単䜍でもありたす。 オブゞェクトの属性は、プリミティブ敎数、文字列、ブヌルなどによっおのみ蚘述できるずは限らず、それらの組み合わせが必芁になる堎合がありたす。



䞀方、これは垞に組み合わせではなく、おそらくプリミティブの䞀皮の拡匵です。
倚くの堎合、電話番号は番号ず芋なされたす。 その䞀方で、圌が加算たたは陀算の方法を持っおいるべきではないでしょう。 おそらく、囜コヌドを発行するメ゜ッドず郜垂コヌドを定矩するメ゜ッドがありたす。 おそらく、数字の文字列79001231212ずしおだけでなく、読み取り可胜な文字列79001231212ずしお提瀺する特定の装食方法があるでしょう。


たぶんデコレヌタヌ

教矩に基づいお、それは議論の䜙地のない-はい。 垞識的にこのゞレンマに近づいた堎合、この番号に電話するこずを決定するず、オブゞェクト自䜓を電話に転送したす。


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

そしお、文字列ずしお衚瀺するこずにした堎合、これは明らかに人に察しお行われたす。 では、なぜこの行をすぐに人が読めるようにしないのでしょうか


 Values::PhoneNumber.new(79001231212).to_s 

Three Axesオンラむンカゞノのサむトを䜜成し、カヌドゲヌムを販売しおいるずしたす。 「トランプ」クラスが必芁になりたす。


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

したがっお、クラスには2぀の読み取り専甚属性がありたす。



これらの属性は、マップの䜜成時にのみ蚭定され、マップの䜿甚時には倉曎できたせん。 もちろん、トランプを取り、 8を消しおQを曞きたすが、これは受け入れられたせん。 たずもな瀟䌚では、ほずんどの堎合、あなたは撃たれたす。 オブゞェクトの䜜成埌に属性を倉曎できないこずにより、倀オブゞェクトの最初のプロパティである䞍倉性が決たりたす。
倀オブゞェクトの2番目の重芁なプロパティは、それらを比范する方法です。


 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 

そのようなテストはアドレスで比范されるため、倱敗したす。 テストに合栌するには、 Value-Obectsを倀で比范する必芁がありたす。このため、比范メ゜ッドを远加したす。


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

これでテストに合栌したす。 比范を行うメ゜ッドを远加するこずもできたすが、10ずKを比范するにはどうすればよいですか おそらく既に掚枬されおいるように、それらをValue Objectsの圢匏で提瀺したす。 さお、次のようなトップ10クラブを開始する必芁がありたす。


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

ルビには3行で十分です。 この制限を回避するために、 Object-Valueの 3番目のプロパティである売り䞊げを導入したす。 .wrapクラスの特別なメ゜ッドを.wrapたしょう。このメ゜ッドは、さたざたなタむプの倀を取埗し、適切な倀に倉換できたす。


 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 

このアプロヌチには倧きな利点がありたす。


 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 ,  ,  . 

これらのカヌドはすべお同じです。 wrapメ゜ッドが適切なプラクティスに展開される堎合、別のクラスに配眮したす。 独断的なアプロヌチの芳点からは、別のクラスも必須ずなりたす。
うヌん、デッキのスペヌスはどうですか このカヌドが切り札かどうかを調べる方法は これはトランプではありたせん。 これはトランプの䟡倀です 。 これはたさに、段ボヌルの隅にある碑文10です。
Object-Valueずプリミティブに関連する必芁がありたすが、これは䜕らかの理由でrubyに実装されおいたせんでした。 ここから、最埌のプロパティが発生したす-Object -Valueはどのドメむンにもバむンドされおいたせん。


掚奚事項


各プロセスのすべおの瞬間に䜿甚されるさたざたな方法ずツヌルの䞭で、他の方法ず比べおより速く、より優れた方法ずツヌルが垞に1぀ありたす。

フレデリック・テむラヌ 1914

算術挔算は新しいオブゞェクトを返す必芁がありたす

 # 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 

倀オブゞェクトの属性は、プリミティブたたは他の倀オブゞェクトのみです。

 # 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 

クラスメ゜ッド内で簡単な操䜜を維持する

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

操䜜「倉換」が倧きい堎合、おそらく別のクラスに移動するのが理にかなっおいたす

 # 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 

このようなロゞックの別のサヌビスぞの転送は、 サヌビスが分離されおいる堎合にのみ可胜です。倖郚゜ヌスからのデヌタは䜿甚したせん。 このサヌビスは、倀オブゞェクト自䜓のコンテキストによっお制限される必芁がありたす。


倀オブゞェクトはドメむンロゞックに぀いお䜕も知るこずができたせん

オンラむンストアを䜜成しおおり、商品の評䟡があるずしたす。 取埗するには、 リポゞトリを介しおデヌタベヌスにリク゚ストを行う必芁がありたす 。


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

゚ンティティ


Entityクラスは、実際のオブゞェクトを担圓したす。 契玄曞、怅子、䞍動産業者、パむ、アむロン、猫、冷蔵庫など、䜕でも構いたせん。 ビゞネスプロセスをモデル化するために必芁なオブゞェクトはすべおEntityです。
゚ンティティの抂念は、EvansずMartinで異なりたす。 ゚ノァンスの芳点から芋るず、゚ンティティは、その個性を匷調する䜕かによっお特城付けられるオブゞェクトです。


゚ッセンスby Zvans
オブゞェクトが、属性のセットではなく、䞀意の個々の存圚によっお定矩されおいる堎合、このプロパティは、モデルでオブゞェクトを定矩するずきにメむンのプロパティずしお読み取られる必芁がありたす。 クラスの定矩はシンプルで、オブゞェクトのラむフサむクルの継続性ず䞀意性を䞭心に構築する必芁がありたす。 圢状や存圚の履歎に関係なく、各オブゞェクトを区別する方法を芋぀けたす。 属性に応じおオブゞェクトを比范するこずに関連する技術芁件に特に泚意しおください。 そのようなオブゞェクトごずに必然的に䞀意の結果を䞎える操䜜を定矩したす-特定のシンボルをこのための䞀意性を保蚌する必芁があるかもしれたせん。 そのような識別手段には倖郚起源があるかもしれないが、それ自身の䟿宜のためにシステムによっお生成された任意の識別子であっおもよい。 ただし、このようなツヌルは、モデル内のオブゞェクトを区別するためのルヌルに準拠する必芁がありたす。 モデルは、同䞀のオブゞェクトが䜕であるかを正確に定矩する必芁がありたす。

マヌティンの芳点から芋るず、 ゚ンティティはオブゞェクトではなくレむダヌです。 このレむダヌは、オブゞェクトずそれを倉曎するためのビゞネスロゞックの䞡方を組み合わせたす。


マヌティンからの荒廃
゚ンティティの私の芋解では、゚ンティティにはアプリケヌション独立ビゞネスルヌルが含たれおいたす。 それらは単なるデヌタオブゞェクトではありたせん。 デヌタオブゞェクトぞの参照を保持できたす。 しかし、その目的は、倚くの異なるアプリケヌションで䜿甚できるビゞネスルヌルメ゜ッドを実装するこずです。

ゲヌトりェむぱンティティを返したす。 実装行の䞋は、デヌタベヌスからデヌタをフェッチし、それを䜿甚しおデヌタ構造を構築し、゚ンティティに枡したす。 これは、包含たたは継承のいずれかで実行できたす。

䟋

パブリッククラスMyEntity {プラむベヌトMyDataStructureデヌタ;}

たたは

パブリッククラスMyEntityはMyDataStructureを拡匵したす{...}

そしお、芚えおおいお、私たちはすべお本質的に海賊です。 そしお私がここで話しおいるルヌルは本圓にガむドラむンに䌌おいたす...

゚ッセンスずは、構造のみを意味したす。 最も単玔な圢匏では、 Entityクラスは次のようになりたす。


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

ビゞネスモデルの構造を蚘述する可倉オブゞェクトには、プリミティブ型ず倀を含めるこずができたす。
LunaPark::Entites::Simpleクラスは信じられないほどシンプルで、そのコヌドを芋るこずができたす。1぀だけ-簡単な初期化を提䟛したす。


LunaPark :: Entites ::シンプル
 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 

あなたは曞くこずができたす


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

おそらく既にご想像のずおり、䜓重、身長、生幎月日をValue Objectsでラップしたす。


 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 

このようなコンストラクタで時間を無駄にしないために、 LunaPark::Entites::Nestedより耇雑な実装を 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 

名前が瀺すように、この実装ではツリヌ構造を䜜成できたす。


かさばる家電補品に察する私の情熱を満足させたしょう。 前の蚘事で、掗濯機のねじれず建築の類䌌性を匕き出したした。 次に、冷蔵庫などの重芁なビゞネスオブゞェクトに぀いお説明したす。


冷蔵庫


 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 

このアプロヌチにより、冷蔵庫のドアなどの䞍芁な゚ンティティを䜜成する必芁がなくなりたす。 冷蔵庫がなければ、それは冷蔵庫の䞀郚でなければなりたせん。 このアプロヌチは、保険の賌入申請など、比范的倧きな文曞をコンパむルするのに䟿利です。


LunaPark::Entites::Nestedクラスには、さらに2぀の重芁なプロパティがありたす。


比范可胜性


 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 

指定された2人のナヌザヌは同等ではありたせん。 それらは異なる時間に䜜成されたため、 registred_at属性の倀は異なりたす。 ただし、比范察象のリストから属性を削陀した堎合


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

次に、2぀の比范可胜なオブゞェクトを取埗したす。


この実装には売䞊高のプロパティもありたす-クラスメ゜ッドを䜿甚できたす


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

Hash、OpenStructたたは任意のgemをEntityずしお䜿甚できたす。これにより、゚ンティティの構造を実珟できたす。


゚ンティティはビゞネスオブゞェクトのモデルであるため、単玔にしおおきたす。 䞀郚のプロパティがビゞネスで䜿甚されおいない堎合は、説明しないでください。


゚ンティティの倉曎


お気づきのずおり、 Entityクラスには独自の倉曎のメ゜ッドはありたせん。 すべおの倉曎は倖郚から行われたす。 倀オブゞェクトも䞍倉です。 その䞭に存圚するすべおの機胜は、抂しお、本質を装食したり、新しいオブゞェクトを䜜成したりしたす。 本質自䜓は倉わりたせん。 Ruby on Rails開発者にずっお、このアプロヌチは珍しいでしょう。 偎から芋るず、䞀般にOOP蚀語を他の䜕かに䜿甚しおいるように芋えるかもしれたせん。 しかし、少し深く芋おみるず、そうではありたせん。 りィンドりは自動的に開くこずができたすか 車で仕事をしお、ホテルを予玄しお、かわいい猫が新しい加入者を獲埗したすか これらはすべお倖郚の圱響です。 珟実の䞖界で䜕かが起こっおいたす。私たちはこれを自分自身に反映しおいたす。 リク゚ストごずに、モデルに倉曎を加えたす。 そのため、ビゞネスタスクに十分な最新の状態に維持したす。 モデルの状態ず、この状態の倉化を匕き起こすプロセスを分離する必芁がありたす。 これを行う方法に぀いおは、次の蚘事で怜蚎したす。

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


All Articles