Jak jsme došli k vlastnímu iOS toolingu?
V průběhu let, ve kterých děláme iOS vývoj, jsme narazili na spoustu nástrojů, které nám ulehčují různé aspekty naší práce. Ne každý z takových nástrojů se nám osvědčil nebo nám vyhovoval na 100%. U složitějších nástrojů jsou takové nuance akceptovatelné, jelikož řeší komplexní problém a vytvořit vlastní variantu, která nám bude 100% zapadat do naší flow, by bylo neúměrně náročné. U těch jednodušších to naopak dává velký smysl a o třech takových případech si dnes povíme.
Lokalizace aplikace
Každá naše aplikace obsahuje lokalizované texty, obrázky, popř. další assety. Pro lokalizování textů aplikace existuje spousta možností. My jsme si vybrali lokalizaci pomocí Google Spreadsheetu především pro jeho jednoduchost, protože upravit jednoduchou tabulku zvládne kdokoliv.
Ve chvíli, kdy máte vyplněnou tabulku s jednotlivými jazyky a překladovými klíči, zbývá vyřešit, jak překlady dostat do aplikace. Když jsme s lokalizací přes spreadsheet začínali, využívali jsme nástroj localize-with-spreadsheet. Dnes je už velmi zastaralý, ale v dobách, kdy jsme s ním začínali, to tak špatné nebylo. Pro naše tehdejší použití fungoval poměrně dobře.
Postupem času se náš tým vyvíjel, měnili se klienti, pro které jsme pracovali a některá omezení, která nástroj měl, nás skutečně začala limitovat. V první řadě je nástroj napsaný v Node.js a pro jeho spuštění je třeba mít ho nainstalovaný. Já si dodnes myslím, že Node.js ve stacku pro vývoj nativní aplikace spíše místo nemá, pokud se bavíme o aplikaci samotné. Dalším omezením byla nutnost mít spreadsheet publikovaný, což by se obzvlášť větším klientům nemuselo zamlouvat. A v neposlední řadě tehdejší podpora pluralizace byla žalostná nebo spíše nulová.
Tato omezení nás vedla k vytvoření vlastního nástroje AC Localization, který řeší všechny zmíněné problémy. Je napsaný ve Swiftu, tudíž kdokoliv z týmu je schopen jej upravit. Data ze spreadsheetu se stahují pomocí Google Spreadsheets API, které umí pracovat s přístupovými právy ke spreadsheetu, což řeší otázku přístupových práv. Implementace nativní pluralizace textů tak na sebe nenechala dlouho čekat. 😎
Cachování Carthage artefaktů
Dnes je náš dependency management postavený primárně kolem Carthage. Stále se nám líbí, že závislosti zkompilujeme jednou a potom až když se změní. Šetří nám to čas při vývoji i na CI.
Ve chvíli, kdy jsme Carthage začali používat, okamžitě jsme začali řešit, jak zařídit, aby se primárně na CI nekompilovaly ty samé závislosti pořád dokola. Původně jsme pouze kopírovali složku se závislostmi lokálně po CI stroji, což nebylo zrovna sofistikované. Později jsme narazili na Rome.
Rome uměl vzít zkompilované závislosti, nahrát je do S3 bucketu, odkud si je mohlo stáhnout nejen CI, ale i ostatní vývojáři z týmu. Najednou tak stačilo, aby závislosti zkompiloval jeden člen týmu a ostatní už nemuseli. Až do představení Maců s čipem Apple Silicon nám Rome fungoval také poměrně dobře, i když s nějakými výhradami – pokud jedna závislost v Cartfilu vygenerovala víc než jeden framework nebo pokud se framework jmenoval jinak než závislost, bylo potřeba specifikovat mapování.
Když Apple představil čipy M1 (a do Carthage byla doimplementována podpora pro XCFrameworky), nastal problém. Než do Rome byla doimplementována podpora pro XCFrameworky, trvalo to věčnost. Začali jsme se proto zabývat vlastní náhradou. V první řadě je Rome napsaný v Haskellu. Pokud Node.js nepatří zrovna do standardní výbavy iOS vývojáře, tak Haskell už vůbec ne.
Když jsme se začali zajímat, jak by se dalo takové cachování napsat, zjistili jsme celkem zajímavé věci. Dokud jsme používali Rome, tak nás ani nenapadlo, zda je skutečně potřeba řešit vše zmíněné mapování závislostí na vygenerované frameworky. Ve chvíli, kdy jsme se začali zajímat, jaký výstup má volání Carthage, tak se nám toto všechno zjednodušilo. Zjistili jsme, že nic takového není potřeba. Stvořili jsme proto Torino.
Torino má jednodušší konfiguraci, je napsané ve Swiftu a jelikož je psané námi pro nás, tak své cachované artefakty ukládá do GCP bucketu. Podpora pro GCP šla do Rome dopsat, ale nikomu se s tím nechtělo úplně dělat, tak jsme využívali S3. Díky tomuto nástroji je tak celé cachování pro všechny v týmu více transparentní a každý se může podívat, co Torino vlastně dělá.
Automatizace CI
Dlouhé roky jsme pro automatizaci využívali fastlane jako asi každý iOS tým na světě. Teď ruku na srdce, kolik týmů je s ním reálně spokojeno? Osobně mi fastlane jako takový nepřijde špatný, ale Ruby prostředí, na kterém je fastlane postaven, se mi nelíbí. Považuji jej za příliš nekonzistentní a nestabilní. Každý nový člen našeho týmu má typicky jinou instalaci Ruby, někdo jej nepoužívá vůbec a má systémovou “retro verzi”. Někdo updatuje přes brew, někdo využívá rbenv, někdo RVM – možných variant je poměrně dost. Často jsme řešili, že na dvou strojích se stejnými verzemi Ruby při využití Bundleru, volání fastlanu na jednom stroji prošlo a na druhém ne. Navíc čím mladší vývojáři přicházeli do týmu, tím méně měli zkušeností s Ruby, protože např. Cocoapods už jim nic neříká.
Tohle nás vedlo k zamyšlení, co vlastně po fastlanu chceme. Zjistili jsme, že toho zas tolik není:
- pustit testy
- zkompilovat appku
- archivovat appku
- vyřešit code signing credentials
- nahrát appku do Firebase App Distribution nebo do Testflightu
A to je vše. Což nezní tak složitě. Navíc na testy a kompilaci appky lze využít Tuist, který využíváme na všech našich projektech. Tohle uvědomění nás přivedlo na myšlenku, že bychom si vytvořili vlastní nástroj, který bude umět těchto pár věcí. A tak vznikl Jarvis.
Jarvis je jediný z těchto nástrojů, který není open source. Je velmi úzce zaměřen na naše potřeby a na náš stack. Zároveň vyvinout nástroj pro vlastní využití je mnohem snazší, než obecný tool jako je fastlane. Jarvis využíváme už téměř dva roky a celý tým si jej stále pochvaluje a nadpoloviční většina týmu v něm má contribution, zatímco znalost našeho fastlane byla omezena na 2-3 členy týmu.
Během vývoje Jarvise jsme šli postupně. Především část, která řeší code signing dlouho závisela na fastlanu, jelikož celá problematika byla velmi složitá. Postupné mazání fastlanu z našeho stacku vypadalo tak, že Jarvis nejdříve spoléhal na to, že ve Fastfile bude lane, která vyřeší code signing. Později Fastfile nebyl nutný vůbec a Jarvis volal Match přímo. Dnes již má Jarvis svoji implementaci “Matche”, který si dodnes nemůžeme vynachválit. Ale i to je důvod, proč Jarvis zabral suverénně nejvíc času ze všech zmíněných nástrojů, i když je nejmladší.
Přepisujeme tedy vše po svém?
Určitě ne. Všechny tyto nástroje vznikly, protože do té doby používané varianty třetích stran nám dlouhodobě nevyhovovaly nebo vyžadovaly kompromisy, které jsme nechtěli podstoupit. I dnes nejdříve zkoušíme zapojit již existující nástroje třetích stran. Neradi bychom vynalézali kolo. 🙂
Zároveň není poselstvím tohoto textu promo na naše nástroje, i když samozřejmě budeme rádi, pokud by vám zapadly do vašeho stacku. Poselstvím by mělo být – pokud máte ve stacku nástroj, kterým vám dlouhodobě pije krev, bylo by dobré se zamyslet, zda by s tím nešlo něco dělat. V první řadě se podívat na nejnovější verze již využívaných nástrojů, zda už problém někdo nevyřešil. Následně prozkoumat alternativy a až potom se rozmyslet, zda se pustit do vlastní implementace. 😎