03 — Mobilā izstrāde

iOS, Android, vairāku platformu un backendi aiz tiem

Mobilās lietotnes, kas piegādātas reāliem lietotājiem — un palika piegādātas — vairāk nekā vienpadsmit gadus.

Natīvais iOS un Android to pašu valodās, React Native un Flutter tur, kur tie der, un backendi, keši un mākoņi, kas padara tālruni par vairāk nekā plānu apvalku. Vienpadsmit gadu trase ir tas, kas pārējo padara ticamu.

Pamats

Esmu pavadījis vairāk nekā vienpadsmit gadus, būvējot un piegādājot mobilās lietotnes reāliem lietotājiem — un tieši šis viens fakts padara katru citu apgalvojumu šajā lapā lasīšanas vērtu.

Ikviens var uzskaitīt frameworkus. Apliecinājums, kas svarīgs, ir ilgmūžība: lietotnes, ko reāli cilvēki instalēja, paturēja un lietoja iOS, Android un Windows platformās vairāk nekā desmitgadi. Vienpadsmit gadu trase nav rindiņa CV — tā ir pierādījums, ka zemāk esošie lēmumi tika pieņemti zem spiediena no programmatūras, kurai bija jāturpina darboties pēc palaišanas.

Es strādāju natīvi vispirms. iOS tas nozīmē Swift un Objective-C ar SwiftUI, Core Data, Core Animation un SiriKit; Android tas nozīmē Kotlin un Java pret Android SDK daudzās OS versijās. Tieši šī natīvā tekošā prasme padara vairāku platformu darbu — React Native un Flutter augstā līmenī, Xamarin darba līmenī — par apzinātu izvēli, nevis veidu, kā izvairīties no platformas.

Un mobilā lietotne nekad nav tikai klients. Aiz tās sēž backendi Node, Spring Boot, Django, Flask, Rails un Go, eksponējot REST un GraphQL, balstīti uz SQLite ierīcē un Redis serverī, izvietoti uz Firebase, AWS un Google Cloud. Lapa, kas seko, ir visa šī virsma, izstāstīta tā, kā es to patiešām būvēju.

0+

gadi, piegādājot mobilās lietotnes reāliem lietotājiem — iOS, Android un Windows platformās

0

natīvās platformas, uzturētas to pašu valodās — Swift/Objective-C un Kotlin/Java

0

vairāku platformu steki, ko ekspluatēju augstā līmenī — React Native un Flutter

0

backend frameworki, ko savienoju ar mobilajiem klientiem, no Node līdz Go

Platformu matrica

Divas natīvās platformas, divi vairāku platformu steki, viena Windows virsma.

Pirmais lēmums jebkurā mobilajā projektā ir, uz kā būvēt, un tā reti ir viena un tā pati atbilde divreiz. Zemāk esošā matrica ir tas, kā es par to spriežu: natīvais iOS un Android katrs savā valodā, divi vairāku platformu steki, ko ekspluatēju augstā līmenī, un Windows virsma, kas notur godīgu koplietoto loģiku. Diagramma kartē valodas un frameworkus uz platformām, nevis izliekas, ka viens rīks aptver visu.

VALODA MĒRĶIS Swift / ObjC Kotlin / Java React Native Flutter iOS Android Windows nepārtraukts = natīvā tekošā prasme · plāns = vairāku platformu tvērums

Valodas un frameworki, kartēti uz platformām

Matrica, nevis monolīts — katra platforma valodā, ko tā atalgo.

iOS saņem Swift un Objective-C; Android saņem Kotlin un Java; Windows saņem savu klientu. React Native un Flutter aptver veikalus, kad UI necīnās ar platformu, un kolonna pa labi parāda, kur katrs rīks patiešām nokļūst.

Matricas lasīšana ir darbs: tā es izlemju, vai funkcija ir natīva, vairāku platformu vai plāns klients virs koplietota backenda, pirms uzrakstīta kaut viena UI rindiņa.

  • iOS — Swift, Objective-C, SwiftUI, Core Data
  • Android — Kotlin, Java, Android SDK
  • Vairāku platformu — React Native, Flutter (augsts līmenis)
  • Windows — natīvs darbvirsmas klients
iOSAndroidReact NativeFlutterWindows
Pa platformai

Ko es patiešām rakstu katrā platformā.

