Steven
Steven5 min. skaitymo

Viena kodo bazė, dvi programos: kaip kurti baltos etiketės produktą be šakojimo

GeekBye ir Pavleur yra dvi skirtingai prekės ženklu paženklintos darbalaukio programos, sukurtos iš vienos saugyklos — jokio šakojimo, jokios dubliuotos kodo bazės. Štai kompiliavimo metu veikianti mašinerija, kuri iš vienos kodo bazės sukuria du produktus, ir viena vienos eilutės klaida, dėl kurios mūsų antroji programa prisistatė netinkamu vardu.

Inžinerija
Architektūra
Build
GeekBye leidimai
Viena kodo bazė, dvi programos: kaip kurti baltos etiketės produktą be šakojimo

GeekBye yra susitikimų užrašų priemonė. Pavleur yra DI pokalbių praktikos programa. Jos atrodo kaip du skirtingi produktai, nes yra du skirtingi produktai — bet jos sukurtos iš vienos kodo bazės, be jokio šakojimo ir be nutolstančios šakos. Tai inžinerinė baltos etiketės pusė: ne „kodėl parduoti prekės ženklu paženklintą programą" (tai kito įrašo tema), o kaip iš tikrųjų sukompiliuoti vieną saugyklą į dvi programas — ir tas neefektingas klaidos atvejis, kuris slepiasi kiekvienoje baltos etiketės sistemoje, kol nepradedi jo ieškoti.

Generuok, o ne šakok

Neteisingas būdas paleisti du produktus iš vienos kodo bazės yra apiberti programą if (product === 'pavleur') patikrinimais arba šakoti ir melstis, kad dvi kopijos niekada nenutols viena nuo kitos. Abu greitai supūva.

GeekBye požiūris yra kodo generavimas kompiliavimo metu. Kiekvienas produktas turi konfigūracijos failą — configs/geekbye/config.ts, configs/pavleur/config.ts — laikantį jo tapatybę: pavadinimą, bundle id, URL protokolą, automatinių atnaujinimų leidimų saugyklą ir taip toliau. Prieš build vykdomas vienas scenarijus:

node scripts/build-product.js pavleur

Tas scenarijus nuskaito pasirinkto produkto konfigūraciją ir atlieka tris konkrečius dalykus:

  1. Sugeneruoja du config modulius — vieną renderer procesui (src/config/product.ts), vieną pagrindiniam procesui (electron/config/product.ts) — kiekvienas pažymėtas antrašte „DO NOT EDIT MANUALLY — changes will be overwritten". Likusi programos dalis tiesiog importuoja productName, applicationId ir protocol iš config ir niekada negalvoja, kuris prekės ženklas ji yra.
  2. Nukopijuoja tik to prekės ženklo išteklius — piktogramas, mažąjį logotipą, iškylančiojo pranešimo piktogramą. GeekBye build fiziškai neturi nė vieno Pavleur grafinio elemento ir atvirkščiai. Nėra kam nutekėti.
  3. Perrašo package.json (leidimų build atveju) — programos id, produkto pavadinimą, URL protokolą, GitHub leidimų saugyklą, į kurią publikuoti, ir, kas malonu, prekės ženklo mikrofono leidimo tekstą, kad macOS klaustų „Pavleur nori naudoti mikrofoną", o ne netinkamą prekės ženklą.

Visa programa yra prekės ženklui neutrali; prekės ženklas įterpiamas kompiliavimo metu. Nėra vykdymo metu veikiančio produkto perjungiklio, kurį būtų galima suklaidinti, nes vykdymo metu visada įkeptas tik vienas produktas.

Vienas backend, du prekės ženklai

Abi programos kalbasi su tuo pačiu backend. Tad kaip serveris žino, kuriam produktui — ir kuriai kainodarai, užklausų šablonams bei apribojimams — priklauso užklausa?

Du signalai, abu nustatomi kompiliavimo metu. Pirma, application id (geekbye arba pavleur), įkeptas į konfigūraciją ir siunčiamas su užklausomis, kad backend galėtų nukreipti į tinkamo produkto elgseną. Antra, User-Agent, kurį klientas prideda prie kiekvieno kreipimosi į backend, formos Product/version (platform) — pvz., Pavleur/1.2.5 (win32) arba GeekBye/1.7.3 (darwin). Ta viena antraštė nemokamai suteikia backend priskyrimą pagal produktą ir pagal OS, be atskiro analitikos lauko. Tuo tarpu automatiniai atnaujinimai lieka izoliuoti: kiekvienas produktas publikuoja į savo paties leidimų saugyklą, todėl GeekBye atnaujinimas niekada negali būti pateiktas Pavleur įdiegimui.

