7 tipp a Kotlin-könyvtár ragyogásának növelésére

Előszó

Amikor új nyelven kezdjük el a programozást, először gyakran ragaszkodunk a kialakult paradigmákhoz és szokásokhoz, miközben programozzuk a már ismert nyelven. Noha az elején rendben tűnhet, azoknak az embereknek, akik egy ideje azon a nyelven programoznak, amelyet próbálsz elsajátítani, ez az érdesség nyilvánvaló.

Amikor csak két évvel ezelőtt váltottam át a Java-ról a Kotlin-re, alapvetően „Java-programozást, de Kotlin-ban” végeztem. Annak ellenére, hogy Kotlin olyan volt, mint egy friss levegő lélegzete számomra, Android-mérnökként mindazokat a csúnya-gazdag kiterjesztési funkciókat és adatosztályokat használtam, amelyek nem mindig voltak konzisztensek. Megváltoztattam a meglévő Java-kódot Kotlin-ként, és némileg nézegettem rá néhány ötletet, hogy emlékezzem meg, amikor API-kat terveztem Kotlin különböző újrahasznosítható összetevőire vagy könyvtáraira.

Itt, a BUX-nál, két alkalmazáson dolgozunk, amelyeknek pár megosztott könyvtára van. Míg a Stocks alkalmazást (amely még nem jelent meg) Kotlinban írták a kezdetektől, az első CFD alkalmazást Java-ban írták, majd egy idő után Kotlin-ba konvertálták. Ebben a pillanatban a CFD alkalmazás 78,7% Kotlin, ami azt jelenti, hogy továbbra is dolgozunk rajta, és ezért fontos figyelni a könyvtári API-kra, amelyeket két csapat tart fenn, amelyek egyszerre használják a Java-t és a Kotlin-t.

Tehát ha van meglévő Kotlin vagy Java könyvtára, amelyet Kotlinify-nak szeretne használni, vagy ha API-t tervez a Kotlin használatával, akkor vedd fel velem néhány ötletet, amit megtehetsz a könyvtár felhasználói életének megkönnyítése érdekében.

1. Bővítő funkciók

Az esetek nagy részében, amikor meglévő osztályt kell új funkciókkal kibővítenie, vagy valamilyen kompozíciót kell használni, vagy új osztályt kell létrehoznia (amely széles körű felhasználás esetén ugyanolyan törékenyvé teszi osztályhierarchiáját, mint az IKEA üvegpoharai). Nem számít, hogy mi az Ön preferenciája, Kotlin-nak saját erre a válaszára, úgynevezett Bővítési funkciók. Dióhéjban lehetővé teszi, hogy egy új funkciót egy meglévő osztályhoz illesszen egy nagyon ügyes szintaxissal. Például az Androidon a következő módon határozhat meg egy új módszert a Nézet osztályhoz:

Ezt szem előtt tartva, sok könyvtár, amely kiegészítő funkciókat biztosít a meglévő osztályok számára (pl .View, Context stb.) Ahelyett, hogy dekorátorokat, statikus gyári módszereket vagy valami mást használna, előnyös lehet abban, hogy kiterjesztési funkcióikként zökkenőmentesen biztosítják funkciójukat, mintha ez a funkcionalitás az eredeti osztályokban már a kezdetektől létezik.

2. Alapértelmezett argumentumértékek

A Kotlin-t eredetileg a Java tömör, ügyes és rendezett verziójára tervezték, és kiderül, hogy ezt az alapértelmezett függvény argumentumértékekkel nagyon jól csinálja. Az API szolgáltatója képes megadni az alapértelmezett értékeket azoknak az argumentumoknak, amelyek kihagyhatók. Nagyon meglepődnék, ha nem látott hasonló kódot az SQLite használatával az Androidon:

Annak ellenére, hogy több módszer hibája van, mint azoknak a csúnya nulloknak a végén, itt nem azért vagyok, hogy megítéljem, hanem azt mondjam, hogy ezek az idők eltűntek, és komolyan megkérdőjelezem a Kotlin így írt kódját. Sok ilyen példa létezik, de szerencsére most jobban tudunk csinálni, és ha bizonyos hangolási paraméterekkel ellát egy külső API-t, ahelyett, hogy építőkészüléket biztosítana, vagy ezen felül, fontolja meg az alapértelmezett argumentumértékek használatát. Ennek legalább két előnye van: egyrészt nem kényszeríti a felhasználót a választható paraméterek megadására, vagy bármire, amit előre meg tud jósolni, és a második az, hogy a felhasználónak lesz egy alapértelmezett konfigurációja, amely csak működni fog. -doboz:

Nagyon fontos megemlíteni, hogy ha ezeket az argumentumokat az alapértelmezett értékekkel a végére helyezi, akkor a felhasználónak nem kell megneveznie a kötelező paraméterek nevét.