Platformas nav savstarpēji aizstājamas, un rīki to atspoguļo. Katra cilne ir platforma, kurā esmu piegādājis — valodas, frameworki un spriedums par to, kad katrs nopelna savu vietu.

Natīvais iOS Swift valodā, ar Objective-C tur, kur tas vēl dzīvo

iOS es rakstu Swift un lasu Objective-C, jo reālas koda bāzes, kas piegādātas gadiem, reti ir tīrs Swift. Es būvēju saskarnes SwiftUI jaunajiem ekrāniem un saglabāju UIKit tur, kur no tā atkarīga esoša plūsma, nevis pārrakstu strādājošu kodu kāda framework dēļ.

Noturība ir Core Data, kad lietotnei pieder reāls objektu grafs, un kustība ir Core Animation, kad pārejai jājūtas natīvai, nevis tuvinātai. SiriKit apstrādā balss nodomus tur, kur tie pelna savu vietu — ne katrā ekrānā, tikai tur, kur runātais saīsne patiešām ir ātrāka par pieskaršanos.

  • Swift vispirms, Objective-C lasīts un uzturēts
  • SwiftUI jauniem ekrāniem, UIKit saglabāts tur, kur tas darbojas
  • Core Data objektu grafam, Core Animation kustībai
  • SiriKit nodomi tur, kur balss patiešām ir ātrāka
iOS, dziļumā

Swift tā, kā tas lasās uz reāla ekrāna.

Koda panelis ir godīgāks par funkciju sarakstu — tā ir iOS darba forma, nevis tā apraksts.

iOS es paļaujos uz SwiftUI jaunajām virsmām un Core Data objektu grafam aiz tām. Zemāk esošais fragments ir tāda veida, ko rakstu katru dienu: mazs, tipizēts modelis, fetch, ko skats var novērot, un izkārtojums, kas paliek deklaratīvs. Tas ir apzināti parasts — natīvās tekošās prasmes jēga ir tāda, ka rutīnas kods ir tīrs, nevis viltīgs.

ContactList.swiftSwift · SwiftUI · Core Data
import SwiftUI
import CoreData

struct ContactList: View {
    @FetchRequest(
        sortDescriptors: [SortDescriptor(\.name)]
    ) private var contacts: FetchedResults<Contact>

    var body: some View {
        List(contacts) { contact in
            VStack(alignment: .leading) {
                Text(contact.name)
                    .font(.headline)
                Text(contact.phone)
                    .font(.subheadline)
                    .foregroundStyle(.secondary)
            }
        }
        .animation(.easeInOut, value: contacts.count)
    }
}
SwiftUI · UIKit Core Anim. SiriKit Core Data Swift · Objective-C

iOS frameworku kopa

SwiftUI virspusē, Core Data apakšā, SiriKit tur, kur balss ir ātrāka.

Frameworki saliekas kopā: SwiftUI renderē, Core Data noturē, Core Animation apstrādā kustību, ko SwiftUI neapstrādā, un SiriKit eksponē vienu vai divus nodomus, kur runātais saīsne patiešām pārspēj pieskaršanos. Objective-C paliek attēlā, jo ilgdzīvojošas lietotnes to vēl satur, un tā lasīšana ir daļa no to uzturēšanas.

Nekas no tā netiek pievienots pats par sevi. Katrs framework ir lietotnē, jo konkrēta problēma — noturība, kustība, balss — to pieprasīja.

  • SwiftUI jauniem ekrāniem, UIKit saglabāts tur, kur tas darbojas
  • Core Data objektu grafam
  • Core Animation natīvi jūtamai kustībai
  • SiriKit nodomi tikai tur, kur balss ir ātrāka
SwiftSwiftUICore DataSiriKit
Android, dziļumā

Kotlin pret Android SDK, ar visu fragmentāciju.

Android atalgo skaidrību. Zemāk esošais fragments ir Kotlin ViewModel, kas eksponē UI stāvokli kā flow — dzīves cikla apzinīgs, izdzīvo konfigurācijas izmaiņas un dara savu ielādi ārpus galvenā pavediena. Esot piegādājis daudzās OS versijās, es rakstu Android kodu, kas pieņem procesa nāvi un saspringtus fona ierobežojumus, nevis cer no tiem izvairīties.

ContactViewModel.ktKotlin · Android SDK
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch

class ContactViewModel(
    private val repo: ContactRepository
) : ViewModel() {
    private val _state =
        MutableStateFlow<UiState>(UiState.Loading)
    val state: StateFlow<UiState> = _state.asStateFlow()

    init {
        viewModelScope.launch {
            runCatching { repo.loadContacts() }
                .onSuccess { _state.value = UiState.Ready(it) }
                .onFailure { _state.value = UiState.Error }
        }
    }
}
ATBALSTĪTĀS OS VERSIJAS min virsotne jaunākā

Daudzas OS versijas, reālas ierīces

Atbalstīt tālruņus, ko lietotāji nēsā, nevis to no atklāšanas runas.

Android fragmentācija nav problēma, par ko sūdzēties — tā ir vide. Darbs ir izvēlēties godīgu minimālo SDK, testēt versiju un ekrānu izmēru klāstu, ko darbina reālā lietotāju bāze, un apstrādāt fona un atļauju noteikumus, kas saspringst ar katru laidienu.

Java paliek rīkkopā līdzās Kotlin tā paša iemesla dēļ, kāpēc Objective-C uz iOS: piegādātais kods dzīvo ilgi, un tā uzturēšana nozīmē to lasīt tekoši.

  • Kotlin un Java pret Android SDK
  • Godīgas minimālā SDK izvēles
  • Testēts versijās, ko lietotāji darbina
  • Skaidra fona un atļauju apstrāde
KotlinJavaAndroid SDKLifecycle
Lietotnes arhitektūra

Lietotnes forma, uzzīmēta no UI līdz datu krātuvei.

Mobilā lietotne ir skaidru slāņu kaudze — un disciplīna ir tos saglabāt skaidrus, lai katru varētu testēt un nomainīt atsevišķi.

Lai kāda būtu platforma, arhitektūra, pie kuras ķeros, garā ir tā pati: UI slānis, kas tikai renderē stāvokli, domēna slānis, kas tur loģiku, datu slānis, kas sarunājas ar tīklu un ierīces krātuvi, un sinhronizācijas robeža pa vidu. Diagramma parāda slāņus un vienīgo virzienu, uz kuru norāda atkarības.

Bultu turēšana, norādot vienā virzienā, ir tas, kas padara lietotni uzturamu gadu vēlāk — UI nesniedzas tīklā, un tīkls nezina par UI. Tā pati forma turas, vai klients ir Swift, Kotlin, React Native vai Flutter.

UI SLĀNIS SwiftUI · Compose · RN · Flutter DOMĒNA SLĀNIS loģika · noteikumi · stāvoklis DATU SLĀNIS repozitoriji · ORM SQLite ierīcē TĪKLS REST · GraphQL

UI → domēns → dati → krātuve

Četri slāņi, atkarības norādot vienā virzienā.

UI novēro stāvokli un izstaro nodomus; domēna slānis izlemj; datu slānis izgūst un noturē; SQLite tur patiesību ierīcē, un tīkls nes pārējo. Katra robeža ir vieta, kur varu ielikt testu vai nomainīt implementāciju, augšējiem slāņiem to nepamanot.

Tā nav arhitektūra pati par sevi. Tā ir struktūra, kas ļāva vienpadsmit gadu lietotnēm turpināt pieņemt funkcijas, nesabrūkot zem tām.

  • UI renderē stāvokli, nekad nesniedzas tīklā
  • Domēna slānis tur loģiku un noteikumus
  • Datu slānim pieder tīkls un ierīces noturība
  • SQLite kā patiesības avots ierīcē
ArhitektūraSlāņošanaTestējams
Backendi

Katras mobilās lietotnes servera puse.

Mobilais klients ir tik labs, cik backends, ar kuru tas runā — tāpēc es būvēju arī šo backendu, jebkurā framework, kas der komandai.

Aiz lietotnēm esmu piegādājis Node/Express, Spring Boot, Django, Flask, Ruby on Rails un Go ar Gin un Gorm. Framework tiek izvēlēts komandai un latentuma budžetam, nevis pēc ieraduma: Node tur, kur komanda tekoši pārvalda JavaScript, Spring tur, kur tā ir JVM māja, Django vai Flask Python smagiem backendiem, Rails konvenciju virzītam CRUD, un Go tur, kur budžets uz pieprasījumu ir saspringts.

