Back to site
Since 2004, our University project has become the Internet's most widespread web hosting directory. Here we like to talk a lot about web servers, web development, networking and security services. It is, after all, our expertise. To make things better we've launched this science section with the free access to educational resources and important scientific material translated to different languages.

Pravilan način kodiranja DCI kod Ruby

Mnogi članci u Ruby zajednici mnogo pojednostavljuje upotrebu DCI. Ti članci, uključujući i moj , podvlače upotrebu DCI kod Roles objekata rutine, ključne stvari DCI arhitekture. Mnogi ppstovi koji se odnose na DCI su na sledeći način:

class User; end # Data
module Runner # Role
  def run
    ...
  end
end

user = User.new # Context
user.extend Runner
user.run

Ima nekoliko mana koje se pojavljuju u datim primerima. Prvo, čita se “kako dečifrovati DCI”. DCI je više od objekta. Drugo, podvalči se #extend dodajući metodu objekata u vremenu. U ovom članku, voleo bih da odredim adresu kod sledećih pitanja: DCI iza postojećih objkeata. Sledeći post sadrži umanjenu tehniku kod Roles u objekte upotrebom #extend i obrnuto.

DCI (Data-Context-Interaction)

Kao što je pre naglašeno, DCI je više od objekta. Tu se skuplja kraj uprebom modela i rekonstrukcijom održivog koda. Unutar → pristupa, slično sa BDD, gde smo posatrali korisnika kao prvog i poslednjeg modela. Kod spoljašnjeg → pristup je jedan od razloga što volim arhitektruu: dobro se uklapa u BDD stil, koji dalje promoviše testiranost.

Važna stvar je poznavati DCI koji je više od koda. On je o procesiuranju i ljudima. Počinje princippima iza Agile i Leani čiri se na one koji imaju kod. Ima i sami benefit od ovog DCI koji se lepo slaže uz Agile i Lean. Sve je o održivosti koda, koji je odgovoran, ili je u pitanju dekompresija koja radi (funkcionalnost) iz sitema datog (model podataka).

Uzimam ponašanje koje implementira DCI u Rails aplikaciju, počinjući sa Interactions i dalje na Data model. Većinom, pišem kod prvo pa ga onda testiram. Naravno, kada dobro tazumete ponašanje DCI, možete pprvo da pišete testove. Nemam razmišljanje o prvo test pa ostalo stavu, ali to određuje sam koncept.

Korisničke priče

Korisničko mišljenje je važan deo karakteristika DCI koji je dovoljan da na pravi način predstavi proizvod. To je početna tačka definisanja. Lepota početka sa ovim pričama je ta da se sve uklapa sa Agile procesom. Tipično, počećemo priču tako što definišemo krajnjeg korisnika. Pojednostavljena priča izgleda ovako:

"As a user, I want to add a book to my cart."

Trenutno, imamo divnu ideju o karakteristikama koje implementiramo.

Pored toga:formalna implementacija DCI zahteva premeštanje cele priče. Tada je uzor taj koji daje više objašnjenja o inputu, autputu, ulogama, itd.

Napišite test

Trebalo bi do sada da imamo dovoljno materijala da možemo napisati test. hajde da upotrebimo RSpec i Capybara :

spec/integration/add_to_cart_spec.rb

describe 'as a user' do
  it 'has a link to add the book to my cart' do
    @book = Book.new(:title => 'Lean Architecture')
    visit book_path(@book)
    page.should have_link('Add To Cart')
  end
end

U duhu BDD, počećemo tako što ćemo da definišemo domen model (naš Data). Znamo da Book sadrži title atribut. U duhu DCI, identifikovali smo Context kada upotrebljavamo Actors što je ključno. Context se dodaje. Actor identifikuje User.

Realistično, dodajemo više testova na dalje korice karakteristikama koje su sporedne.

"Roles"

Actors igraju Roles.za određene stvari stvarno imamo jednog Actor, User. User igra Role kupca koji dodaje neke proizvode u korpu. Roles opisuju algoritme koji se koriste da bi definisali ulogu.

Hajde da to kodiramo:

app/roles/customer.rb

module Customer
  def add_to_cart(book)
    self.cart << book
  end
end

Stvaranje Customer Role pomoglo je da dobijemo više Data model, User. Znamo da nam je potreban #cart metod na bilo kom Data objektu koji igra ulogu Customer Role.

