Az egyszerűbb iOS szoftver tervezésének négy szabálya

Az 1990-es évek végén, az extrém programozás fejlesztése közben a híres szoftverfejlesztő, Kent Beck kidolgozta az egyszerű szoftver-tervezés szabályainak listáját.

Kent Beck szerint egy jó szoftverfejlesztés:

  • Az összes tesztet futtatja
  • Nem tartalmaz másolatot
  • Kifejezi a programozó szándékát
  • Minimalizálja az osztályok és módszerek számát

Ebben a cikkben arról beszélünk, hogyan lehet ezeket a szabályokat alkalmazni az iOS fejlesztői világában gyakorlati iOS példák bemutatásával és azzal, hogy miként profitálhatunk belőlük.

Az összes tesztet futtatja

A szoftvertervezés segít létrehozni egy olyan rendszert, amely a tervek szerint működik. De hogyan lehet ellenőrizni, hogy egy rendszer úgy működik-e, ahogyan azt eredetileg a terve a tervezte? A válasz az, hogy teszteket készít, amelyek validálják.

Sajnos az iOS fejlesztésében a legtöbb esetben elkerüljük a teszteket ... De egy jól megtervezett szoftver létrehozásához mindig a Swift kódot kell írnunk, a tesztelhetőség szem előtt tartásával.

Beszéljünk meg két olyan alapelvről, amelyek egyszerűbbé teszik a tesztírás és a rendszertervezést. És ezek az egységes felelősség elve és a függőség injektálása.

Egységes felelősségvállalási elv (SRP)

Az SRP kijelenti, hogy az osztálynak csak egy oka lehet a változásnak. Az SRP az egyik legegyszerűbb alapelv, és a legnehezebb helyrehozni. A felelősségi körök keverését természetesen megtesszük.

Mutasson egy példát néhány olyan kódra, amelyet igazán nehéz tesztelni, majd ezt követően reagálja az SRP használatával. Ezután beszélje meg, hogyan tette lehetővé a kód tesztelését.

Tegyük fel, hogy jelenleg be kell mutatnunk egy PaymentViewController-et a jelenlegi nézetszabályozónkból, a PaymentViewController-nek a fizetési termék árától függően konfigurálnia kell a nézetet. Esetünkben az ár változó, bizonyos külső felhasználói eseményektől függően.

A végrehajtás kódja jelenleg a következőképpen néz ki:

Hogyan tesztelhetjük ezt a kódot? Mit kell először tesztelnünk? Az árengedmény kiszámítása helyes? Hogyan lehet gátolni a fizetési eseményeket a kedvezmény tesztelésére?

Ehhez az osztályhoz a vizsgák írása bonyolult lenne, jobb módszert kell találnunk az íráshoz. Nos, először nézzük meg a nagy problémát. Kihúznunk kell függőségeinket.

Látjuk, hogy logikánk van a termék betöltésekor. Van olyan fizetési események, amelyek révén a felhasználó kedvezményes lehet. Van kedvezmények, van egy kedvezmény kiszámítása és a lista folytatódik.

Próbáljuk ezeket egyszerűen lefordítani Swift-kódra.

Létrehoztuk a PaymentManager alkalmazást, amely kezeli a kifizetésekkel kapcsolatos logikánkat, és a különálló PriceCalculator programot, amely könnyen tesztelhető. Ezen felül egy adat-betöltő, amely felelős a hálózati vagy adatbázis interakcióért a termékek betöltésekor.

Azt is megemlítettük, hogy szükségünk van egy osztályra, amely felelős az árengedmények kezeléséért. Hívjuk ezt CouponManagernek, és kezeli a felhasználói kedvezményes kuponokat is.

A Fizetés nézet-vezérlőnk ezután a következőképp néz ki:

Írhatunk olyan teszteket, mint például

  • testCalculatingFinalPriceWithoutCoupon
  • testCalculatingFinalPriceWithCoupon
  • testCouponExists

és még sok más! Különálló objektumok létrehozásával elkerüljük a felesleges másolatot, és létrehozunk egy olyan kódot is, amelyre könnyű teszteket írni.

Függőség-befecskendezés

A második elv a függőség-befecskendezés. És a fenti példákból láttuk, hogy a függőségi injektálást már használtuk a tárgyinicializálóinkon.

Két függvénynek van két fő előnye az, ha a fentiekhez hasonló módon beinjektáljuk függőségeinket. Világossá teszi, hogy milyen típusú függőségekre támaszkodnak a típusaink, és lehetővé teszi számozott objektumok beillesztését, amikor a valódi helyett tesztelni akarunk.

Egy jó módszer az, hogy protokollokat készítsünk tárgyaink számára, és az alábbiak szerint biztosítsuk a valós és a ál objektum konkrét megvalósítását:

Most könnyen eldönthetjük, hogy melyik osztályt szeretnénk injektálni függőségként.