Katrs eksponē līgumu — REST vai GraphQL —, pret kuru tiek būvēts mobilais klients, noturē caur ORM kā Sequelize un Mongoose, un kešo karsto ceļu Redis. Zemāk esošais process ir tas pats neatkarīgi no tā, kurš framework sēž pa vidu.

No līguma līdz sinhronizētai ierīcei

  1. 01 Definēt līgumu REST vai GraphQL shēma vispirms saskaņota — klients un serveris tiek būvēti pret vienu līgumu, nevis viens pret otru.
  2. 02 Izvēlēties framework Node/Express, Spring Boot, Django/Flask, Rails vai Go (Gin/Gorm) — izvēlēts, lai derētu komandai un latentuma budžetam.
  3. 03 Modelēt datus ORM — Sequelize vai Mongoose — virs relāciju vai dokumentu krātuves, kuru domēns patiešām vajag.
  4. 04 Kešot karsto ceļu Redis dārgo lasījumu priekšā, ar skaidru invalidāciju, nevis cerīgiem TTL.
  5. 05 Sinhronizēt ierīci SQLite ierīcē, sinhronizācijas protokols pār līgumu, konfliktu risināšana definēta pirms tā vajadzīga.
  6. 06 Piegādāt pīpeli Parakstīti būvējumi, automatizēti testi, piegāde veikaliem — CI, kas pārvērš commit būvējumā, ko lietotājs var instalēt.
handler.goGo · Gin · Gorm
func GetContact(c *gin.Context) {
    id := c.Param("id")
    if cached, err := rdb.Get(ctx, id).Result();
        err == nil {
        c.Data(200, "application/json",
            []byte(cached))
        return
    }
    var contact Contact
    if err := db.First(&contact, id).Error;
        err != nil {
        c.JSON(404, gin.H{"error": "not found"})
        return
    }
    c.JSON(200, contact)
}

Go apstrādātājs, tā, kā tas tiek piegādāts

REST un GraphQL, apkalpoti ātri un tipizēti.

Fragments ir Gin apstrādātājs, kas lasa caur Gorm ar Redis kešu priekšā — mazā, atkārtojamā galapunkta forma, uz kuru mobilais klients var paļauties: tipizēta atbilde, paredzama kļūda un kešs, kas noņem slodzi no datubāzes karstajā ceļā.

Vai framework ir Go, Node vai Spring, līgums, ko redz tālrunis, ir tas pats. Tā ir jēga to vispirms saskaņot.

  • Go ar Gin un Gorm uz saspringta budžeta ceļiem
  • Redis, kas kešo dārgos lasījumus
  • Tipizētas atbildes, paredzamas kļūdu formas
  • Tas pats līgums neatkarīgi no framework
GoGinGormRedisREST

Pilns mobilais steks — no klienta līdz mākonim

iOS valodas
Swift · Objective-C
iOS frameworki
SwiftUI · UIKit · Core Data · Core Animation · SiriKit
Android valodas
Kotlin · Java
Android mērķis
Android SDK, daudzas OS versijas
Vairāku platformu
React Native · Flutter (augsts līmenis) · Xamarin (darba līmenis)
Darbvirsma
Windows klienti
Backend risinājumi
Node/Express · Spring Boot · Django/Flask · Rails · Go (Gin/Gorm)
API
REST · GraphQL
Ierīcē / dati
SQLite · Redis · Sequelize · Mongoose
Mobilais mākonis
Firebase · AWS · Google Cloud
Frontend amats
HTML5 · CSS3 · SASS/SCSS · JS ES6+ · TypeScript
Bezsaiste vispirms

Kad tīkls atteic — un uz tālruņa tas atteiks.

Tālrunis pārvietojas pa tuneļiem, liftiem un mirušajām zonām. Lietotne, kas pieņem savienojamību, ir lietotne, kas iestrēgst pie griezēja reāla lietotāja priekšā.

Es būvēju mobilās lietotnes bezsaiste vispirms: ierīce nekavējoties raksta SQLite un ievieto izmaiņu rindā uz sinhronizāciju, lai lietotājs nekad negaida tīklu, lai redzētu savu paša darbību stājamies spēkā. Kad savienojamība atgriežas, rinda izsmeļas pār REST vai GraphQL līgumu, un konflikti tiek atrisināti pēc politikas, kas izlemta katrai entītijai, pirms tā vispār vajadzīga.

