Verkkosivustosi etenee ja kasvat nopeasti. Ruby / Rails on paras ohjelmointivaihtoehto. Tiimisi on isompi ja jätit jo käsitteen 'rasvaiset mallit, ohuet kuljettajat' ( rasvamallit, laihat kontrollerit ) Rails-sovellusten suunnittelutyylinä. Et kuitenkaan silti halua lopettaa kiskojen käyttöä.
Ei ongelmaa. Tänään keskustelemme siitä, miten OOP: n parhaiden käytäntöjen avulla voit tehdä koodistasi puhtaamman, eristetyn ja erillisen.
Aloitetaan katsomalla, kuinka sinun pitäisi päättää, onko hakemuksesi hyvä ehdokas refactoringiin.
Tässä on luettelo mittareista ja kysymyksistä, jotka yleensä kysyn itseltäni sen selvittämiseksi, tarvitsevatko koodini uudelleen.
Yritä käyttää jotain tällaista saadaksesi selville, kuinka monta riviä Ruby-lähdekoodia sinulla on:
find app -iname '*.rb' -type f -exec cat {} ;| wc -l
Tämä komento etsii kaikki tiedostot, joiden .rb-laajennus (rubiinitiedostot) on / app-kansiossa, ja tulostaa sitten rivien määrän. Huomaa, että tämä luku on vain arvio, koska kommenttirivit sisällytetään tähän kokonaismäärään.
Toinen tarkempi ja informatiivisempi vaihtoehto on käyttää tehtävää harava stats
Rails, joka paljastaa nopean yhteenvedon koodiriveistä, luokkien lukumäärästä, menetelmien lukumäärästä, menetelmien suhde luokkiin ja koodirivien suhde menetelmää kohti:
*bundle exec rake stats* +----------------------+-------+-----+-------+---------+-----+-------+ | Nombre | Líneas | LOC | Clase | Método | M/C | LOC/M | +----------------------+-------+-----+-------+---------+-----+-------+ | Controladores | 195 | 153 | 6 | 18 | 3 | 6 | | Helpers | 14 | 13 | 0 | 2 | 0 | 4 | | Modelos | 120 | 84 | 5 | 12 | 2 | 5 | | Mailers | 0 | 0 | 0 | 0 | 0 | 0 | | Javascripts | 45 | 12 | 0 | 3 | 0 | 2 | | Bibliotecas | 0 | 0 | 0 | 0 | 0 | 0 | | Controlador specs | 106 | 75 | 0 | 0 | 0 | 0 | | Helper specs | 15 | 4 | 0 | 0 | 0 | 0 | | Modelo specs | 238 | 182 | 0 | 0 | 0 | 0 | | Petición specs | 699 | 489 | 0 | 14 | 0 | 32 | | Routing specs | 35 | 26 | 0 | 0 | 0 | 0 | | Vista specs | 5 | 4 | 0 | 0 | 0 | 0 | +----------------------+-------+-----+-------+---------+-----+-------+ | Total | 1472 |1042 | 11 | 49 | 4 | 19 | +----------------------+-------+-----+-------+---------+-----+-------+ Código LOC: 262 Prueba LOC: 780 Ratio Código a Prueba: 1:3.0
Aloitetaan tosielämän esimerkistä.
Oletetaan, että haluamme kirjoittaa sovelluksen, joka seuraa säätä lenkkeilijöille; Pääsivulla käyttäjä voi nähdä syötetyt ajat.
Jokaisella aikamerkinnällä on päivämäärä, etäisyys, kesto ja asiaankuuluvat lisätiedot (esim. Sää, maastotyyppi jne.) Sekä keskinopeus, joka voidaan laskea tarvittaessa.
Tarvitsemme raportin, joka näyttää keskimääräisen nopeuden ja matkan viikossa. Jos keskimääräinen nopeus sisäänkäynnillä on suurempi kuin keskimääräinen nopeus yhteensä, ilmoitamme asiasta käyttäjälle tekstiviestillä (tässä esimerkissä käytämme Nexmo RESTful-sovellusliittymä lähettää tekstiviestin).
Pääsivulla voit valita juoksumatkan, päivämäärän ja kellonajan, jotta voit luoda samanlaisen merkinnän:
Meillä on myös estadísticas
-sivu, joka on pohjimmiltaan viikoittainen raportti, joka sisältää keskimääräisen nopeuden ja kuljetun matkan viikossa.
aplicación
-Hakemistorakenne näyttää samanlaiselta kuin tämä:
⇒ tree . ├── assets │ └── ... ├── controllers │ ├── application_controller.rb │ ├── entries_controller.rb │ └── statistics_controller.rb ├── helpers │ ├── application_helper.rb │ ├── entries_helper.rb │ └── statistics_helper.rb ├── mailers ├── models │ ├── entry.rb │ └── user.rb └── views ├── devise │ └── ... ├── entries │ ├── _entry.html.erb │ ├── _form.html.erb │ └── index.html.erb ├── layouts │ └── application.html.erb └── statistics └── index.html.erb
En keskustele mallista Usuario
koska se ei ole mitään epätavallista, koska käytämme sitä Motto todennuksen toteuttamiseksi.
Mallin Entrada
osalta se sisältää sovelluksemme liiketoimintalogiikan.
Kukin Entrada
kuuluu ryhmään Usuario
.
Vahvistamme jokaisen syötteen distancia
, períodode_tiempo
, fecha_hora
ja estatus
.
Joka kerta, kun luomme merkinnän, verrataan käyttäjän keskinopeutta järjestelmän kaikkien käyttäjien keskiarvoon ja ilmoitetaan käyttäjälle tekstiviestillä Nexmo (Emme keskustele siitä, miten Nexmo-kirjastoa käytetään, vaikka halusin osoittaa tapauksen, jossa käytämme ulkoista kirjastoa).
Huomaa, että Entrada
malli sisältää enemmän kuin pelkkä liiketoimintalogiikka. Se käsittelee myös joitain validointeja ja puheluita.
entries_controller.rb
on osakkeita JULMA tärkein (tosin ilman päivitystä). EntriesController#index
hakee nykyisen käyttäjän merkinnät ja lajittelee tietueet luomispäivämäärän mukaan, kun taas EntriesController#create
luo uusi merkintä. Ei tarvitse keskustella EntriesController#destroy
: n ilmeisistä asioista tai vastuista :
Vaikka statistics_controller.rb
vastaa viikkoraportin laskemisesta StatisticsController#index
hakee sisäänkirjautuneen käyttäjän syötteet ja ryhmittelee ne viikkojen mukaan #group_by
joka on luokassa Lukuisia julkaisussa Rails. Yritä sitten koristella tuloksia yksityisillä menetelmillä.
Emme keskustele näkemyksistä paljon täällä, koska lähdekoodi on itsestään selvä.
Alla on näkymä sisäänkirjautuneen käyttäjän (index.html.erb
) merkintöjen luetteloon. Tätä mallia käytetään hakemistotoiminnon (menetelmän) tulosten näyttämiseen syöttökäsittelijässä:
Huomaa, että käytämme render @entries
Osittainen, jaetun koodin saattamiseksi osittaiseksi malliksi _entry.html.erb
jotta voimme pitää koodimme KUIVA ja uudelleenkäytettävä:
Sama koskee a _forma
osittainen. Sen sijaan, että käyttäisimme samaa koodia (uusien ja muokattujen) toimintojen kanssa, luomme uudelleenkäytettävän osamuodon:
Viikkoraporttisivun näkymän osalta statistics/index.html.erb
näyttää joitain tilastoja ja raportoi käyttäjän viikkotoiminnoista ryhmittelemällä joitain merkintöjä:
Ja lopuksi auttaja syötteille entries_helper.rb
sisältää kaksi auttajia readable_time_period
ja readable_speed
jonka pitäisi tehdä ominaisuuksista helpompi lukea:
Mikään ei ole vielä liian monimutkaista.
Suurin osa teistä voi väittää, että tämän muuttaminen on periaatteen vastaista SUUDELLA ja se tekee järjestelmästä monimutkaisemman.
Joten onko tätä sovellusta todella uudistettava?
Ehdottomasti ei , mutta tarkastelemme sitä vain otantatarkoitusta varten.
Loppujen lopuksi, jos tarkastellaan seuraavaa osaa ja ominaisuuksia, jotka osoittavat, että sovellus tarvitsee refaktorointia, käy selväksi, että esimerkissämme oleva sovellus ei ole kelvollinen ehdokas refaktorointiin.
Aloitetaan selittämällä rakennemalli MVC julkaisussa Rails.
Se alkaa yleensä hakukoneella tekemällä pyyntö, kuten https://www.toptal.com/jogging/show/1
.
Verkkopalvelin vastaanottaa pyynnön ja käyttää rutas
määritellä mikä controlador
käyttää.
Ohjaimet analysoivat käyttäjien pyyntöjä, tiedonsiirtoja, evästeitä, istuntoja jne. Ja kysyvät sitten modelo
saada tiedot.
modelos
Ne ovat Ruby-luokkia, jotka keskustelevat tietokannan kanssa, tallentavat ja vahvistavat tiedot, toteuttavat liiketoimintalogiikkaa ja tekevät raskaan nostamisen. Näkymät ovat mitä käyttäjät voivat nähdä: HTML, CSS, XML, Javascript, JSON.
Jos haluamme näyttää Rails-elinkaaripyynnön järjestyksen, se näyttää tältä:
Haluan saavuttaa lisäämällä abstraktiota käyttämällä PORO: ita ja tekemällä kuviosta jotain seuraavanlaista create/update
-toiminnoille:
Ja jotain vastaavaa tähän toimintoihin list/show
:
Lisäämällä PORO-abstraktit varmistamme vastuiden täydellisen erottamisen SIRPPI , jotain, jota Rails ei hallitse täysin.
Uuden suunnittelun saavuttamiseksi käytän alla olevia ohjeita, mutta pidä mielessä, että nämä eivät ole sääntöjä, joita sinun on noudatettava kirjeeseen. Ajattele niitä joustavina ohjeina, jotka helpottavat uudelleenrakentamista.
ActiveRecord-mallit voivat sisältää assosiaatioita ja vakioita, mutta ei mitään muuta. Tämä tarkoittaa, että puheluja ei ole (käytä palveluobjekteja ja lisää puhelut sinne) eikä vahvistuksia (käyttö Muodosta esineitä sisällyttää mallin nimet ja validoinnit).
Pidä ohjaimet ohuina kerroksina ja kutsu aina huolto-esineitä. Jotkut teistä saattavat miettiä, miksi käyttää ohjaimia, jos haluamme jatkaa palveluobjektien soittamista logiikan sisällyttämiseksi? Ohjaimet ovat hyvä paikka reititys HTTP, parametrien jäsentäminen, todennus, sisällön neuvottelu, oikean palvelu- tai muokkausobjektin kutsuminen, poikkeusten saaminen, vastausten muotoilu ja oikean HTTP-koodin tilan palauttaminen.
Kyselyt tulisi tehdä esineillä kysely . Objektimenetelmät Kysely on palautettava esine, a hash tai taulukko , mutta ei ActiveRecord-yhdistystä.
Vältä käyttöä Auttajat , käytä paremmin sisustajia. Miksi? Yhteinen vaikeus auttajia Railsissa on, että niistä voidaan tehdä joukko ei- OO , jotka jakavat tilan nimen ja ovat päällekkäisiä. Mutta se on paljon pahempaa, että mitään polymorfismia ei voida käyttää auttajia Kiskot - tarjoamalla erilaisia toteutuksia eri yhteyksille tai tyypeille ja ohittamalla tai aliluokittelemalla avustajia. Mielestäni sellaisia auttaja kiskoissa niitä tulisi yleensä käyttää hyödyllisyysmenetelmiin, ei erityisiin käyttötapauksiin; kuinka muotoilla mallimääritteet mille tahansa esityslogiikalle. Pidä ne kevyinä ja helposti seurattavina. Sisustajat / edustajat paremmin. ** Miksi? Loppujen lopuksi huolet näyttävät olevan osa kiskoja, ja ne voivat kuivua ( Kuivua ) koodi, kun se jaetaan useiden mallien välillä. Suurempi ongelma on kuitenkin se, että huolenaiheet eivät tee mallista yhtenäisempää. Vain koodi on paremmin järjestetty. Toisin sanoen mallin sovellusliittymässä ei ole todellisia muutoksia.
Yritä purkaa Arvokkaita esineitä malleista pitämään koodisi puhtaampana ja ryhmään liittyvät määritteet.
Ennen kuin aloitan, haluan keskustella jostakin muusta. Kun refaktorointi alkaa, päädyt yleensä miettimään: 'Onko se hyvä refaktorointi?'
Jos sinusta tuntuu, että erotat tai eristät enemmän vastuuta (vaikka se merkitsisi lisää koodia ja uusia tiedostoja), tämä on hyvä asia. Loppujen lopuksi sovelluksen irrottaminen on erittäin hyvä käytäntö ja helpottaa oikean yksikötestin suorittamista.
En aio keskustella asioista, kuten logiikan siirtämisestä ohjaimista malleihin, koska oletan, että teet sen ja olet mukava käyttää kiskoja (yleensä Skinny Controller- ja FAT-malli).
Jotta tämä artikkeli olisi tiivis, en aio keskustella testaamisesta, mutta se ei tarkoita, että sinun ei pitäisi testata.
Päinvastoin, sinun pitäisi aloita aina testillä varmistaaksesi, että asiat menevät hyvin, ennen kuin siirryt eteenpäin. Tämä on jotain edellytetään, varsinkin kun teet refaktorointia.
Voimme sitten toteuttaa muutoksia ja varmistaa, että testit käyvät läpi koodin asiaankuuluvat osat.
Ensinnäkin, mikä on arvokas kohde?
Martin Fowler Selittää:
Arvoobjekti on pieni esine, kuten raha- tai ajanjaksoobjekti. Niiden keskeinen piirre on, että he seuraavat arvosemantiikkaa eikä viitteellistä semantiikkaa.
Joskus saatat joutua tilanteeseen, jossa käsite ansaitsee oman abstraktinsa ja jossa sen tasa-arvo ei perustu arvoihin, vaan identiteettiin. Esimerkkejä tästä voivat olla: Rubyn päivämäärä, URI ja polun nimi. Arvokkaan objektin (tai verkkotunnusmallin) purkaminen on erittäin kätevää.
Miksi vaivautua?
Yksi arvo-objektin suurista eduista on, että ne auttavat saamaan koodissasi ilmeikkyyden. Koodisi on yleensä selkeämpi tai ainakin se voi olla, jos sinulla on hyvät nimeämiskäytännöt. Koska arvoobjekti on abstraktio, se johtaa selkeämpiin koodeihin ja vähemmän virheitä.
Toinen voitto on muuttumattomuus . Esineiden muuttumattomuus on erittäin tärkeää. Kun tallennamme tiettyjä tietojoukkoja, joita voidaan käyttää arvoobjektissa, en yleensä pidä siitä, että tietoja manipuloidaan.
Milloin tämä on hyödyllistä?
Tähän kysymykseen ei ole täydellistä vastausta. Tee se, mikä on sinun eduksi ja mikä on järkevintä tietyssä tilanteessa.
Tämän lisäksi on joitain ohjeita, joiden avulla autan minua tekemään päätöksen.
Jos luulet, että joukko menetelmiä liittyy toisiinsa, arvoesineiden kanssa se on kalliimpaa. Tämä ilmeikkyys tarkoittaa, että arvo-objektin tulisi edustaa erottuvaa tietojoukkoa, jonka keskimääräinen kehittäjäsi voi päätellä vain katsomalla objektin nimeä.
Miten teet tämän?
Arvoesineiden tulisi noudattaa tiettyjä sääntöjä:
Esimerkissämme luon arvo-objektin EntryStatus
abstraktien attribuuttien Entry#status_weather
ja Entry#status_landform
omalle luokalleen, joka näyttää tältä:
Huomaa: Tämä on vain PORO (Plain Old Ruby Object), se ei peri ActiveRecord::Base
Olemme määrittäneet määritteillemme lukijametodit ja määrittelemme ne käynnistyksen yhteydessä. Lisäksi käytämme vertailukelpoista sekoitusta objektien sovittamiseen () -menetelmällä.
Voimme muokata mallia Entry
käyttää luomamme arvo-objektia:
Voimme myös muokata menetelmää EntryController#create
käyttää uutta arvo-objektia vastaavasti:
Mikä on palveluobjekti?
Palveluobjektin tehtävänä on pitää koodia tietyssä liiketoimintalogiikan tilassa. Toisin kuin tyyli 'Rasvamalli' , jossa pieni määrä objekteja sisältää monia, monia menetelmiä, kaikkeen tarvittavaan logiikkaan nähden, palveluobjektien käyttäminen johtaa moniin luokkiin, joista jokaisella on ainutlaatuinen tarkoitus.
Miksi? Mitä hyötyä siitä on?
Vetää erilleen. Palveluobjektit auttavat sinua saavuttamaan suuremman eristyksen esineiden välillä.
Näkyvyys. Palveluobjektit (jos ne on nimetty oikein) osoittavat, mitä sovellus tekee. Voin selata palveluhakemistoa nähdäksesi, mitä ominaisuuksia sovellus tarjoaa.
KUIVA ja hyväksy muutos. Pidän palvelutarvikkeet mahdollisimman yksinkertaisina ja pieninä. Sävelen palveluobjektit muiden palveluobjektien kanssa ja käytän niitä uudelleen.
Puhdista ja nopeuta testipakettiasi. Palvelut ovat nopeita ja helppoja testata, koska ne ovat pieniä Ruby-esineitä, joilla on lähtökohta (kutsuttua menetelmää). Monimutkaiset palvelut koostuvat muista palveluista, joten voit helposti erottaa testit. Palveluobjektien käyttö helpottaa myös toisiinsa liittyvien objektien hakemista ilman, että sinun on ladattava koko kiskoympäristöä.
Toisaalta mikään ei ole täydellistä. Yksi palveluobjektien haittapuoli on, että ne voivat olla ylenmääräisiä jokaisesta pienestä toiminnasta. Näissä tapauksissa voit lopulta vaikeuttaa koodiasi eikä yksinkertaistaa sitä.
Milloin sinun on purettava palveluobjektit?
Myöskään tässä ei ole kiinteää sääntöä.
Palveluobjektit ovat tyypillisesti parhaita keskisuurille ja suurille järjestelmille: niille, joilla on kohtuullinen logiikka, tavallisten CRUD-toimintojen lisäksi.
Joten kun luulet, että koodikappale ei kuulu hakemistoon, paikassa, johon aiot lisätä sen, on hyvä harkita sitä uudelleen ja nähdä, olisiko parempi, jos se menisi palveluobjektiin.
Seuraavassa on joitain ohjeita siitä, milloin palveluobjekteja käytetään:
Kuinka sinun tulisi suunnitella palveluobjekteja?
Palveluobjektin luokan suunnittelu on suhteellisen yksinkertaista, koska et tarvitse sitä helmiä sinun ei pitäisi oppia a DLS uusi, mutta voit enemmän tai vähemmän luottaa jo hallussasi oleviin ohjelmistosuunnittelutaidoihin.
Yleensä käytän seuraavia ohjeita ja käytäntöjä palveluobjektin suunnittelussa:
app/services
. Kehotan sinua käyttämään alihakemistoja vahvojen liiketoimintalogiikan verkkotunnusten osalta. Esimerkiksi tiedosto app/services/report/generate_weekly.rb
määrittelee Report::GenerateWeekly
kun taas app/services/report/publish_monthly.rb
määrittelee Report::PublishMonthly
.ApproveTransaction
, SendTestNewsletter
, ImportUsersFromCsv
.Jos tarkastelet StatisticsController#index
, huomaat joukon menetelmiä (weeks_to_date_from
, weeks_to_date_to
, avg_distance
jne.) Ryhmiteltyinä ohjaimeen. Tuo ei ole hyvä. Harkitse seurauksia, jos haluat luoda viikkoraportin statistics_controller
: n ulkopuolella.
Meidän tapauksessamme aiomme luoda Report::GenerateWeekly
ja poimi logiikkaraportti StatisticsController
:
Joten StatisticsController#index
nyt se näyttää puhtaammalta:
Soveltamalla Service-objektikuviota ryhmittelemme koodin monimutkaisen ja spesifisen toiminnan ympärille ja edistämme pienempien ja selkeämpiä menetelmiä.
Kotitehtävät: harkitse käyttöä Arvokas esine varten WeeklyReport
Struct
: n sijaan .
Mikä on esine Kysely ?
Esine Kysely on PORE, joka edustaa kyselytietokantaa. Sitä voidaan käyttää uudelleen sovelluksen eri paikoissa piilottaen samalla kyselylogiikka. Se tarjoaa myös hyvän eristetyn yksikön testausta varten.
Sinun tulisi purkaa monimutkaiset SQL / NoSQL-kyselyt omiin luokkiinsa.
Jokainen esine Kysely on vastuussa tulosten palauttamisesta kriteerien / liiketoimintasääntöjen perusteella.
Tässä esimerkissä meillä ei ole kyselyä ( kysely ) monimutkainen, joten käytä objektia Kysely se ei olisi tehokasta. Esittelyä varten haemme kyselyn kuitenkin Report::GenerateWeekly#call
-sivulta ja luomme generate_entries_query.rb
:
Korvataan Report::GenerateWeekly#call
: ssa:
def call @user.entries.group_by(&:week).map do |week, entries| WeeklyReport.new( ... ) end end
kanssa:
def call weekly_grouped_entries = GroupEntriesQuery.new(@user).call weekly_grouped_entries.map do |week, entries| WeeklyReport.new( ... ) end end
Objektikuvio kysely (kysely) auttaa pitämään mallilogiikkasi tiukasti luokan käyttäytymisessä pitäen samalla ohjaimesi laihana. Koska ne eivät ole muuta kuin tavalliset vanhat Ruby-luokat , esineet kysely heidän ei tarvitse periä ActiveRecord::Base
: sta, ja heidän pitäisi olla vastuussa vain kyselyn suorittamisesta.
Nyt aiomme purkaa uuden merkinnän luomisen logiikan uuteen palveluobjektiin. Käytetään käytäntöä ja luodaan CreateEntry
:
Ja nyt EntriesController#create
on seuraava:
def create begin CreateEntry.new(current_user, entry_params).call flash[:notice] = 'Entry was successfully created.' rescue Exception => e flash[:error] = e.message end redirect_to root_path end
Nyt asiat alkavat tulla mielenkiintoisemmiksi.
Muista, että ohjeissamme sovimme, että halusimme malleihin assosiaatioita ja vakioita, mutta ei mitään muuta (ei validointeja tai kutsuja). Joten aloitetaan poistamalla huomiotekstit ja käyttämällä sen sijaan Shape-objektia.
Shape-objekti on PORO (Plain Old Ruby Object). Ota ohjain / palveluobjekti komentoon, kun haluat puhua tietokannan kanssa.
Miksi käyttää Shape-esineitä?
Kun joudut muokkaamaan sovellustasi, on aina hyvä pitää mielessä tärkein yksittäinen vastuu ( SIRPPI ).
SIRPPI auttaa sinua tekemään parempia suunnittelupäätöksiä luokan vastuusta.
Esimerkiksi tietokantataulukon malli (ActiveRecord-malli Railsin yhteydessä) edustaa koodissa ainutlaatuista tietokantatietuetta, joten sinun ei tarvitse olla huolissasi mistään käyttäjän tekemästäsi toiminnasta.
Tässä tulee Shape-objekti.
Shape-objekti on vastuussa muodon edustamisesta sovelluksessasi. Joten kutakin syöttökenttää voidaan käsitellä luokan attribuuttina. Voit vahvistaa, että nämä määritteet täyttävät joitain vahvistussääntöjä, ja voit siirtää 'puhtaat' tiedot sinne, missä niiden pitäisi mennä (esim. Tietokantamallisi tai ehkä kyselyhaun rakennustyökalu).
Milloin sinun on käytettävä Shape-esinettä?
Tämän avulla voit laittaa kaiken lomakelogiikan (nimeämiskäytännöt, validoinnit ja muut) yhteen paikkaan.
Kuinka luoda Shape-objekti?
ActiveModel::Model
(Rails 3: een on sen sijaan sisällytettävä nimi, muunnos ja vahvistus).Huomaa, että voit käyttää helmi uudistaa , mutta jatkamme PORO: n kanssa, luomme entry_form.rb
joka näyttää tältä:
Ja muokkaamme CreateEntry
aloittaa Format-objektin EntryForm
käyttö:
class CreateEntry ...... ...... def call @entry_form = ::EntryForm.new(@params) if @entry_form.valid? .... else .... end end end
Huomautus: Jotkut teistä sanovat, että Shape-objektia ei tarvitse käyttää Service-objektista ja että voimme soittaa Shape-objektin suoraan ohjaimesta, mikä on kelvollinen argumentti. Minulla olisi kuitenkin mieluummin selkeä kulku, siksi soitan aina Shape-objektille Service-objektista.
Kuten sovimme aiemmin, emme halua malliemme sisältävän validointeja ja puheluita. Noutimme validoinnit Shape-objekteilla. Mutta käytämme edelleen joitain puheluita (after_create
mallissa Entry
compare_speed_and_notify_user
).
Miksi haluamme poistaa huomiotekstit malleista?
Rails-kehittäjät he alkavat yleensä havaita puhelun aiheuttamaa kipua testien aikana. Jos et testaa ActiveRecord-mallejasi, huomaat tuskan myöhemmin, kun sovelluksesi kasvaa ja kun tarvitaan enemmän logiikkaa soittamiseen tai puheluiden välttämiseen.
después_*
puheluita käytetään ensisijaisesti kohteen tallentamiseen tai jatkamiseen.
Kun kohde on tallennettu, kohteen tarkoitus (esim. Vastuu) on täytetty. Joten jos näemme edelleen puheluita, objektin tallentamisen jälkeen nämä ovat todennäköisesti puheluita, jotka haluavat päästä pois kohteen vastuualueelta, ja silloin kohtaamme ongelmia.
Meidän tapauksessamme lähetämme käyttäjälle tekstiviestin, joka ei liity Input-verkkotunnukseen.
Yksinkertainen tapa ratkaista ongelma on siirtää puhelu siihen liittyvään palveluobjektiin. Loppujen lopuksi tekstiviestin lähettäminen vastaavalle käyttäjälle liittyy palveluobjektiin CreateEntry
eikä Entry-malli sellaisenaan.
Tällöin meidän ei enää tarvitse sulkea, compare_speed_and_notify_user
testeissämme. Olemme tehneet tämän yksinkertaisen asian luomalla merkinnän ilman tarvetta lähettää tekstiviestejä ja noudatamme hyvää olio-suuntautunutta suunnittelua varmistaen, että luokkamme on ainutlaatuinen vastuu ( SIRPPI ).
Joten nyt CreateEntry
se on jotain samanlaista kuin tämä:
Vaikka voimme helposti käyttää kokoelmaa Draper näkökulmamalleista ja sisustajista pysyn POROn luona tässä artikkelissa, kuten olen tähän mennessä tehnyt.
Tarvitsen luokan, joka kutsuu menetelmiä koristeltuun esineeseen.
Voin käyttää method_missing
sen toteuttamiseksi, mutta käytän tavallista Ruby-kirjastoa SimpleDelegator
. Seuraava koodi näyttää SimpleDelegator
: n käytön toteuttaa peruskoristelijamme:
% app/decorators/base_decorator.rb require 'delegate' class BaseDecorator Miksi _h
menetelmä?
Tämä menetelmä toimii näkymän kontekstin välityspalvelimena. Näkymäkonteksti on oletusarvoisesti näkymäluokka, joka on ActionView::Base
. Voit käyttää auttajia näkemykset seuraavasti:
_h.content_tag :div, 'my-div', class: 'my-class'
Jotta se olisi helpompaa, lisätään menetelmä decorado
a ApplicationHelper
:
module ApplicationHelper # ..... def decorate(object, klass = nil) klass ||= '#{object.class}Decorator'.constantize decorator = klass.new(object, self) yield decorator if block_given? decorator end # ..... end
Nyt voimme siirtää auttajia EntriesHelper
sisustajille:
# app/decorators/entry_decorator.rb class EntryDecorator Ja voimme käyttää readable_time_period
ja readable_speed
seuraavasti:
# app/views/entries/_entry.html.erb - +
- +
Rakenne jälkikäsittelyn jälkeen
Päätimme lisää tiedostoja, mutta se ei välttämättä ole huono asia (ja muista tämä, alusta alkaen olimme tietoisia siitä, että tämä esimerkki oli tarkoitettu esittelyä varten ja ei oli välttämättä hyvä käyttötarkoitus refaktorointiin):
app ├── assets │ └── ... ├── controllers │ ├── application_controller.rb │ ├── entries_controller.rb │ └── statistics_controller.rb ├── decorators │ ├── base_decorator.rb │ └── entry_decorator.rb ├── forms │ └── entry_form.rb ├── helpers │ └── application_helper.rb ├── mailers ├── models │ ├── entry.rb │ ├── entry_status.rb │ └── user.rb ├── queries │ └── group_entries_query.rb ├── services │ ├── create_entry.rb │ └── report │ └── generate_weekly.rb └── views ├── devise │ └── .. ├── entries │ ├── _entry.html.erb │ ├── _form.html.erb │ └── index.html.erb ├── layouts │ └── application.html.erb └── statistics └── index.html.erb
johtopäätös
Vaikka tässä blogikirjoituksessa keskitymme kiskoihin, RoR (Ruby on Rails) ei ole riippuvuus palveluobjekteista tai muista PORO-palveluista. Voit käyttää tätä lähestymistapaa minkä tahansa kanssa kehysverkko , mobiili- tai konsolisovellus.
Käytettäessä MVC Arkkitehtuurina kaikki tarttuu yhteen ja hidastaa sinua, koska useimmat muutokset vaikuttavat sovelluksen muihin osiin. Se pakottaa myös miettimään, mihin laittaa liiketoimintalogiikkaa - pitäisikö sen mennä malliin, ohjaimeen vai näkymään?
Käyttämällä yksinkertaista PORO: ta olemme siirtäneet liiketoimintalogiikan malleihin tai palveluihin, jotka eivät peri ActiveRecord
: sta, mikä on jo voitto, puhumattakaan siitä, että meillä on selkeämpi koodi, joka tukee SIRPPI ja nopeammat yksikötestit.
Puhdas arkkitehtuuri yrittää laittaa käyttöruudut rakenteen keskelle / yläosaan, jotta voit helposti nähdä, mitä sovelluksesi tekee. Se myös helpottaa muutosten hyväksymistä, koska se on modulaarisempi ja eristetty. Toivon, että olen osoittanut miten Tavalliset vanhat rubiinikohteet ja enemmän abstraktioita, se erottaa huolenaiheet, yksinkertaistaa testausta ja auttaa tuottamaan puhtaan, ylläpidettävän koodin.
Liittyvät: Mitkä ovat Ruby on Rails -edut? Kahden vuosikymmenen ohjelmoinnin jälkeen. Käytä kiskoja