IOS-i tarkvara lihtsa kujunduse neli reeglit

1990ndate lõpus, kuulsa tarkvaraarendaja Kent Becki ekstreemset programmeerimist arendades tuli välja lihtsa tarkvara kujundamise reeglite loetelu.

Kent Becki sõnul on hea tarkvarakujundus:

  • Läbib kõik testid
  • Ei sisalda dubleerimist
  • Väljendab programmeerija kavatsust
  • Minimeerib klasside ja meetodite arvu

Selles artiklis räägime sellest, kuidas neid reegleid saab iOS-i arendusmaailmas rakendada, esitades praktilisi iOS-i näiteid ja arutades, kuidas saaksime neist kasu saada.

Läbib kõik testid

Tarkvarakujundus aitab meil luua süsteemi, mis toimib nagu ette nähtud. Kuid kuidas saaksime kontrollida, kas süsteem toimib nii, nagu selle kavandamine algselt ette nägi? Vastus on testide loomisega, mis seda valideerivad.

Kahjuks välditakse iOS-i arenduse universumites enamikul juhtudel testimist ... Kuid hästi kavandatud tarkvara loomiseks peaksime Swift-koodi kirjutama alati, pidades silmas testitavust.

Arutleme kahe põhimõtte üle, mis võivad testide kirjutamise ja süsteemi kujundamise lihtsamaks muuta. Ja need on ühe vastutuse põhimõte ja sõltuvuse süstimine.

Ühe vastutuse põhimõte (SRP)

SRP väidab, et klassil peaks olema üks ja ainult üks põhjus muutmiseks. SRP on üks lihtsamaid põhimõtteid ja üks raskemaid õigeks saada. Kohustuste segamine on asi, mida teeme loomulikult.

Toogem näide mõne koodi kohta, mida on tõesti raske testida ja pärast seda saate seda reageerida SRP abil. Seejärel arutage, kuidas see muutis koodi testitavaks.

Oletame, et praegu peame oma praeguses vaatekontrolleris esitlema PaymentViewControlleri, siis peaks PaymentViewController oma vaate seadistama sõltuvalt meie maksetoote hinnast. Meie puhul on hind varieeruv sõltuvalt mõnest välisest kasutaja sündmusest.

Selle rakenduse kood näeb praegu välja järgmine:

Kuidas saaksime seda koodi testida? Mida peaksime kõigepealt katsetama? Kas hinnasoodustus on õigesti arvutatud? Kuidas saaksime maksesündmusi mõnitada, et allahindlust testida?

Selle klassi jaoks testide kirjutamine oleks keeruline, peaksime leidma parema viisi selle kirjutamiseks. Noh, kõigepealt tegeleme suure probleemiga. Peame oma sõltuvused lahti harutama.

Näeme, et meil on loogika oma toote laadimiseks. Meil on makseüritusi, mis võimaldavad kasutajal soodustust saada. Meil on allahindlused, allahindluste arvutamine ja nimekiri jätkub.

Proovime need lihtsalt Swifti koodiks tõlkida.

Lõime maksehalduri, mis haldab meie maksetega seotud loogikat, ja eraldi hinnakalkulaatori, mille testimine on lihtne. Samuti andmete laadur, mis vastutab võrgu või andmebaasi interaktsiooni eest meie toodete laadimisel.

Samuti mainisime, et vajame allahindluste haldamise eest vastutavat klassi. Nimetagem seda CouponManageriks ja haldame ka kasutaja sooduskuponge.

Meie maksevaate kontroller võib siis välja näha järgmine:

Me võime kirjutada nüüd teste nagu

  • testCalculatingFinalPriceWithoutCoupon
  • testCalculatingFinalPriceWithCoupon
  • testCouponExists

ja paljud teised! Nüüd eraldi objektide loomisega väldime tarbetut dubleerimist ja loome ka koodi, mille jaoks on testide kirjutamine lihtne.

Sõltuvuse süstimine

Teine põhimõte on sõltuvuse süstimine. Ja nägime ülaltoodud näidetest, et me kasutasime juba oma objekti initsiaatorites sõltuvuse süstimist.

Nagu ülalpool, on meie sõltuvuste süstimisel kaks peamist eelist. See teeb selgeks, millistest sõltuvustest meie tüübid sõltuvad ja võimaldab meil sisestada pilkavaid objekte, kui tahame testida tegelike asemel.

Hea tehnika on luua oma objektidele protokolle ja pakkuda reaalset ja pilkupüüdvat objekti konkreetselt järgmiselt:

Nüüd saame hõlpsalt otsustada, millist klassi me sõltuvusena süstida tahame.