3. Tárgyak

Előfordult, hogy Önnek is magadnak kellett megvalósítania a Singleton mintát a Java-ban? Valószínűleg volt, és ha igen, akkor tudnia kell, hogy milyen nehézkes lehet néha:

Különböző megvalósítások léteznek, mindegyiknek megvan a maga előnye és hátránya. Kotlin a Singleton mintázat megvalósításának mind az 50 árnyalatát tárgyalja egyetlen objektum deklarációnak nevezett struktúrával. Nézd, ne, nincs „dupla ellenőrzésű reteszelés”:

Ami a szintaxistól eltérően remek, az, hogy az objektum deklaráció inicializálása egyrészt szálbiztos, másrészt lazán inicializálódik, amikor először fér hozzá hozzá:

Az olyan könyvtárak esetében, mint a Fabric, a Glide, a Picasso vagy bármely más, amely az objektum egyetlen példányát használja az általános könyvtári API fő belépési pontjaként, ez egy természetes út a továbblépéshez, és nincs ok arra, hogy a régi Java módszert használja csináld ugyanazokat a dolgokat.

4. Forrás fájlok

Ugyanúgy, ahogy Kotlin átgondolja a sok szintaktikai kihívást, amellyel napi szinten szembesülünk, ezenkívül átgondolja a létrehozott kód megszervezésének módját is. A Kotlin forrásfájljai több olyan deklaráció otthonaként szolgálnak, amelyek szemantikailag közel állnak egymáshoz. Kiderült, hogy azok a tökéletes helyek az ugyanazon osztályhoz kapcsolódó kiterjesztési funkciók meghatározására. Nézze meg ezt a Kotlin forráskódból származó egyszerűsített kivonatot, ahol a szöveg manipulálásához használt kiterjesztési funkciók ugyanabban a „Strings.kt” fájlban találhatók:

Használatának másik megfelelő példája az API-val történő kommunikációs protokoll meghatározása, valamint az adatosztályok és az interfészek egyetlen forrásfájlban. Ez lehetővé teszi a felhasználó számára, hogy ne veszítse el a figyelmét azáltal, hogy átvált a különböző fájlok között, miközben követi a folyamatot:

De ne menjen túl messzire, mivel kockáztathatja, hogy túlterhel egy felhasználót a fájl méretével, és átalakítja azt RecyclerView osztályba ~ 13 000 sorral .

5. Szokások

Ha a könyvtár több szálat használ a hálózathoz való hozzáféréshez vagy bármilyen más, hosszan futó munka elvégzéséhez, fontolja meg az API felfüggesztési funkciókkal való ellátását. A Kotlin 1.3-tól kezdve a korutinák már nem kísérleti jellegűek, ami remek alkalom arra, hogy elkezdje őket a termelésben, ha korábban már kétségei merültek fel. A szokásos esetekben jó alternatíva lehet az RxJava által megfigyelhető és az aszinkron hívások kezelésének más módjai számára. Amit korábban már láthatott, az API-val tele van metódus eredmény visszahívással, vagy az Rx hype idején, egyetlen vagy komplett csomagolással:

De most a Kotlin korszakában vagyunk, így azt a testvérhasználat támogatására is tervezhetnénk:

Annak ellenére, hogy a csúcsminőség jobban teljesít, mint a régi jó Java szálak, mivel könnyebbek, jelentősen hozzájárulnak a kód olvashatóságához:

6. Szerződések

A stabil irányelvek mellett a Kotlin 1.3 bemutatja a fejlesztőknek a fordítóval való kapcsolattartás módját is. A szerződés egy új szolgáltatás, amely lehetővé teszi számunkra, hogy könyvtárfejlesztőként megoszthassuk a fordítóval az ismereteinket az úgynevezett effektusok megadásával. Annak érdekében, hogy könnyebben megértsük, mi a hatása, hozjuk a legközelebbi analógiát a Java-ról. Legtöbben valószínűleg már láttak, vagy akár használtak már a Guava-i Precondition osztályt sok állítással és annak adaptációjával olyan könyvtárakban, mint a Dagger, amelyek nem akarnak teljes könyvtárat letölteni:

Ha az átadott referenciaobjektum nulla, akkor a módszer kivételt jelenít meg, és a módszer után elhelyezett fennmaradó kódot nem fogják elérni, tehát biztonságosan feltételezhetjük, hogy a referencia ott semmi sem lesz. Itt jön a probléma - bár rendelkezünk ezzel a tudással, ez nem segít a fordítónak ugyanazt a feltételezést tenni. Itt jelennek meg a @ Nullable és a @ NotNull kommentárok, mivel ezek pusztán azért vannak, hogy segítsék a fordító megérteni a feltételeket. Ez az, amire valójában van egy hatás - ez egy tipp egy fordítónak, amely segít a kifinomultabb kód elemzésben. Egy olyan meglévő hatás, amelyet már látott Kotlin-ben, egyfajta intelligens casting a blokkban, annak típusának ellenőrzése után:

A Kotlin-fordító már okos, és nem kétséges, hogy tovább javul a jövőben, de a szerződések bevezetésével a Kotlin-fejlesztők könyvtári fejlesztőkként felhatalmazták számunkra, hogy javítsuk azt azáltal, hogy saját intelligens ötleteket írunk, és olyan effektusokat hozzunk létre, amelyek segítik a felhasználókat abban, hogy írjon tisztább kódot. Írjuk át újra a checkNotNul módszert Kotlinben a Contracts segítségével, hogy bemutassák képességeiket:

Különböző hatások is vannak, de ez nem egy teljes méretű bevezetés a szerződésekbe, és remélem, hogy ez csak egy ötletet adott neked arról, hogy miként profitálhat belőle. Ezen felül a Githubon található stdlib tároló számos hasznos szerződéses példát tartalmaz, amelyeket érdemes megnézni.

Nagy hatalommal jár a nagy felelősségvállalás, és a szerződések sem kivétel. Bármit is kijelent a szerződésében, a fordító a Szent Bibliaként kezeli. Technikai szempontból a fordító nem kérdőjelezi meg és nem érvényesíti az ott írt mindent, ezért gondosan ellenőriznie kell a kódot, és ellenőriznie kell, hogy nincs-e következetlenség.

Amint a @ExperimentalContracts kommentárból észrevette, a szerződések továbbra is a kísérleti szakaszban vannak, így nem csak az API változhat az idő múlásával, hanem néhány új funkció is származhat belőle, mivel egyre érettebbé válik.

7. Java interoperabilitás

A kotlini könyvtár írásakor az is fontos, hogy a közönséget szélesebb körben megőrizze azáltal, hogy zökkenőmentes integrációs élményt nyújt a fejlesztő társainak, akik Java-t használnak. Ez nagyon fontos, mivel még mindig sok olyan projekt van, amely ragaszkodik a Java-hoz, és különféle okokból nem akarják megírni a meglévő kódot. Mivel azt akarjuk, hogy a Kotlin közösség gyorsabban növekedjen, jobb, ha megengedjük, hogy ezek a projektek fokozatosan, lépésről lépésre tegyék meg. Természetesen nem olyan napos a fal ezen a oldalán, de vannak olyan dolgok, amelyeket könyvtárfenntartóként megtehetsz.

Az első dolog az, hogy a Kotlin kiterjesztési függvényeket a Java-ban csúnya statikus módszerekké állítják össze, ahol a módszer első argumentuma egy vevő típusú:

Noha itt nincs igazán sok ellenőrzés, legalább megváltoztathatja a generált osztály nevét, ha hozzáadja a következő sort a forrásfájl elejére, amely a fenti csomagszintű funkciókat tartalmazza:

Egy másik példa arra, hogyan lehet egy generált kódot kissé befolyásolni, a társobjektum-módszerek használatához kapcsolódik:

Arra kényszerítheti Kotlin-t, hogy statikus osztályokat generáljon a társobjektumban definiált függvények helyett a @JvmStatic kommentár használatával:

Összehasonlítva Kotlin-rel, a Java-ban két hasonló névvel ellátott funkció, de a különféle általános típusok nem definiálhatók együtt a típus törlése miatt, tehát a Java felhasználók számára show-stop lehet. Remélhetőleg elkerülheti azt, ha a metódus aláírását másik megjegyzéstel változtatja meg:

És utoljára, de nem utolsósorban az a képesség, hogy a Java felhasználók számára meghatározzuk az ellenőrzött kivételeket a funkciókban, bár ezek nem közvetlenül elérhetők Kotlinben. Ez nagyon hasznos lehet, mivel a Java és Kotlin kivételével kapcsolatos nyilatkozatok paradigma különbözik:

Az itt található dolgok többsége nem kötelező, ám ezek minden bizonnyal forrást jelentenek a könyvtár számára a Java felhasználók számára.

Alsó sorban

A kotlin egy nagyszerű nyelv, amely folyamatosan halad előre, és sok mindent megtehet a könyvtárral kapcsolatban, hogy zökkenőmentes legyen a használata. A fent említett ötletek közül az elsőként próbálj felhasználóként lenni, és gondold ki, mit szeretnél, és hogyan használnád. Az Ördög a részletekben van, és remélhetőleg ezek az apró dolgok, amelyeket alkalmazsz, a felhasználók javát szolgálják, és jobb élményt nyújtanak. Egészségére!