Customer uloga koje se gore definiše ne objašnjava mnogo #cart. Jednu sam odluku doneo zarad jednostavnosti pre mnogo vremena, da ubacim bazu podataka umesto samo jednu sesiju, #cart metod defininiše bilo koji Actor kod Customer Role što ne bi trebalo biti elaborat implementacija uloge. Samo dolazim do jednostavnih zaključaka.

Roles su dobre sa polimorfizmom. Customer Role se može igrati na bilo kom objektu koji odgovara #cart metodi. Role sada naju koji tip jeste argument, ostavljajući taj opis u Context.

Napišite test

hajde da se malo vratimo i napišemo neki test za Role.

spec/roles/customer_spec.rb

describe Customer do
  let(:user) { User.new }
  let(:book) { Book.new }

  before do
    user.extend Customer
  end

  describe '#add_to_cart' do
    it 'puts the book in the cart' do
      user.add_to_cart(book)
      user.cart.should include(book)
    end
  end
end

Ovaj test pokazuje na koji način Role, Customer, u okviru Context, dodajući ulogu, funkcionišu.

"Context"

DCI, Context je okruženje Data objekata koji izvršavaju Roles. Ima uvek samo jedan Context za svaku priču. Zavisno od kompleksnosti priče, može pstojati više od jednog Context ikoji povezuje Roles (šta sistem radi) Data objektima (šta sistem jeste).

Kod ovog dela, znamo da će se upotrebljavati Role, Customer, i imamo jaku ideju o Data objektima i User.

Hajde da kodiramo:

app/contexts/add_to_cart_context.rb

class AddToCartContext
  attr_reader :user, :book

  def self.call(user, book)
    AddToCartContext.new(user, book).call
  end

  def initialize(user, book)
    @user, @book = user, book
    @user.extend Customer
  end

  def call
    @user.add_to_cart(@book)
  end
end

Ažuriranje: Jim Coplien implementacija Contexts korisnika AddToCartContext#execute kao pokretač sadržaja. Da bi se podržali Ruby idiomi, proces i lambdas,primeri su promenjeni u AddToCartContext#call.

Ključne karakteristike:

  • Context se definiše kao klasa. Ima ulogu klase i odaziva se na #call metodu poznatu kao triggering.
  • Imajući klasnu metodu AddToCartContext.call je jednostavno dobra metoda.
  • Osnova DCI je u @user.extend Customer. Augmentovanje Data objekata sa Roles ad hoc ije ono što dovodi do dupliranja, Ima milion načina da se Roles ubace u objekat, #extend. U sledećem članku, pokazaću vam druge načine pomoću kojih možete ovo postići.
  • Prebacujući Context može se doći do Role metode. Ako želimo pomoć, moraćemo da prihvatimo user_id i book_id u Context i da dozvolimo Context objekata.
  • Context mora da nađe Actors. U slučaju attr_reader koristi se @user i @book. @book nije Actor u Context, bez obzira koliko tot ako izgledalo.
  • Najvažnije: Trebalo bi da se oslonite na #unextend Role objekta. Data objekat će obično biti stavljen na Role u trenutku Context. Ima samo jedan Context za pokazivanje (napomena: po slučaju, ne po priči). Zato, oslanjamo se na uvođenje novih funkcionalnosti i uvođenju kolizija. DCI, je prihvatljivo manipulator Roles u objekte datog Context. Zato je problem kolizija do koje još dolazi ali bi trebalo učestalost da se smanji.

Napišite test

Pobornik sam ruganju i preispitivanju ali ne mislim da bi i ovde to trebalo uraditi jer je Contexts već precaio svoj kod u Role odrednice. Sada samo testiramo intergraciju.

spec/contexts/add_to_cart_context_spec.rb

describe AddToCartContext do
  let(:user) { User.new }
  let(:book) { Book.new }

  it 'adds the book to the users cart' do
    context = AddToCartContext.new(user, book)
    context.user.should_recieve(:add_to_cart).with(context.book)
    context.call
  end
end

Glavni cilj jeste pozvati #add_to_cart metodu sa pravim argumentima. Ovo uradimo tako što se setimo primera kod Actor zajedno sa AddToCartContext kada imamo #add_to_cart metodu nazvanu book argument.

Nema više DCI. Brinemo o Interaction izmežu objekta i Context kada imaju interakciju. Najvažniji kod je već napisan. Samo je ostao Data.

