Četiri pravila jednostavnijeg dizajna softvera za iOS

Krajem 1990-ih, tijekom razvoja ekstremnog programiranja, poznati programer softvera Kent Beck sastavio je popis pravila za jednostavno dizajniranje softvera.

Prema Kent Becku, dobar softverski dizajn:

  • Pokreće sve testove
  • Ne sadrži dupliciranje
  • Izražava namjeru programera
  • Minimizira broj časova i metoda

U ovom ćemo članku raspravljati o tome kako se ta pravila mogu primijeniti na svijet razvoja iOS-a pružajući praktične primjere iOS-a i razgovarajući o tome kako od njih možemo imati koristi.

Pokreće sve testove

Dizajn softvera pomaže nam u stvaranju sustava koji djeluje kako je predviđeno. Ali kako možemo potvrditi da će sustav djelovati onako kako je prvotno dizajnirao? Odgovor je stvaranjem testova koji to potvrđuju.

Nažalost, testovi u svemiru za razvoj iOS-a se najčešće izbjegavaju ... Ali da bismo stvorili dobro dizajniran softver, uvijek bismo trebali pisati Swift kod sa predvidljivošću.

Razgovarajmo o dva principa koji pojednostavljuju pisanje testova i dizajn sustava. A oni su princip pojedinačne odgovornosti i ubrizgavanje ovisnosti.

Načelo jedinstvene odgovornosti (SRP)

SRP navodi da bi klasa trebala imati jedan i samo jedan razlog za promjenu. SRP je jedno od najjednostavnijih načela i jedno od najtežih za ispraviti se. Miješanje odgovornosti je nešto što radimo prirodno.

Navedimo primjer nekog koda koji je zaista teško testirati, a nakon toga ga ponovno prilagodite pomoću SRP-a. Zatim razgovarajte o tome kako je to kôd napravio provjerljivim.

Pretpostavimo da trenutno moramo predstaviti PaymentViewController s našeg trenutnog kontrolera vlasničkog pregleda, PaymentViewController bi trebao konfigurirati svoj pogled, ovisno o cijeni proizvoda za plaćanje. U našem slučaju, cijena je promjenjiva, ovisno o nekim vanjskim događajima korisnika.

Kôd za ovu implementaciju trenutno izgleda ovako:

Kako možemo testirati ovaj kôd? Što prvo treba testirati? Je li popust na cijenu pravilno izračunan? Kako možemo ismijavati događaje plaćanja kako bismo testirali popust?

Pisanje testova za ovaj razred bilo bi komplicirano, trebali bismo pronaći bolji način da ga napišemo. Pa, prvo se pozabavimo velikim problemom. Moramo razdvojiti svoje ovisnosti.

Vidimo da imamo logiku za učitavanje našeg proizvoda. Imamo događaje plaćanja koji korisniku omogućuju popust. Imamo popuste, obračun popusta i lista se nastavlja.

Pokušajmo ih jednostavno prevesti u Swift kod.

Stvorili smo PaymentManager koji upravlja našom logikom plaćanja i odvojeni PriceCalculator koji je lako testirati. Također, alat za punjenje podataka koji je odgovoran za interakciju mreže ili baze podataka za učitavanje naših proizvoda.

Spomenuli smo i da nam je potrebna klasa odgovorna za upravljanje popustima. Nazovimo ga CouponManager i neka tako dobro upravlja kuponima za popust korisnika.

Naš kontroler prikaza plaćanja tada može izgledati na sljedeći način:

Sada možemo pisati testove poput

  • testCalculatingFinalPriceWithoutCoupon
  • testCalculatingFinalPriceWithCoupon
  • testCouponExists

i mnogi drugi! Stvaranjem zasebnih objekata sada izbjegavamo nepotrebno kopiranje, a također smo stvorili i kôd na koji je lako pisati testove.

Ubrizgavanje ovisnosti

Drugi princip je ubrizgavanje zavisnosti. Iz gornjih primjera smo vidjeli da smo već koristili injekciju ovisnosti o našim objektnim inicijalizatorima.

Dvije su glavne prednosti ubrizgavanja naših ovisnosti kao gore. Jasno nam pokazuje na koje se ovise naše vrste i omogućava nam umetanje podsmiješnih predmeta kada želimo testirati umjesto pravih.

Dobra tehnika je kreiranje protokola za naše objekte i pružanje konkretne implementacije stvarnim i ismijanim objektom kao što je sljedeće:

Sada se lako može odlučiti koju klasu želimo uvesti kao ovisnost.

Čvrsto spajanje otežava pisanje testova. Dakle, slično, što više testova pišemo, više koristimo principe poput DIP-a i alate poput ubrizgavanja ovisnosti, sučelja i apstrakcije za minimaliziranje povezivanja.

Ako kôd postane testiraniji, ne samo da eliminira naš strah da ga prekršimo (jer ćemo napisati test koji će nas poduprijeti), već i pridonosi pisanju čistijeg koda.

Ovaj dio članka bavio se više načinom pisanja koda koji će biti testiran nego pisanjem stvarnog jediničnog testa. Ako želite naučiti više o pisanju jedinice ispitivanja, možete pogledati ovaj članak u kojem stvaram igru ​​života koristeći razvojni test.

Ne sadrži dupliciranje

Umnožavanje je glavni neprijatelj dobro dizajniranog sustava. Predstavlja dodatni rad, dodatni rizik, dodaje nepotrebnu složenost.

U ovom ćemo dijelu raspravljati o tome kako možemo koristiti obrazac dizajna predloška za uklanjanje uobičajenih duplikacija u iOS-u. Da bismo ga lakše razumjeli idemo na refactor provedbu chata u stvarnom životu.

Pretpostavimo da trenutno imamo u svojoj aplikaciji standardni odjeljak za chat. Pojavljuje se novi zahtjev i sada želimo implementirati novu vrstu chata - chat uživo. Chat koji treba sadržavati poruke s najviše 20 znakova, a ovaj će chat nestati kad odbacimo prikaz chata.

Ovaj će chat imati iste prikaze kao i naš trenutačni chat, ali imat će nekoliko različitih pravila:

  1. Mrežni zahtjev za slanje chat poruka bit će različit.

2. Poruke chata moraju biti kratke, ne više od 20 znakova za poruku.

3. Poruke chata ne smiju ostati u našoj lokalnoj bazi podataka.

Pretpostavimo da koristimo MVP arhitekturu i da trenutno upravljamo logikom slanja chat poruka u našem prezentatoru. Pokušajmo dodati nova pravila za našu novu vrstu chata pod nazivom live-chat.

Naivna primjena bila bi sljedeća:

Ali što će se dogoditi ako ćemo ubuduće imati mnogo više vrsta chata?
Ako nastavimo dodavati ako u svakoj funkciji provjeravamo stanje našeg chata, kôd će postati neuredan za čitanje i održavanje. Također, teško je provjeriti i državna provjera će se duplicirati u cijelom dometu prezentatora.

Ovdje se koristi obrazac predloška. Uzorak predloška koristi se kada nam je potrebno višestruka implementacija algoritma. Predložak je definiran i nadograđen uz daljnje varijacije. Koristite ovu metodu kada većina podrazreda mora implementirati isto ponašanje.

Možemo stvoriti protokol za Chat Presenter i odvajamo metode koje će različiti implementirati konkretni objekti u fazama Chat Presenter.

Sada našeg prezentatora možemo učiniti sukladnim IChatPresenteru

Naš Presenter sada obrađuje slanje poruka pozivanjem uobičajenih funkcija unutar sebe i delegira funkcije koje se mogu drugačije implementirati.

Sada možemo pružiti Stvaranje objekata koji se podudaraju s fazama prezentatora i konfigurirati ove funkcije na temelju njihovih potreba.

Ako koristimo ubrizgavanje ovisnosti u našem regulatoru prikaza, sada možemo ponovo upotrijebiti isti kontroler pogleda u dva različita slučaja.

Korištenjem dizajnerskih uzoraka stvarno možemo pojednostaviti svoj iOS kod. Ako želite znati više o tome, sljedeći članak daje dodatno objašnjenje.

izražajan

Većina troškova softverskog projekta nalazi se u dugoročnom održavanju. Programerima softvera potrebno je pisati jednostavan za čitanje i održavanje koda.

Možete ponuditi ekspresivniji kôd pomoću dobrog naziva Naming, SRP i Writing.

imenovanje

Broj jedna stvar koja kôd čini ekspresivnijom - a to je imenovanje. Važno je napisati imena koja:

  • Otkrivanje namjere
  • Izbjegavajte dezinformacije
  • Lako ih možete pretraživati

Kada je u pitanju imenovanje klasa i funkcija, dobar je trik upotreba imenice ili imenske fraze za klase i korisničke glagole ili nazive glagolskih fraza za metode.