Diagramma izseko šo ciklu — lokāla rakstīšana, rinda, sinhronizācija, saskaņošana — un kļūmes režīms ir daļa, kas svarīga: lietotne degradējas uz tikai lasīšanu, nevis klusi pazaudē rakstījumu. Tā ir atšķirība starp lietotni, kurai lietotāji uzticas, un to, ko viņi pamet.

IERĪCE SQLite rakstījums RINDA gaida SERVERIS saskaņot KRĀTUVE Redis · ORM bezsaistē sinhronizācija (REST/GraphQL) atrisināts stāvoklis atpakaļ

Lokāla rakstīšana → rinda → sinhronizācija → saskaņošana

Ierīce ir patiesības avots, līdz serveris piekrīt.

Katrs rakstījums vispirms nokļūst SQLite un tiek atspoguļots sinhronizācijas rindā. Fona sinhronizācija izsmeļ rindu pret serveri, serveris saskaņo, izmantojot Redis balstītus lasījumus un ORM kartēto krātuvi, un atrisinātais stāvoklis plūst atpakaļ uz ierīci. Lietotājs redz tūlītēju lokālu atgriezenisko saiti un galīgu konsekvenci, nevis griezēju.

Konfliktu politikas projektēšana iepriekš — last-write-wins, sapludināšana vai manuāla — ir tas, kas notur ciklu godīgu, kad divas ierīces rediģē to pašu ierakstu.

  • Lokāla rakstīšana SQLite pirms jebkura tīkla izsaukuma
  • Izmaiņa ievietota rindā, izsmelta, kad savienojamība atgriežas
  • Konfliktu politika definēta katrai entītijai iepriekš
  • Degradēties uz tikai lasīšanu, nekad nepazaudēt rakstījumu
Bezsaiste vispirmsSQLiteSinhronizācijaKonfliktu risināšana

Bezsaiste vispirms — līgums ar tīklu

Krātuve ierīcē
SQLite — patiesības avots, kamēr bezsaistē
Rakstīšanas ceļš
Lokāla rakstīšana vispirms, rindā uz sinhronizāciju
Sinhronizācijas transports
REST vai GraphQL pār saskaņoto līgumu
Konfliktu politika
Definēta katrai entītijai pirms tā vajadzīga
Servera kešs
Redis dārgo lasījumu priekšā
Servera krātuve
Relāciju vai dokumentu, caur Sequelize vai Mongoose
Kļūmes režīms
Degradēties uz tikai lasīšanu, nekad klusi nepazaudēt rakstījumu

Lietotājam nekad nevajadzētu gaidīt tīklu, lai redzētu savu paša darbību. Rakstīt lokāli, sinhronizēt fonā un nekad nepazaudēt rakstījumu — tā ir visa bezsaiste-vispirms disciplīna.

Mobilais mākonis

Firebase, AWS un Google Cloud — izvēlēti pēc atbilstības.

Mākonis nav viens lēmums. Mazai komandai vajadzīgs backends uz vakar; produktam, kas mērogojas, vajadzīga kontrole pār savu skaitļošanu. Katra cilne ir platforma, kurā izvietoju mobilos backendus, un spriedums par to, kad katra ir pareizā atbilde.

Firebase, kad mazai komandai vajadzīgs backend uz vakar

Firebase pelna savu vietu, kad mobilam produktam vajadzīga autentifikācija, sinhronizēta datu krātuve un push, vispirms neuzceļot infrastruktūru. Es izmantoju Auth pieteikšanās, Firestore strukturētiem, vaicājamiem datiem, un Realtime Database tur, kur piekļuves raksts patiešām ir dzīvs koks, nevis dokumenti.

Disciplīna ir zināt, kur Firebase pārstāj būt pareizā atbilde — drošības noteikumi, kuriem jākodē reāla autorizācija, un lasīšanas izmaksas, kas aug ar naivu datu modeli. Es projektēju dokumentus ap vaicājumiem, nevis otrādi.

  • Auth pieteikšanās, Firestore strukturētiem datiem
  • Realtime Database tur, kur dzīvs koks der piekļuves rakstam
  • Drošības noteikumi uzskatīti par reālu autorizāciju
  • Dokumenti projektēti ap vaicājumiem
MOBILĀ FIREBASE Auth · Firestore AWS Lambda · EC2 · S3 GCP App Eng · Compute viens klients, backends, kas der slodzei

Kur backends patiešām darbojas