A szoros csatlakozás megnehezíti a tesztek írását. Tehát hasonlóan, minél több tesztet írunk, annál inkább olyan elveket használunk, mint a DIP, és olyan eszközöket, mint a függőségi befecskendezés, interfészek és az absztrakció, hogy minimalizáljuk a csatolást.

A kód tesztelhetõvé tétele nemcsak kiküszöböli a megtörés iránti félelmünket (mivel azt a tesztet fogjuk írni, amely támogatni fog minket), hanem hozzájárul a tisztább kód írásához is.

A cikknek ez a része inkább arra vonatkozott, hogy hogyan lehet beírható kódot írni, mint a tényleges egységteszt írása. Ha többet szeretne megtudni az egységteszt megírásáról, akkor olvassa el ezt a cikket, ahol tesztvezérelt fejlesztés segítségével hozom létre az élet játékát.

Nem tartalmaz másolatot

A sokszorosítás a jól megtervezett rendszer elsődleges ellensége. További munkát, további kockázatot jelent, felesleges bonyolultságot jelent.

Ebben a szakaszban azt fogjuk megvitatni, hogy hogyan használhatjuk a Sablon tervezési mintát az iOS rendszerben a gyakori másolatok eltávolítására. Annak érdekében, hogy könnyebben megértsük, megújítjuk a valós csevegés megvalósítását.

Tegyük fel, hogy jelenleg alkalmazásunkban van egy szabványos csevegési szakasz. Egy új követelmény jelent meg, és most új típusú csevegést akarunk megvalósítani - egy élő csevegést. Egy olyan csevegés, amelynek legfeljebb 20 karakterből álló üzeneteket kell tartalmaznia, és ez a csevegés eltűnik, ha elhagyjuk a csevegési nézetet.

Ennek a csevegésnek ugyanazok a nézetei vannak, mint a jelenlegi csevegésünknek, de néhány eltérő szabályt fog tartalmazni:

  1. A csevegési üzenetek küldésére vonatkozó hálózati kérések különböznek.

2. A csevegõ üzeneteknek rövideknek kell lenniük, és nem lehet több, mint 20 karakter az üzenethez.

3. A csevegési üzeneteket nem szabad tartani a helyi adatbázisban.

Tegyük fel, hogy MVP architektúrát használunk, és jelenleg kezeljük a csevegő üzenetek küldésének logikáját az előadónkban. Próbáljunk új szabályokat hozzáadni az új csevegéstípusnak, az élő csevegésnek.

A naiv megvalósítás a következő lenne:

De mi történik, ha a jövőben sokkal több csevegéstípus lesz?
Ha továbbra is hozzátesszük, ha még minden funkció ellenőrzi a csevegés állapotát minden funkcióban, akkor a kód rendetlenné válik nehéz olvasni és fenntartani. Ez szintén aligha tesztelhető, és az állapot-ellenőrzést megismételnék az előadó hatókörén belül.

Itt használják a sablonmintát. A sablonminta akkor használatos, amikor több algoritmus megvalósítására van szükség. A sablont meghatározzuk, majd további variációkkal építjük fel. Használja ezt a módszert, ha a legtöbb alosztálynak ugyanazt a viselkedést kell végrehajtania.

Létrehozhatunk egy protokollt a Chat Presenter számára, és különválaszthatjuk azokat a módszereket, amelyeket a Chat Presenter Phase konkrét objektumai különféleképpen hajtanak végre.

Most elő tudjuk állítani az előadónkat, hogy megfeleljen az IChatPresenter előírásainak

Bemutatónk most kezeli az üzenetküldést azáltal, hogy magában foglalja a közös funkciókat, és delegálja azokat a funkciókat, amelyeket másként lehet végrehajtani.

Most már olyan objektumokat is létrehozhatunk, amelyek megfelelnek az előadó fázisának, és ezeket a funkciókat igényeik szerint konfigurálhatjuk.

Ha függőségi injekciót alkalmazunk a nézet-vezérlőben, akkor ugyanazt a nézet-vezérlőt két különböző esetben újra felhasználhatjuk.

A Design Patterns használatával valóban egyszerűsíthetjük iOS-kódunkat. Ha többet szeretne tudni erről, a következő cikk további magyarázatot nyújt.

Kifejező

A szoftverprojekt költségeinek nagy része a hosszú távú karbantartásból származik. A szoftverfejlesztők számára kötelező a könnyen olvasható és karbantartható kódírás.

Kifejezőbb kódot kínálhatunk a jó elnevezés, az SRP és az Írás teszt használatával.

elnevezési

Az első számú dolog, ami kifejezőbbé teszi a kódot - és ez az elnevezés. Fontos olyan nevek írása, amelyek:

  • Feltárja a szándékot
  • Kerülje a dezinformációt
  • Könnyen kereshetők

Az osztályok és függvények elnevezésekor jó trükk az, ha főnév vagy főnév-mondatot használunk osztályokhoz és felhasználói igeket, vagy igemondat-neveket a módszerekhez.