Įvadinis procesas taip pat skiriasi kiekvienam produktui — GeekBye vedlys yra apie susitikimų transkribavimą, Pavleur — apie pokalbių praktiką — ir tinkamasis pasirenkamas vykdymo metu iš vienintelio įkepto application id. Ta pati mašinerija, dvejos priekinės durys.

Klaida: kai Pavleur pasivadino GeekBye

Štai karo istorija, ir tai ta pati, kurios versiją turi kiekviena baltos etiketės sistema.

Konfigūracijos generavimas veikė. Piktogramos pasikeitė. Mikrofono raginimas buvo su prekės ženklu. Protokolai ir bundle id buvo teisingi. Pagal kiekvieną matomą matą Pavleur build buvo Pavleur. Ir vis dėlto kurį laiką kiekvienas Pavleur build skambino namo į backend vadindamas save GeekBye.

Kaltininkė buvo viena įkoduota eilutė, ir ji slėpėsi mažiausiai efektingoje vietoje, kokią galima įsivaizduoti: User-Agent kūrėjyje, įkištame tinklo pakartojimo pagalbinėje priemonėje. Viskas, kas matoma vartotojui, buvo nukreipta per config, bet ši viena gilaus vamzdyno priemonė vis dar turėjo literalą `GeekBye/${version}` savyje. Niekas nelaiko pakartojimo priemonės „prekės ženklu", tad niekas jos nebuvo patikrinęs. Pataisa buvo keturios eilutės — importuoti dinaminį productName iš config ir interpoliuoti jį vietoj įkoduoto prekės ženklo — bet pamoka yra visa esmė:

Baltos etiketės kūrimas nėra „ar pasikeitė logotipas". Tai „ar kiekviena tapatybės eilutė nukreipiama per config". Ir paskutiniai likučiai niekada negyvena vartotojo sąsajoje, kur žiūrėtum. Jie gyvena User-Agent, giliosios nuorodos protokolo tvarkyklėje, leidimo raginimo tekste, klaidų pranešimuose — vamzdyne, kurio niekas nepriskiria „prekės ženklui". Vienintelė patikima gynyba yra traktuoti prekės ženklo literalą kaip kažką, ką aktyviai medžioji: grep kodo bazę ieškant įkoduoto pavadinimo ir nutraukti build, jei jis pasirodo bet kur už config, kuri turėtų jį apibrėžti, ribų.

Trys dalykai, kurių mus išmokė baltos etiketės kūrimas

  1. Generuok, o ne šakok. Dviejų mažyčių config modulių generavimas kompiliavimo metu plius atrankinis išteklių kopijavimas įveikia ir šakojimą, ir vykdymo metu esančią produkto patikrinimų tankmę. Programa lieka prekės ženklui neutrali; prekės ženklas yra build įvestis.
  2. Tapatybės eilutės nuteka į vamzdyną. Vartotojo sąsaja yra lengvieji 90 %. Sunkieji 10 % yra User-Agent, URL protokolas, mikrofono leidimo eilutė, klaidų tekstas. Nukreipk juos visus per vieną productName / applicationId eksportą — ir grep neapdorotą prekės ženklo pavadinimą kaip CI vartus, kad pasiklydęs literalas niekada negalėtų iškeliauti.
  3. Vienas backend, daug prekės ženklų, atskirk pagal id ir antraštę. Kompiliavimo metu nustatytas application id plius Product/version (platform) User-Agent suteikia priskyrimą pagal produktą ir pagal platformą be jokios dubliuotos infrastruktūros — švariai atskiriant nekintamą kompiliavimo metu nustatytą tapatybę nuo vykdymo metu esančios elgsenos.

Apie produkto ir privatumo pusę valdant baltos etiketės užrašų priemonę po savo prekės ženklu žr. baltos etiketės DI užrašų priemonė. Tai šeštasis v1 istorijos skyrius, virstantis GeekBye v2 — ankstesniam skyriui žr. kas iš tikrųjų yra 127 commitų leidimas (v1.7.0); o visai istorijos linijai — programinės įrangos tobulybės pristatymo anatomija.