Pārvaldīts tur, kur tas ietaupa darbu, kontrolēts tur, kur tam jābūt.

Firebase Auth un Firestore uzceļ sinhronizētu backendu bez infrastruktūras; Lambda un EC2 dod serverless un ilgdzīvojošu skaitļošanu uz AWS; App Engine un Compute Engine dara to pašu uz Google Cloud; S3 tur medijus, ko tālrunis lejupielādē. Diagramma kartē klientu uz šīm opcijām.

Mobilais ierobežojums iet cauri tam visam: aukstos startus jūt uz tālruņa, un augšupielādēm jāizdzīvo mobilo sakaru savienojums. Mākonis tiek izvēlēts tā, lai latentums, ko redz lietotājs, paliek budžetā.

  • Firebase — Auth, Firestore, Realtime Database
  • AWS — Lambda, EC2, S3
  • Google Cloud — App Engine, Compute Engine
  • Izvēlēts pēc operatīvās atbilstības, latentums budžetā
FirebaseAWSGoogle CloudServerless
Vairāku platformu, dziļumā

React Native un Flutter — izvēle, nevis noklusējums.

Vairāku platformu steki ļauj vienai komandai piegādāt abus veikalus no vienas koda bāzes, un es ekspluatēju React Native un Flutter augstā līmenī. Bet iemesls, kāpēc es tiem uzticos, ir tas, ka esmu piegādājis natīvi vispirms: es precīzi zinu, ko tiltiņš man ietaupa un kur tas traucē. Kad ekrānam vajadzīgs Core Animation, sensors, ko tiltiņš tīri neeksponē, vai platformas uzvedība, ko abstrakcija aizsedz, es nokāpju līdz natīvajam modulim bez vilcināšanās.

Xamarin atrodas darba līmenī rīkkopā, kas ir pareizā atbilde .NET orientētās organizācijās, kur pārējais steks jau ir C#. Lēmums starp tiem nekad nav par uzticību — tas ir par steka pielāgošanu komandai un produktam, ar natīvo vienmēr pieejamu zemāk.

KOPLIETOTA KODA BĀZE React Native · Flutter iOS RENDERS ANDROID RENDERS Swift modulis Kotlin modulis

Viena koda bāze, divi veikali, natīvā glābšanas lūka

Koplietota biznesa loģika virspusē, natīvie moduļi tur, kur tiltiņš apstājas.

Vairāku platformu lietotnē biznesa loģika un lielākā daļa UI dzīvo vienā koplietotā koda bāzē — React Native vai Flutter —, kas renderē gan iOS, gan Android. Daļas, ko abstrakcija nevar apkalpot, izkrīt līdz natīvajiem moduļiem Swift un Kotlin, lai lietotne nekad netirgo spēju pret pārnesamību.

Šī glābšanas lūka ir viss iemesls, kāpēc natīvā tekošā prasme ir svarīga pat vairāku platformu projektā. Koplietotais slānis aptver kopīgo zemi; natīvie moduļi aptver malas.

  • Koplietota loģika un UI vienā koda bāzē
  • Renderē gan iOS, gan Android
  • Natīvie moduļi Swift / Kotlin malās
  • Spēja nekad netiek tirgota pret pārnesamību
React NativeFlutterNatīvie moduļi
CI mobilajam

Pīpelis, kas pārvērš commit instalācijā.

Mobilais CI ir grūtāks par tīmekļa CI — ir divas rīkkopas, koda parakstīšana un divi veikala izskates procesi starp commit un lietotāju.

Mobilais laidiens nav izvietošana; tā ir būve, paraksts un iesniegšana. Pīpelis, ko darbinu, vispirms lint un tipu pārbauda, tad būvē iOS archive ar Xcode un to paraksta, būvē parakstīto Android APK vai AAB ar Gradle un nosūta versionētus artefaktus uz TestFlight un iekšējo kanālu pirms veikala. Noteikums ir vienkāršs: nav zaļš pīpelis, nav laidiena.

Zemāk esošā diagramma parāda šo izvēršanos — viens commit, divas rīkkopas, divi veikali — jo cena par kļūdu koda parakstīšanā vai versijas paaugstināšanā ir noraidīta iesniegšana un zaudēta diena, nevis ātra atkārtota izvietošana.

COMMIT laidiens PĀRBAUDES lint · tips · tests XCODE parakstīt · archive GRADLE parakstīts AAB App Store Play Store