Különböző tervezési minták használatakor is jó, ha az osztálynévhez mellékeli a mintaneveket, például a parancs vagy a látogató. Tehát az olvasó azonnal tudná, hogy a mintát milyen módon használják anélkül, hogy az összes kódot el kellene olvasnia ahhoz, hogy megtudja.

Az SRP használata

Egy másik dolog, ami kifejezővé teszi a kódot, az a fentiekben említett egységes felelősségvállalási elv használata. Kifejezheti magát úgy, hogy a funkcióit és osztályait kicsi és egyetlen célra tartja. A kis osztályok és funkciók általában könnyen megnevezhetők, könnyen megírhatók és könnyen érthetők. Egy funkció csak egy célra szolgálhat.

Írásbeli teszt

A tesztek írása szintén sok egyértelműséget hoz, különösen akkor, ha a régi kóddal dolgozunk. A jól megírt egységi tesztek szintén kifejezőek. A tesztek elsődleges célja dokumentációként szolgálni példaként. A tesztek elolvasójának képesnek kell lennie arra, hogy gyorsan megértse, mi az osztály lényege.

Minimalizálja az osztályok és módszerek számát

Az osztály funkcióinak rövidnek kell lenniük, a funkciónak mindig csak egy dolgot kell végrehajtania. Ha egy funkciónak túl sok sora van, akkor lehet, hogy olyan műveleteket hajt végre, amelyek két vagy több különálló funkcióra oszthatók.

Jó megközelítés, ha megszámoljuk a fizikai vonalakat, és megpróbálunk maximálisan négy-hat funkciós sort megcélozni, a legtöbb esetben bármi, ami meghaladja az ezen vonalak számát, nehezen olvasható és fenntartható.

Az iOS rendszerében jó ötlet a konfigurációs hívások aprítása, amelyeket általában a viewDidLoad vagy a viewDidAppear függvényeknél végezzünk.

Ilyen módon minden funkció kicsi és fenntartható lenne egyetlen rendetlenség viewDidLoad funkció helyett. Ugyanez vonatkozik az alkalmazottra. Kerülnünk kell minden konfiguráció eldobását azdidFinishLaunchingWithOptions módszerrel és külön konfigurációs függvényekkel, vagy még jobb konfigurációs osztályokkal.

A funkciókkal egy kicsit könnyebb megmérni, hogy hosszan vagy röviden tartjuk-e. A legtöbb alkalommal csak a fizikai vonalak megszámlálására támaszkodhatunk. Az osztályoknál más mércét használunk. Számolunk a felelősséggel. Ha egy osztálynak csak öt módszere van, ez nem azt jelenti, hogy az osztály kicsi, lehet, hogy túl sok felelősséggel tartozik csak ezekkel a módszerekkel.

Az iOS-okban ismert probléma az UIViewControllers nagy mérete. Igaz, hogy az apple nézet vezérlő kialakításával nehéz ezeket az objektumokat egyetlen célra tartani, de meg kell próbálnunk a legjobbat.

Számos módja van annak, hogy az UIViewControllers kicsi legyen. Előnyben részesítem egy olyan architektúra használatát, amely jobban elkülöníti az érveket, mint például a VIPER vagy az MVP, de ez nem azt jelenti, hogy nem tehetjük jobbá az apple MVC-ben sem.

Ha annyi aggodalmat különítünk el, elérhetünk elég tisztességes kódot bármilyen architektúrával. Az ötlet az, hogy egycélú osztályokat hozzunk létre, amelyek segítséget nyújthatnak a nézővezérlők számára, és a kód olvashatóbbá és tesztelhetőbbé teszik.

Néhány dolog, amelyet egyszerűen el lehet kerülni anélkül, hogy kifogás nélkül lennék látványvezérlők:

  • A hálózati kód közvetlen írása helyett a NetworkManager osztálynak kell lennie, amely a hálózati hívásokért felel
  • Ahelyett, hogy az adatokat manipulálnánk a nézetvezérlőkben, egyszerűen létrehozhatunk egy DataManager osztályt, amely azért felelős.
  • Ahelyett, hogy a UserDefaults karakterláncokkal játszanánk az UIViewController alkalmazásban, homlokzatot hozhatunk létre rajta.

Összefoglalva

Úgy gondolom, hogy a szoftvereket olyan komponensekből kell összeállítanunk, amelyek pontosan megnevezésre kerülnek, egyszerűek, kicsik, egyért felelősek és újrafelhasználhatók.

Ebben a cikkben a Kent Beck egyszerű tervezésének négy szabályát tárgyaltuk, és gyakorlati példákat mutattunk be arra, hogyan tudjuk ezeket az iOS fejlesztői környezetben megvalósítani.

Ha tetszett ez a cikk, akkor feltétlenül tapsoljon, hogy mutassa meg támogatását. Kövess engem, és még sok olyan cikket megnézhetsz, amelyek az iOS-fejlesztői képességeidet a következő szintre vihetik.

Ha bármilyen kérdése vagy észrevétele van, nyugodtan hagyjon itt jegyzetet, vagy írjon e-mailt az arlindaliu.dev@gmail.com e-mail címre.