Tihe sidumine raskendab testide kirjutamist. Sarnaselt, mida rohkem teste kirjutame, seda rohkem kasutame sidumise minimeerimiseks selliseid põhimõtteid nagu DIP ja selliseid tööriistu nagu sõltuvuse süstimine, liidesed ja abstraktsioon.

Koodi kontrollitavamaks muutmine kõrvaldab mitte ainult hirmu seda rikkuda (kuna kirjutame testi, mis meid varundab), vaid aitab ka puhtama koodi kirjutamisel.

See artikli osa oli rohkem mures selle üle, kuidas kirjutada kontrollitavat koodi kui tegeliku ühikatesti kirjutamist. Kui soovite ühiskatsete kirjutamise kohta rohkem teada saada, siis vaadake seda artiklit, kus loon elumängu testipõhise arengu abil.

Ei sisalda dubleerimist

Kopeerimine on hästi läbimõeldud süsteemi peamine vaenlane. See esindab lisatööd, täiendavat riski, lisab tarbetut keerukust.

Selles jaotises arutame, kuidas saaksime malli kujundusmustrit kasutada iOS-is tavalise dubleerimise eemaldamiseks. Lihtsamaks mõistmiseks jätkame reaalajas vestluse rakendamist.

Oletame, et praegu on meie rakenduses tavaline vestlusjaotis. Tekib uus nõue ja nüüd tahame rakendada uut tüüpi vestlust - otsevestlust. Vestlus, mis peaks sisaldama maksimaalselt 20 tähemärgist koosnevaid sõnumeid ja see vestlus kaob, kui loobume vestluse vaatest.

Sellel vestlusel on samad vaated nagu meie praegusel vestlusel, kuid sellel on mõned erinevad reeglid:

  1. Võrgusõnumid vestlussõnumite saatmiseks on erinevad.

2. Vestlussõnumid peavad olema lühikesed, mitte rohkem kui 20 tähemärki sõnumi jaoks.

3. Vestlussõnumeid ei tohiks meie kohalikus andmebaasis säilitada.

Oletame, et me kasutame MVP arhitektuuri ja käitleme praegu saatejuhi vestlussõnumite saatmise loogikat. Proovime lisada uuele vestlustüübile nimega live-chat uued reeglid.

Naiivne rakendamine oleks järgmine:

Mis saab aga siis, kui meil on tulevikus palju rohkem vestlustüüpe?
Kui jätkame lisamist, kui veel, mis kontrollivad meie vestluse olekut igas funktsioonis, muutub kood räpane raskesti loetavaks ja hooldatavaks. Samuti on see vaevalt kontrollitav ja olekukontroll dubleeritakse kogu saatejuhi ulatuses.

Siin kasutatakse mallimustrit. Mallimustrit kasutatakse siis, kui vajame algoritmi mitut rakendust. Malli määratletakse ja ehitatakse seejärel täiendavate variatsioonidega. Kasutage seda meetodit, kui enamik alamklasse peab rakendama sama käitumist.

Saame luua vestluse tutvustaja protokolli ja eraldame meetodid, mida konkreetsed objektid rakendavad vestluse tutvustaja faasides erinevalt.

Nüüd saame muuta saatejuhi vastavaks IChatPresenterile

Nüüd tegeleb meie saatejuht sõnumite saatmisega, kutsudes endasse ühiseid funktsioone ja delegeerib funktsioone, mida saab erinevalt rakendada.

Nüüd saame pakkuda saateobjektidele vastavaid objekte Loo ja konfigureerime need funktsioonid vastavalt nende vajadustele.

Kui kasutame oma vaatekontrolleris sõltuvuse süstimist, saame nüüd sama vaatekontrolleri uuesti kasutada kahel erineval juhul.

Kujundusmustrite abil saame oma iOS-koodi tõesti lihtsustada. Kui soovite selle kohta rohkem teada saada, annab järgmine artikkel täiendavaid selgitusi.

Ekspressiivne

Suurem osa tarkvaraprojekti maksumusest on pikaajaline hooldus. Tarkvaraarendajatele on kohustuslik kirjutada lihtsalt loetav ja hooldatav kood.

Pakume väljendusrikkamat koodi, kui kasutada head nime, SRP-d ja kirjutamistesti.

Nimetamine

Number üks asi, mis muudab koodi väljendusrikkamaks - ja see on nimetamine. Oluline on kirjutada nimesid, mis:

  • Paljasta kavatsus
  • Vältige desinformatsiooni
  • On hõlpsasti otsitavad

Klasside ja funktsioonide nimetamisel on hea trikk klasside jaoks nimisõna või nimisõnafraasi ja meetodite puhul kasutajate verbide või verbifraaside nimede kasutamine.