Commit → pārbaudes → divas būves → divi veikali

Viens commit izvēršas divās parakstītās būvēs.

Pīpelis palaiž statiskās pārbaudes vienreiz, tad sadalās: Xcode ceļš, kas būvē, paraksta un arhivē iOS, un Gradle ceļš, kas saliek un paraksta Android. Katrs ražo versionētu artefaktu, kas iet uz sava veikala testa kanālu pirms laidiena.

Parakstītās būves uzskatīšana par vienīgo, kas tiek piegādāts — nekad lokāls archive no kāda mašīnas — ir tas, kas notur laidienus reproducējamus visā vienpadsmit gadu lietotņu garumā.

  • Lint, tipu pārbaude un vienības testi kā vārti
  • Xcode paraksta un arhivē iOS
  • Gradle saliek parakstītu APK/AAB Android
  • Versionēti artefakti uz testa kanāliem, tad veikals
CIKoda parakstīšanaTestFlightGradle

Mobilais CI — stadija pa stadijai

Trigeris
Commit laidiena zarā
Statiskās pārbaudes
Lint, tipu pārbaude (TypeScript), vienības testi
iOS būve
Xcode būve, koda parakstīšana, archive
Android būve
Gradle assemble, parakstīts APK/AAB
Artefakts
Versionēts būvējums katrai platformai
Piegāde
TestFlight / iekšējais kanāls, tad veikals
Vārti
Nav zaļš pīpelis, nav laidiena
Frontend amats

Tīmekļa virsmas, kas sēž līdzās lietotnei.

Mobilais produkts reti ir tikai lietotne. Ir uzņemšanas lapas, mārketinga virsmas, iegultie tīmekļa skati un koplietota loģika, kas visa grib to pašu rūpību kā natīvais kods. Es tos būvēju tīrā HTML5 un CSS3, organizēju stilus ar SASS/SCSS, lai dizaina sistēma paliktu sistēma, un rakstu loģiku mūsdienu JavaScript — ES6+ un TypeScript visur, kur projekts pieļauj tipu sistēmu.

TypeScript jo īpaši atmaksājas mobilajā: tipizēts līgums noķer neatbilstību starp klientu un serveri, pirms lietotājs to vispār redz, un tie paši tipi var plūst no GraphQL shēmas līdz React Native klientam.

01

HTML5 un CSS3

Tīmekļa virsmas, kas sēž līdzās mobilajai lietotnei — uzņemšanas lapas, mārketings, iegultie tīmekļa skati — būvētas tīrā HTML5 un CSS3, nevis refleksīvi iemestas framework.

02

SASS/SCSS

Stila lapas, organizētas ar SASS/SCSS, lai dizaina sistēma paliktu sistēma: mainīgie, partials un mixins, nevis kopētas deklarācijas.

03

JavaScript ES6+

Mūsdienu JavaScript koplietotajai loģikai un tīmekļa slānim — moduļi, async/await un valodas iespējas, kas padara koda bāzi lasāmu gadus vēlāk.

04

TypeScript

TypeScript visur, kur projekts to pieļauj, jo tipizēts līgums noķer neatbilstību starp klientu un serveri, pirms lietotājs to vispār redz.

05

REST API

REST vienkāršajiem, resursveida galapunktiem, ar versionēšanu un paredzamām kļūdu formām, uz kurām mobilais klients var paļauties.

06

GraphQL API

GraphQL tur, kur mobilam ekrānam vajadzīgi tieši tā dati vienā turp-atpakaļ braucienā — tīkla brauciens, ko tālrunis maksā, ir tas, ko vērts ietaupīt.

Loks

Vienpadsmit gadi, viens platformas lēmums vienlaikus.

Pamats, natīvais, vairāku platformu, backend, mākonis — tas pats inženieris, sekojot darbam, kamēr produkti pieauga aiz to pirmajiem tūkstoš lietotājiem.

Lasīts secībā, mobilais darbs ir viena nepārtraukta trase, nevis frameworku saraksts. Tas sākas ar vienpadsmit gadiem piegādes reāliem lietotājiem, padziļinās natīvajā iOS un Android, paplašinās caur React Native un Flutter tur, kur tie der, sniedzas atpakaļ backendos, kas padara klientu par vairāk nekā apvalku, un nonāk pie mākoņiem, kas to mērogo.