Također kada koristite različite obrasce dizajna, ponekad je dobro dodati nazive uzoraka poput Command ili Visitor u naziv klase. Tako bi čitatelj odmah znao koji se obrazac koristi tamo, a da ne mora čitati cijeli kôd da bi saznao o tome.

Korištenje SRP-a

Druga stvar koja koda čini izražajnim je korištenje principa jedinstvene odgovornosti koji je spomenut gore. Možete se izraziti zadržavajući svoje funkcije i časove malim i u jednu svrhu. Male razrede i funkcije obično je jednostavno imenovati, lako ih je napisati i lako ih je razumjeti. Funkcija bi trebala služiti samo u jednu svrhu.

Pismeni test

Pisanje testova također donosi puno jasnoće, posebno kada se radi sa naslijeđenim kodom. Dobro napisani testovi jedinice također su ekspresivni. Primarni je cilj testova djelovati kao dokumentacija na primjeru. Netko tko čita naše testove trebao bi biti u stanju brzo razumjeti o čemu se radi.

Smanjite broj klasa i metoda

Funkcije klase moraju ostati kratke, funkcija bi uvijek trebala raditi samo jedno. Ako funkcija ima previše linija, to bi moglo biti slučaj da ona obavlja radnje koje se mogu razdvojiti na dvije ili više zasebnih funkcija.

Dobar je pristup računati fizičke linije i pokušati ciljati na maksimalno četiri do šest linija funkcija, a u većini slučajeva sve što pređe više od onog broja linija može biti teško pročitati i održati.

Dobra ideja u iOS-u je usitniti konfiguracijske pozive koje obično radimo na funkcijama viewDidLoad ili viewDidAppear.

Na taj bi način svaka od funkcija bila mala i održiva, umjesto funkcije nereda viewDidLoad. Isto bi se trebalo primjenjivati ​​na delegata aplikacije. Trebali bismo izbjegavati bacanje svake konfiguracijske metode ondidFinishLaunchingWithOptions i zasebne konfiguracijske funkcije ili još bolje konfiguracijske klase.

Pomoću funkcija malo je lakše izmjeriti zadržavamo li je dugo ili kratko, većinu vremena se možemo osloniti samo na brojanje fizičkih linija. Kod nastave koristimo drugačiju mjeru. Računamo na odgovornosti. Ako klasa ima samo pet metoda, to ne znači da je klasa mala, možda postoji previše odgovornosti samo s tim metodama.

Poznati problem u iOS-u je velika veličina UIViewControllers. Istina je da je dizajnom regulatora za pregled jabuka teško držati ove objekte u jednoj jedinoj svrsi, ali trebali bismo se potruditi.

Mnogo je načina da UIViewControllers učinim malim mojim sklonom korištenje arhitekture koja ima bolje razdvajanje briga poput VIPER-a ili MVP-a, ali to ne znači da i jabučni MVC ne možemo poboljšati.

Pokušavajući odvojiti što više briga možemo postići prilično pristojan kod s bilo kojom arhitekturom. Ideja je stvoriti jednonamjenske klase koje mogu poslužiti kao pomoć pomoćnim kontrolerima i učiniti kôd čitljivijim i testiranijim.

Neke stvari koje se mogu jednostavno izbjeći bez izgovora u pogledu kontrolera su:

  • Umjesto da direktno pišete mrežni kôd, trebao bi biti NetworkManager klasa koja je odgovorna za mrežne pozive
  • Umjesto da manipuliramo podacima u preglednicima kontrolera, jednostavno možemo stvoriti DataManager klasu koja je za to odgovorna.
  • Umjesto da se igramo s nizovima UserDefaults u UIViewController, preko toga možemo stvoriti fasadu.

U zaključku

Vjerujem da bismo trebali sastaviti softver iz komponenti koje su točno imenovane, jednostavne, male, odgovorne za jednu stvar i višekratnu upotrebu.

U ovom smo članku raspravljali o četiri pravila jednostavnog dizajna Kent Beck i dali praktične primjere kako ih možemo implementirati u iOS razvojno okruženje.

Ako ste uživali u ovom članku, pobrinite se da pljeskate kako biste pokazali svoju podršku. Slijedite me da biste pregledali još mnogo članaka koji će vaše vještine iOS Developer-a podići na novu razinu.

Ako imate bilo kakvih pitanja ili komentara, slobodno ovdje ostavite bilješku ili mi pošaljite e-poštu na arlindaliu.dev@gmail.com.