Anti-hva? Det høres sannsynligvis mye mer komplisert enn det er. I løpet av de siste par tiårene var programmører i stand til å identifisere et nyttig utvalg av "design" -mønstre som ofte skjedde gjennom deres kodeløsninger. Mens de løste lignende problemer, var de i stand til å "klassifisere" løsninger som forhindret dem i å gjenoppfinne hjulet hele tiden. Det er viktig å merke seg at disse mønstrene skal ses mer som funn enn oppfinnelsen til en gruppe av avanserte utviklere.
Hvis dette er ganske nytt for deg og du ser deg selv som å være mer på begynnelsersiden av alle ting Ruby / Rails, så er denne nøyaktig skrevet for deg. Jeg synes det er best hvis du tenker på det som en rask, tynn dukkert i et mye dypere emne hvis mestring ikke skjer over natten. Likevel tror jeg sterkt at begynnelsen for å komme inn i denne tidlige viljen nyter nybegynnere og deres mentorer enormt.
AntiPatterner - som navnet antyder - representerer ganske mye det motsatte av mønstre. De er funn av løsninger på problemer som du definitivt bør unngå. De representerer ofte arbeidet med uerfarne kodere som ikke vet hva de ennå ikke vet. Verre, de kan være produksjonen av en lat person som bare ignorerer beste praksis og verktøyrammer uten god grunn - eller de tror de ikke trenger dem. Det de kanskje håper å få i tidsbesparelser i begynnelsen ved å hamre ut raske, dovne eller skitne løsninger, kommer til å hjemsøke dem eller noen beklager etterfølger senere i prosjektets livssyklus.
Ikke undervurder implikasjonene til disse dårlige beslutningene - de kommer til å plage deg, uansett hva.
Jeg er sikker på at du hørte "Fat models, tynne controllers" syngesangen mange ganger da du først startet med Rails. OK, glem det nå! Visst, forretningslogikken må løses i modelllaget, men du bør ikke føle seg tilbøyelig til å kaste alt der inne meningsløst bare for å unngå å krysse linjene inn i kontrollerområdet.
Her er et nytt mål du bør sikte på: "Skinny modeller, tynne kontrollere". Du kan spørre, "Vel, hvordan skal vi ordne kode for å oppnå det? Tross alt er det et null-sumspill?" Bra poeng! Navnet på spillet er sammensetning, og Ruby er godt rustet til å gi deg mange muligheter for å unngå modell fedme.
I de fleste (Rails) webapplikasjoner som støttes av databasen, vil mesteparten av din oppmerksomhet og arbeid være sentrert rundt modelllaget - gitt at du jobber med kompetente designere som kan implementere sine egne ting i visningen, mener jeg. Modellene dine vil iboende ha mer "tyngdekraften" og tiltrekke seg mer kompleksitet.
Spørsmålet er bare hvordan du har tenkt å håndtere den kompleksiteten. Active Record gir deg absolutt massevis av tau for å henge deg selv mens du gjør livet ditt utrolig enkelt. Det er en fristende tilnærming til å designe modelllaget ved bare å følge banen med høyest umiddelbar bekvemmelighet. Ikke desto mindre tar en fremtidssikker arkitektur mye mer hensyn enn å dyrke store klasser og fylle alt i Active Record-objekter.
Det virkelige problemet som du håndterer her er kompleksitet - unødvendig, så vil jeg si. Klasser som samler tonn kode blir komplekse bare etter deres størrelse alene. De er vanskeligere å vedlikeholde, vanskelig å analysere og forstå, og stadig vanskeligere å endre fordi deres sammensetning sannsynligvis mangler avkobling. Disse modellene overgår ofte deres anbefalte kapasitet til å håndtere et enkelt ansvar og er ganske over alt. Verste fallet, de blir som søppelbusser, og håndterer alt søppel som er sløyfe kastet på dem.
Vi kan gjøre det bedre! Hvis du mener at kompleksiteten ikke er en stor avtale, er du allikevel spesiell, smart og all-think igjen! Kompleksitet er den mest beryktede serielle prosjektmordet der ute - ikke ditt vennlige nabolag "Dark Defender".
"Skinnier-modeller" oppnår en ting avanserte folk i kodingsvirksomheten (sannsynligvis mange flere yrker enn kode og design) setter pris på og hva vi alle bør absolutt strebe for-enkelhet! Eller i det minste mer av det, noe som er et rettferdig kompromiss hvis kompleksiteten er vanskelig å utrydde.
Hvilke verktøy tilbyr Ruby å gjøre livet enklere i den forbindelse og la oss trimme fettet ut av våre modeller? Enkle, andre klasser og moduler. Du identifiserer koherent kode som du kan trekke ut i et annet objekt og derved bygge et modellelag som består av rimelig størrelse agenter som har sitt eget unike, særegne ansvar.
Tenk på det når det gjelder en talentfull artist. I virkeligheten, kan en slik person være i stand til å rape, knuse, skrive tekster og lage egne melodier. I programmering foretrekker du dynamikken til et band - her med minst fire karakteristiske medlemmer - hvor hver person har ansvar for så få ting som mulig. Du vil bygge et orkester av klasser som kan håndtere kompleksiteten til komponisten-ikke en mikromanaging genius maestro klasse av alle handler.
La oss se på et eksempel på en fet modell og spille med et par alternativer for å håndtere fedme. Eksemplet er en dummy en, selvfølgelig, og ved å fortelle denne tunge lille historien håper jeg det blir lettere å fordøye og følge etter nybegynnere.
Vi har en Specter klasse som har for mange ansvar og har derfor vokst unødvendig. Foruten disse metodene, tror jeg det er lett å forestille seg at et slikt eksemplar allerede har samlet mange andre ting som godt representert av de tre små prikkene. Spektre er godt på vei til å bli en gudklasse. (Sjansene er ganske lave til fornuftig formulere en slik setning igjen når som helst snart!)
"Ruby Class Specter < ActiveRecord::Base has_many :spectre_members has_many :spectre_agents has_many :enemy_agents has_many :operations
...
def turn_mi6_agent (enemy_agent) setter "MI6 agent # enemy_agent.name vendt over til Specter" slutten
def turn_cia_agent (enemy_agent) setter "CIA agent # enemy_agent.name vendt over til Specter" slutten
def turn_mossad_agent (enemy_agent) setter "Mossad agent # enemy_agent.name vendt over til Specter" slutten
def kill_double_o_seven (spectre_agent) spectre_agent.kill_james_bond end
def dispose_of_cabinet_member (number) spectre_member = SpectreMember.find_by_id (nummer)
setter "En viss synder har sviktet denne brorskapets absolutte integritet. Den rette handlingen er å røyke nummer # nummer i stolen. Hans tjenester vil ikke bli savnet i stor grad" spectre_member.die end
def print_assignment (drift) setter "Operation # operation.name 's mål er å # operation.objective." avslutte
privat
def enemy_agent #clever kode ende
def spectre_agent #clever kode ende
def operasjon #clever kode ende
...
slutt
"
Specter vender ulike typer fiendtlige agenter, delegater dreper 007, griller Specters kabinetsmedlemmer når de feiler, og skriver også ut operasjonsoppgaver. Et klart tilfelle av mikromanagement og definitivt et brudd på "Single Responsibility Principle". Private metoder stabler også raskt opp.
Denne klassen trenger ikke å vite de fleste av de ting som er i det. Vi vil dele denne funksjonaliteten i et par klasser og se om kompleksiteten ved å ha et par flere klasser / objekter er verdt fettsuging.
"rubin
klassespekter < ActiveRecord::Base has_many :spectre_members has_many :spectre_agents has_many :enemy_agents has_many :operations
...
def turn_enemy_agent Interrogator.new (enemy_agent) .turn slutten
privat
def enemy_agent self.enemy_agents.last slutten
klasse Interrogator attr_reader: enemy_agent
def initialisere (enemy_agent) @enemy_agent = enemy_agent end
def slå enemy_agent.turn slutten
klassen EnemyAgent < ActiveRecord::Base belongs_to :spectre belongs_to :agency
def turn puts 'Etter omfattende hjernevasking, tortur og hoards of cash ...' slutten
klasse MI6Agent < EnemyAgent def turn super puts “MI6 agent #name turned over to Spectre” end end
klasse CiaAgent < EnemyAgent def turn super puts “CIA agent #name turned over to Spectre” end end
klasse MossadAgent < EnemyAgent def turn super puts “Mossad agent #name turned over to Spectre” end end
klasse NumberOne < ActiveRecord::Base def dispose_of_cabinet_member(number) spectre_member = SpectreMember.find_by_id(number)
setter "En viss skyldige har sviktet denne brorskapets absolutte integritet. Den rette handlingen er å røyke nummer # nummer i stolen. Hans tjenester vil ikke bli savnet i stor grad" spectre_member.die endeenden
klasse drift < ActiveRecord::Base has_many :spectre_agents belongs_to :spectre
def print_assignment setter "Operasjon # name 's mål er å # objective." End-end
klasse SpectreAgent < ActiveRecord::Base belongs_to :operation belongs_to :spectre
def kill_james_bond setter "Mr. Bond, jeg forventer at du skal dø! "Slutten
klasse SpectreMember < ActiveRecord::Base belongs_to :spectre
def dør setter "Nooo, nei, det var ikke meeeeeeeee! ZCHUNK! "Endeenden
"
Jeg tror den viktigste delen som du bør være oppmerksom på, er hvordan vi brukte en vanlig Ruby-klasse som forhørs
å håndtere vendingen av agenter fra ulike byråer. Eksempler på ekte verden kan representere en omformer som for eksempel forvandler et HTML-dokument til en pdf og omvendt. Hvis du ikke trenger full funksjonalitet av Active Record-klasser, hvorfor bruke dem hvis en enkel Ruby-klasse også kan gjøre trikset? Litt mindre tau å henge oss med.
Spektaklassen etterlater den ekle virksomheten til å snu agenter til forhørs
klassen og bare delegerer til den. Denne har nå det eneste ansvaret for torturering og hjernevasking som er fanget.
Så langt så bra. Men hvorfor opprettet vi separate klasser for hver agent? Enkel. I stedet for bare å direkte utvinne de ulike svingmetoder som turn_mi6_agent
over til forhørs
, Vi ga dem et bedre hjem i sin egen respektive klasse.
Som et resultat kan vi effektivt gjøre bruk av polymorfisme og bryr seg ikke om enkelte tilfeller for svingemidlene. Vi forteller bare disse forskjellige agentobjektene å slå, og hver av dem vet hva de skal gjøre. De forhørs
trenger ikke å vite detaljene om hvordan hver agent blir.
Siden alle disse agenter er Active Record-objekter, opprettet vi en generisk, EnemyAgent
, Det har en generell følelse av hva som betyr å snu en agent, og vi inkapslerer den for alle agenter på ett sted ved å subclassere den. Vi benytter denne arven ved å levere sving
metoder for de forskjellige midlene med super
, og derfor får vi tilgang til hjernevasking og torturvirksomhet uten duplisering. Enkelt ansvar og ingen duplisering er et godt utgangspunkt for videreføring.
De andre Active Record-klassene tar på seg ulike ansvarsområder som Specter ikke trenger å bry seg om. "Nummer One" pleier vanligvis grilling av mislykkede Specter-kabinettmedlemmer selv, så hvorfor ikke la en dedikert gjenstand håndtere elektrocution? På den annen side vet ikke spektermedlemmer hvordan de skal dø selv når de blir røkt i stolen av Nummer en
. Operasjon
skriver nå også oppdragene sine selv - det er ikke nødvendig å kaste bort tiden til Specter med peanøtter sånn.
Sist, men ikke minst, blir drap James Bond vanligvis forsøkt av en agent i feltet, så kill_james_bond
er nå en metode på SpectreAgent
. Goldfinger ville ha håndtert det annerledes, selvfølgelig, må du leke med den laseren thingie hvis du har en, antar jeg.
Som du tydeligvis kan se, har vi nå ti klasser der vi tidligere kun hadde en. Er det ikke for mye? Det kan sikkert være. Det er et problem du må kjempe med mesteparten av tiden når du deler opp slike ansvarsområder. Du kan definitivt overdrive dette. Men å se på dette fra en annen vinkel kan hjelpe:
Jeg antar ikke at disse spørsmålene må kontrolleres av listen hver gang, men det er de tingene du sannsynligvis burde begynne å spørre deg selv mens du slanker ned modellene dine.
Å utforme tynne modeller kan være vanskelig, men det er et viktig tiltak for å holde applikasjonene sunne og smidige. Disse er heller ikke de eneste konstruktive måtene å håndtere fettmodeller, men de er en god start, spesielt for nybegynnere.
Dette er trolig den mest åpenbare AntiPattern. Å komme fra den testdrevne siden av ting, ved å røre en moden app som ikke har testdekning, kan være en av de mest smertefulle opplevelsene som møter. Hvis du vil hate verden og ditt eget yrke mer enn noe, bare bruke seks måneder på et slikt prosjekt, og du vil lære hvor mye av en misantrop som muligens er i deg. Å tuller, selvfølgelig, men jeg tviler på at det vil gjøre deg lykkeligere og at du vil gjøre det igjen - noensinne. Kanskje en uke også vil gjøre det. Jeg er ganske sikker på at ordet tortur vil dukke opp i tankene dine oftere enn du tror.
Hvis testingen ikke var en del av prosessen så langt, og den slags smerte føles normal for arbeidet ditt, bør du kanskje vurdere at testing ikke er så dårlig, og det er heller ikke din fiende. Når dine kodenelaterte gledenivåer er mer eller mindre stadig over null, og du kan fryktløst endre koden din, vil den generelle kvaliteten på arbeidet ditt være mye høyere i forhold til produksjonen som er besvimt av angst og lidelse.
Overestimerer jeg? Jeg tror egentlig ikke det! Du vil ha en svært omfattende testdekning, ikke bare fordi det er et flott designverktøy for bare å skrive kode som du faktisk trenger, men også fordi du må endre koden din på et tidspunkt i fremtiden. Du vil være mye bedre rustet til å engasjere seg med kodebase-og mye mer selvsikkerhet - hvis du har en test sele som hjelper og veileder refactorings, vedlikehold og utvidelser. De vil oppstå sikkert nedover veien, null tviler på det.
Dette er også poenget hvor en testpakke begynner å betale ut den andre runden av utbytte, fordi den økte hastigheten som du sikkert kan gjøre disse kvalitetsendringene ikke kan oppnås med en lang skudd i apper som er laget av folk som tenker å skrive tester er tull eller tar for mye tid.
Dette er modeller som er super nysgjerrige og ønsker å samle for mye informasjon om andre objekter eller modeller. Det er i sterk kontrast til en av de mest grunnleggende ideene i Objektorientert Programmering-innkapsling. Vi vil heller streve for selvstendige klasser og modeller som styrer sine interne forhold så mye som mulig. Når det gjelder programmeringskonsepter, bryter disse voyeuristiske modellene i utgangspunktet "Princip of Minimum Knowledge", aka "Demeter Law" - uansett hvor du vil uttale det.
Hvorfor er dette et problem? Det er en form for duplisering - en subtil en - og fører også til kode som er mye mer sprø enn forventet.
Demeterloven er ganske mye den mest pålitelige kode lukten som du alltid kan angripe uten å være bekymret for mulige ulemper.
Jeg antar å ringe denne en "lov" var ikke så pretensiøs som det kanskje høres først. Grav inn i denne lukten, fordi du trenger det mye i prosjektene dine. Det står i utgangspunktet at når det gjelder objekter, kan du ringe metoder på objektets venn, men ikke på vennens venn.
Dette er en vanlig måte å forklare det på, og det kaster seg ned til å bruke ikke mer enn en enkelt prikk for metallsamtaler. Forresten, det er helt fint å bruke flere prikker eller metallsamtaler når du håndterer et enkelt objekt som ikke forsøker å nå lenger enn det. Noe som @ weapons.find_by_name ('Poison dart'). formel
Det er helt fint. Finders kan hakke opp ganske mange prikker noen ganger. Encapsulating dem i dedikerte metoder er likevel en god ide.
La oss se på noen få dårlige eksempler fra klassene ovenfor:
"rubin
@ operation.spectre_agents.first.kill_james_bond
@ spectre.operations.last.spectre_agents.first.name
@ spectre.enemy_agents.last.agency.name
"
For å få tak i det, er det noen få fiktive:
"rubin
@ quartermaster.gizmos.non_lethal.favorite
@ mi6.operation.agent.favorite_weapon
@ mission.agent.name
"
Bananer, ikke sant? Ser ikke bra ut, gjør det? Som du ser, kaller disse metodene for mye inn i virksomheten til andre objekter. Den viktigste og åpenbare negative konsekvensen er å forandre en haug med disse metodene ringer over alt om strukturen til disse objektene må endres, hvilket de til slutt vil, fordi den eneste konstanten i programvareutvikling er endring. Også, det ser veldig stygg, ikke lett på øynene i det hele tatt. Når du ikke vet at dette er en problematisk tilnærming, lar du Rails å ta dette veldig langt uansett - uten å skrike på deg. Mange tau, husk?
Så hva kan vi gjøre med dette? Tross alt vil vi få den informasjonen på en eller annen måte. For en ting kan vi komponere våre objekter slik at de passer til våre behov, og vi kan gjøre smart bruk av delegasjonen for å holde våre modeller slanke samtidig. La oss dykke inn i en kode for å vise deg hva jeg mener.
"rubin
klasse SpectreMember < ActiveRecord::Base has_many :operations has_many :spectre_agents
...
slutt
klasse drift < ActiveRecord::Base belongs_to :spectre_member
...
slutt
klasse SpectreAgent < ActiveRecord::Base belongs_to :spectre_member
...
slutt
@ spectre_member.spectre_agents.all @ spectre_member.operations.last.print_assignment @ spectre_member.spectre_agents.find_by_id (1) .name
@ drift.spectre_member.name @ operation.spectre_member.number @ operation.spectre_member.spectre_agents.first.name
@ spectre_agent.spectre_member.number
"
"rubin
klasse SpectreMember < ActiveRecord::Base has_many :operations has_many :spectre_agents
...
def list_of_agents spectre_agents.all end
def print_operation_details operation = Operation.last operation.print_operation_details sluttend
klasse drift < ActiveRecord::Base belongs_to :spectre_member
...
def spectre_member_name spectre_member.name end
def spectre_member_number spectre_member.number slutten
def print_operation_details setter "Denne operasjonens mål er # objective. Målet er # target "slutten
klasse SpectreAgent < ActiveRecord::Base belongs_to :spectre_member
...
def superior_in_charge legger "Min sjef er nummer # spectre_member.number" slutten
@ spectre_member.list_of_agents @ spectre_member.print_operation_details
@ drift.spectre_member_name @ operation.spectre_member_number
@ spectre_agent.superior_in_charge
"
Dette er definitivt et skritt i riktig retning. Som du ser, pakket vi inn informasjonen vi ønsket å skaffe oss i en mengde wrapper-metoder. I stedet for å nå direkte over mange objekter, abstrakte vi disse broene og la den til de respektive modellene for å snakke med vennene deres om den informasjonen vi trenger.
Ulempen med denne tilnærmingen er å ha alle disse ekstra innpakningsmetoder som ligger rundt. Noen ganger er det bra, men vi vil virkelig unngå å opprettholde disse metodene i en rekke steder hvis en gjenstand endres.
Om mulig er det dedikerte stedet for dem å forandre seg på deres gjenstand - og bare på deres gjenstand. Forurensende gjenstander med metoder som har lite å gjøre med sin egen modell, er også noe å passe på siden dette alltid er en potensiell fare for vanning ned enkelt ansvar.
Vi kan gjøre det bedre enn det. Når det er mulig, la oss delegere metallsamtaler direkte til sine objekter som er ansvarlige, og prøv å kutte ned på wrapper-metoder så mye som mulig. Rails vet hva vi trenger og gir oss det praktiske delegat
klassemetode for å fortelle vennens venner hvilke metoder vi trenger kalt.
La oss zoome inn på noe fra forrige kodeeksempel og se hvor vi kan gjøre riktig bruk av delegasjonen.
"rubin
klasse drift < ActiveRecord::Base belongs_to :spectre_member
delegere: navn,: nummer, til:: spectre_member, prefiks: true
...
# spectre_member.name # end
# spectre_member.number # end
...
slutt
@ drift.spectre_member_name @ operation.spectre_member_number
klasse SpectreAgent < ActiveRecord::Base belongs_to :spectre_member
delegere: nummer, til:: spectre_member, prefix: true
...
def superior_in_charge legger "Min sjef er nummer # spectre_member_number" slutten
...
slutt
"
Som du kan se, kan vi forenkle ting litt ved hjelp av metodegruppering. Vi ble kvitt Operasjon # spectre_member_name
og Operasjon # spectre_member_number
helt, og SpectreAgent
trenger ikke å ringe Nummer
på spectre_member
lenger-Nummer
er delegert tilbake direkte til sin "opprinnelses" klasse SpectreMember
.
I tilfelle dette er litt forvirrende først, hvordan fungerer dette nøyaktig? Du forteller delegat hvilken : method_name
det bør delegere til:
hvilken :klassenavn
(flere metodenavn er også bra). De prefiks: sant
del er valgfritt.
I vårt tilfelle prefikserte det slangekasset klassenavnet til mottakerklassen før metodenavnet og gjorde det mulig for oss å ringe operation.spectre_member_name
i stedet for det potensielt tvetydige operation.name
-hvis vi ikke hadde brukt prefiks-alternativet. Dette fungerer veldig bra med tilhører
og has_one
foreninger.
På har mange
siden av ting, men musikken vil stoppe og du kommer til å trenge inn i problemer. Disse foreningene gir deg en samlingsproxy som vil kaste NameErrors eller NoMethodErrors hos deg når du delegerer metoder til disse "samlingene".
For å avrunde dette kapittelet om modell AntiPatterns i Rails, vil jeg gjerne bruke litt tid på hva jeg skal unngå når SQL er involvert. Active Record-foreninger gir alternativer som gjør livet ditt betydelig lettere når du er klar over hva du bør holde seg borte fra. Finder-metoder er et helt tema for seg selv, og vi vil ikke dekke dem i full dybde, men jeg vil nevne noen få vanlige teknikker som hjelper deg selv når du skriver veldig enkle.
Ting som vi burde være bekymret for ekko det meste av det vi har lært så langt. Vi vil ha hensikt-avslørende, enkle og rimelig navngitte metoder for å finne ting i våre modeller. La oss dykke rett inn i koden.
"rubin
klasse drift < ActiveRecord::Base
har mange: agenter
...
slutt
klasse agent < ActiveRecord::Base
belong_to: drift
...
slutt
klasse OperationsController < ApplicationController
def index @operation = Operation.find (params [: id]) @agents = Agent.where (operation_id: @ operation.id, licence_to_kill: true) slutten
"
Ser ufarlig ut, nei? Vi leter bare etter en mengde agenter som har lisensen til å drepe for vår ops side. Tenk igjen. Hvorfor skal OperationsController
grave inn i internals of Middel
? Også er dette virkelig det beste vi kan gjøre for å inkapslere en finner på Middel
?
Hvis du tenker at du kan legge til en klassemetode som Agent.find_licence_to_kill_agents
som encapsulates finder logikken, er du definitivt et skritt i riktig retning - ikke nesten nok, skjønt.
"rubin
klasse agent < ActiveRecord::Base
belong_to: drift
def self.find_licence_to_kill_agents (operasjon) hvor (operation_id: operation.id, license_to_kill: true) end ...
slutt
klasse OperationsController < ApplicationController
def index @operation = Operation.find (params [: id]) @agents = Agent.find_licence_to_kill_agents (@operation) slutten
"
Vi må være litt mer engasjert enn det. Først og fremst bruker dette ikke foreningene til vår fordel, og innkapsling er også suboptimal. Foreninger som har mange
kom med den fordelen vi kan legge til på proxy-arrayet som vi kommer tilbake. Vi kunne ha gjort dette i stedet:
"rubin
klasse drift < ActiveRecord::Base
har mange: agenter
def find_licence_to_kill_agents self.agents.where (lisence_to_kill: true) avslutte ...
slutt
klasse OperationsController < ApplicationController
def index @operation = Operation.find (params [: id]) @agents = @ drift.find_licence_to_kill_agents endeend
"
Dette fungerer sikkert, men er også bare et lite skritt i riktig retning. Ja, kontrolleren er litt bedre, og vi benytter godt av modellforeninger, men du bør fortsatt være mistenksom på hvorfor Operasjon
er opptatt av gjennomføringen av å finne en bestemt type Middel
. Dette ansvaret hører tilbake til Middel
modellen selv.
Navngitte scopes kommer ganske bra med det. Omfangene definerer kjedelig-veldig viktige klassemetoder for modellene dine og gir deg dermed mulighet til å angi nyttige spørringer som du kan bruke som ekstra metallsamtaler på toppen av modellforeningene dine. Følgende to tilnærminger for scoping Middel
er likegyldig.
"rubin
klasse agent < ActiveRecord::Base belongs_to :operation
omfang: lisenced_to_kill, -> where (licence_to_kill: true) avslutte
klasse agent < ActiveRecord::Base belongs_to :operation
def self.licenced_to_kill hvor (licence_to_kill: true) slutten
klasse OperationsController < ApplicationController
def index @operation = Operation.find (params [: id]) @agents = @ operation.agents.licenced_to_kill endeend
"
Det er mye bedre. I tilfelle syntaxen av scopes er ny for deg, er de bare (stabby) lambdas-ikke veldig viktig å se på dem med en gang, forresten - og de er den riktige måten å ringe på siden siden Rails 4. Middel
er nå ansvarlig for å administrere sine egne søkeparametere, og foreninger kan bare kaste seg på det de trenger å finne.
Denne tilnærmingen lar deg oppnå spørsmål som enkle SQL-anrop. Jeg personlig liker å bruke omfang
for dens eksplisitte. Scopes er også veldig nyttige å kjede inne i velkjente søkemetoder, slik at de øker muligheten for å gjenbruke kode og DRY-ing-kode. La oss si at vi har noe litt mer involvert:
"rubin
klasse agent < ActiveRecord::Base belongs_to :operation
omfang: licenced_to_kill, -> hvor (lisens_to_kill: true) omfang: womanizer, -> where (womanizer: true) omfang: bond, -> hvor (navn: 'James Bond') omfang: gambler > hvor (gambler: true) slutten
"
Vi kan nå bruke alle disse omfangene til å skreddersy bygge mer komplekse søk.
"rubin
klasse OperationsController < ApplicationController
def index @operation = Operation.find (params [: id]) @double_o_agents = @ operation.agents.licenced_to_kill end
def show @operation = Operation.find (params [: id]) @bond = @ operation.agents.womanizer.gambler.licenced_to_kill end
… slutt
"
Jo, det fungerer, men jeg vil gjerne foreslå at du går et skritt videre.
"rubin
klasse agent < ActiveRecord::Base belongs_to :operation
omfang: licenced_to_kill, -> hvor (lisens_to_kill: true) omfang: womanizer, -> where (womanizer: true) omfang: bond, -> hvor (navn: 'James Bond') omfang: gambler > hvor (gambler: true)
def self.find_licenced_to_kill lisenced_to_kill end
def self.find_licenced_to_kill_womanizer womanizer.licenced_to_kill end
def self.find_gambling_womanizer gambler.womanizer slutten
...
slutt
klasse OperationsController < ApplicationController
def index @operation = Operation.find (params [: id]) @double_o_agents = @ operation.agents.find_licenced_to_kill end
def show @operation = Operation.find (params [: id]) @bond = @ operation.agents.find_licenced_to_kill_womanizer #or @bond = @ operation.agents.bond end
...
slutt
"
Som du ser, øker vi fordelene ved riktig innkapsling, modellforeninger, kodeutnyttelse og uttrykksfull navngivning av metoder, og samtidig gjør det enkelt SQL-spørringer. Ikke mer spaghetti kode, fantastisk!
Hvis du er bekymret for å bryte loven om Demeter thingie, vil du være glad for å høre at siden vi ikke legger til punkter ved å komme inn i den tilknyttede modellen, men bare knytte dem til eget objekt, begår vi ikke Demeter forbrytelser.
Fra et nybegynnerperspektiv tror jeg at du har lært mye om bedre håndtering av Rails Models, og hvordan du modellerer dem robustere uten å ringe etter en hangman.
Ikke la deg lure, men tenk at det ikke er mye mer å lære om dette emnet. Jeg presenterte deg med noen få AntiPatterner som jeg tror nybegynnere kan forstå og håndtere for å beskytte seg selv tidlig. Hvis du ikke vet hva du ikke vet, er det nok av tau tilgjengelig for looping rundt halsen.
Selv om dette var en solid start i dette emnet, er det ikke bare flere aspekter til AntiPatterns i Rails-modeller, men også mer nyanser som du må utforske også. Disse var de grunnleggende - svært viktige og viktige - og du burde føle deg oppnådd i en liten stund at du ikke har ventet til mye senere i din karriere for å finne ut dem.