"Data"

Data bi trebalo da je slim. Bolje rečeno: "Data objekat interfejsa jeste jednostavan i minimalan: dovoljan da uhvati domen vlasništva, ali bez određenih operacija koje su jednistvene u svakom određenom scenariju” (Lean Architecture). Data bi trebalo da se odnosi na određenom metodu, koji nikada nema uticaj podataka koji se koriste. hajde da pogledamo metodu Book modela koji smo već testirali na bazičnim atributima.

class Book < ActiveRecord::Base
  validates :title, :presence => true
end

Nema metode. Samo klasna definicija, asocijacija i validnost. Način na koji se Book upotrebljava trebalo bi da bude Book model. Trebalo bi da napišemo neke testove oko istog modela, kao što je i pitanje. Testiranje validacije i asocijacije jetse standard i nema tu nikakve rasprave.

Održavajte vaš Data na nivou.

Uklapanje

Nema mnogo da se kaže oo uklpanju ovog koda u Rails. Jednostavno, stavićemo Context u Controller.

app/controllers/book_controller.rb

class BookController < ApplicationController
  def add_to_cart
    AddToCartContext.call(current_user, Book.find(params[:id]))
  end
end

Evo ga diagram koji pokazuje kako DCI pristaje Rails MVC. Context postaje izlaz za korisnički interfejs i model podataka.

MVC + DCI

Šta smo uradili

Sledeće opravdava ceo članak, ali takođe i želim da na kratko pogledam u strukturalni kod DCI.

  • Primorani smo da pogledamo funkcionalnost sistema i kako se podaci strukturiraju. To nam dodaje benefit kompresije i lake polimorofizacije.
  • Napravili smo čitljivi kod. Lako je rezonovati kada je u pitanju kod i algoritam koji se nalazi u okviru njega. Veoma je dobro sve organizovano. Pogledajte Uncle Bob gripe o čitljivost.
  • Naš Data model, kada sistem je, može biti stabilan dok smo u progresu i refaktorisanju Roles, kada sistem radi.
  • Približili smo se predstavljanju krajnjeg korisnika mentalnog modela. To je glavni cilj MVC, nešto što se otkrije vremenom.

Dodajemo još jedan sloj kompleksnosti, da. Moramo da održavamo Contexts i Rolesna vrhu tradicionalnog MVC. Contexts, naročito kod postojećeg koda. Ipak, ovim se postiže veliki prosperitet. Kao programer i vođa tima, oslanjam se na ove benefite iz raloga što je to vaš posao i povezivanje poslovanja.

Finalne reči

Problemi sa DCI postoje. Prvo, zahteva menjanje paradigme. Dizajniran je komplementima MVC (Model-View-Controller) tako da se uklapa u Railsali i zahteva vaš potez koda van kontrolora i modela. Kao što je poznato, Rails zajednica ima fetiš stavljanja koda u modele i kontrolore. Paradigma pomeranja je ta da nešto što zahteva veliki potez ima nekoliko aplikacija. ipak, DCI može da refaktoriše samo klasu po klsau bazičnih aplikacija koje se malo po malo menjaju sa “debelog primera, na mršavog kontrolora”, Drugo, potentcijalno nosi degradaciju performansa , zahvaljujući činjenici da se objekti pomeranju ad hoc.

Glavni benefit DCI jeste odnos Ruby zajednicom koja mu daje srtukturu u diskusiji glavnog domena “debelog primera, na mršavog kontrolora”, tako da se kod ne stavlja u kontrolor OR modela beć negde drugo. Problem kod pakovanja je vođenje operacije gde bi naš kod trebalo da živi i način na koji je strukturisan. Ne želimo ga u modelu, ne želimo ga u kontroloru, i ne želimo ga svakako na putu. Najviše, i samo praćenje ovih upstava vodi ka konfuziji, prerangiranju i nedostatku doslednosti. DCI nam daje otisak raspada Rails modle i stavranja održivog, testiranog i raspoloživog koda.

Pored toga: Postoji još radova u ovoj oblasti. Avdi Grimm ima fenomenalnu knjigu koja se zove Objects on Rails koja vam nudi i neka dodatna rešenja.

Srećno u arhitekturi!!





Published (Last edited): 11-06-2013 , source: http://mikepackdev.com/blog_posts/24-the-right-way-to-code-dci-in-ruby