Ka siis, kui kasutatakse erinevaid kujundusmustreid, on mõnikord hea lisada klassinimele mustrinimed, näiteks käsk või külastaja. Nii et lugeja teaks kohe, millist mustrit seal kasutatakse, ilma et oleks vaja selle teada saamiseks kogu koodi läbi lugeda.

SRP kasutamine

Teine asi, mis muudab koodi väljendusrikkaks, on ülalt vastutuse põhimõtte kasutamine, mida mainiti eespool. Saate end väljendada, hoides oma funktsioone ja klasse väikestel eesmärkidel. Väikesi klasse ja funktsioone on tavaliselt lihtne nimetada, neid on lihtne kirjutada ja neid on lihtne mõista. Funktsioon peaks teenima ainult ühte eesmärki.

Kirjutamise test

Testide kirjutamine toob ka palju selgust, eriti pärandkoodiga töötamisel. Ka hästi kirjutatud ühikatsed on väljendusrikkad. Testide peamine eesmärk on toimida dokumenteerimisel näitena. Keegi, kes meie teste loeb, peaks saama kiiresti aru, mis klassiga on tegemist.

Minimeerige klasside ja meetodite arv

Klassi funktsioonid peavad jääma lühikeseks, funktsioon peaks alati täitma ainult ühte asja. Kui funktsioonil on liiga palju ridu, võib juhtuda, et see toimib kaheks või enamaks eraldi funktsiooniks.

Hea lähenemisviis on loendada füüsilisi ridu ja proovida sihtida maksimaalselt nelja kuni kuue funktsiooniridani, enamasti võib see, mis ületab ridade arvu, muutuda raskeks loetavaks ja hooldatavaks.

IOS-i hea mõte on tükeldada konfiguratsioonikõned, mida tavaliselt teeme funktsioonides viewDidLoad või viewDidAppear.

Sel moel oleksid kõik funktsioonid väikesed ja hooldatavad ühe funktsiooni viewDidLoad asemel. Sama peaks kehtima ka rakenduse esindaja kohta. Peaksime vältima iga konfiguratsiooni viskamist ondidFinishLaunchingWithOptions meetodile ja eraldi konfiguratsioonifunktsioonidele või veelgi parematele konfiguratsiooniklassidele.

Funktsioonide abil on natuke lihtsam mõõta, kas hoiame seda pikka või lühikest, enamasti võime loota ainult füüsiliste joonte loendamisele. Klassidega kasutame teistsugust mõõtu. Me arvestame kohustustega. Kui klassil on ainult viis meetodit, ei tähenda see, et klass on väike, võib juhtuda, et tal on liiga palju kohustusi ainult nende meetoditega.

IOS-is on probleemiks UIViewControllersi suur suurus. On tõsi, et õunavaate kontrolleri kujunduse järgi on raske hoida neid objekte ühe eesmärgi nimel, kuid me peaksime andma endast parima.

UIViewControllersi vähendamiseks on palju viise. Minu eelistuseks on kasutada arhitektuuri, mis eraldab selliseid probleeme nagu VIPER või MVP, kuid see ei tähenda, et me ei saaks seda ka Apple MVC-s paremaks muuta.

Püüdes võimalikult palju muresid eraldada, jõuame mis tahes arhitektuuriga päris korraliku koodini. Idee on luua üheotstarbelised klassid, mis saaksid olla abiks vaatekontrolleritele ning muudavad koodi loetavamaks ja kontrollitavaks.

Mõned asjad, mida saab lihtsalt ilma vabanduseta vaatekontrollerites vältida:

  • Võrgukoodi otse kirjutamise asemel peaks võrgukõnede eest vastutama klass NetworkManager
  • Vaatekontrollerites andmetega manipuleerimise asemel saame lihtsalt luua DataManageri klassi, mis selle eest vastutab.
  • UIViewControlleris kasutatavate UserDefaults-keelpillidega mängimise asemel saame selle jaoks luua fassaadi.

Kokkuvõtteks

Usun, et peaksime tarkvara koostama komponentidest, mis on täpselt nimetatud, lihtsad, väikesed, ühe asja eest vastutavad ja korduvkasutatavad.

Selles artiklis arutasime Kent Becki nelja lihtsa kujunduse reeglit ja tõime praktilisi näiteid, kuidas neid iOS-i arenduskeskkonnas rakendada.

Kui teile see artikkel meeldis, plaksutage kindlasti, et oma tuge näidata. Järgige mind, et vaadata veel palju artikleid, mis võivad viia teie iOS-i arendaja oskused järgmisele tasemele.

Kui teil on küsimusi või kommentaare, jätke palun siia märkus või saatke mulle e-kiri aadressil arlindaliu.dev@gmail.com.