Tas, kas iet cauri visam, ir tas pats atteikums, kas caurvij pārējo manu darbu: lietotne un sistēma aiz tās ir viena problēma, nevis divas, sadalītas starp diviem cilvēkiem.

  1. Pamats Vienpadsmit gadi piegādes reāliem lietotājiem Trase, kas noenkuro visu pārējo: vairāk nekā vienpadsmit gadi, būvējot un piegādājot mobilās lietotnes, ko reāli cilvēki instalēja un lietoja, iOS, Android un Windows platformās.
  2. Natīvais iOS un Android to pašu valodās Swift un Objective-C uz iOS ar SwiftUI, Core Data, Core Animation un SiriKit; Kotlin un Java uz Android daudzās OS versijās. Natīvā tekošā prasme, kas padara vairāku platformu izvēles informētas.
  3. Vairāku platformu React Native un Flutter augstā līmenī Viena komanda, kas piegādā divus veikalus, kur tas der, nokāpjot līdz natīvajiem moduļiem, kur ne — plus Xamarin darba līmenī .NET orientētām komandām.
  4. Backend Katras lietotnes servera puse Node/Express, Spring Boot, Django/Flask, Rails un Go (Gin/Gorm), eksponējot REST un GraphQL, balstīti uz SQLite, Redis un ORM — backendi, kas padara mobilo klientu par vairāk nekā plānu apvalku.
  5. Mākonis Firebase, AWS un Google Cloud Pārvaldītas datu krātuves, serverless skaitļošana un glabātuve, izvēlētas pēc operatīvās atbilstības — infrastruktūra, kas mērogo lietotni aiz tās pirmajiem tūkstoš lietotājiem.
Kā es strādāju

Principi zem platformām.

Platformas un frameworki mainās ar produktu; principi ne. Šie ir noteikumi, ko piemēroju, vai lietotne ir natīvs Swift, natīvs Kotlin, React Native vai Flutter — daļa, kas vienpadsmit gadu mobilo darbu pārvērta lietotnēs, kas turpināja darboties, nevis palaišanu portfelī.

01

Natīvā tekošā prasme nopelna abstrakciju

Tā kā esmu piegādājis Swift un Kotlin tieši, React Native vai Flutter izvēle ir mērīts kompromiss, nevis veids, kā izvairīties no platformas apgūšanas. Es zinu, ko tiltiņš man ietaupa un ko tas slēpj.

02

Līgums nāk pirmais

Klients un serveris tiek būvēti pret vienu saskaņotu REST vai GraphQL līgumu, ideālā gadījumā tipizētu no sākuma līdz beigām. Integrācija tiek projektēta, pirms kāda no pusēm uzrakstīta, nevis apspriesta pēc tam, kad abas salūst.

03

Pieņem, ka tīkls atteiks

Tālrunis pārvietojas pa mirušajām zonām. Lietotne vispirms raksta lokāli SQLite, ievieto rindā uz sinhronizāciju un degradējas uz tikai lasīšanu, nevis pazaudē rakstījumu vai iestrēgst pie griezēja.

04

Respektē platformas noteikumus

Fona ierobežojumi, procesa nāve, veikala izskate, koda parakstīšana — tie nav šķēršļi, ko apiet. Strādāt ar tiem ir tas, kas notur lietotni instalētu, nevis atinstalētu.

05

Testē fragmentāciju

Daudzas Android OS versijas un iOS ierīču klāsts nozīmē testēt to, ko lietotāji patiešām nēsā, nevis apgalvot, ka jaunākais laidiens aptver visus.

06

Vienpadsmit gadi ir apliecinājums

Katrs apgalvojums šeit ir balstīts uz lietotnēm, kas tika piegādātas un palika piegādātas. Ilgmūžība ir pierādījums — nevis framework uz slaida, bet programmatūra, kas izdzīvoja saskari ar reāliem lietotājiem.

Vienpadsmit gadi lietotņu, kas tika piegādātas un palika piegādātas, ir apliecinājums. Viss pārējais šajā lapā ir patiess tāpēc, ka šī viena lieta ir.

Open to the right work

Ja jūsu produkts ir mobilā lietotne un backends, mākonis un bezsaistes uzvedība, kas to padara uzticamu, tā ir visa problēma, ko es vēlos.

If you are holding a problem that doesn't fit inside one field, that is the conversation I want.

NextCloud & DevOps