Preskoči na sadržaj
Blog

Tri vrste grešaka koje prolaze typecheck, ESLint i build

Pregledali smo 74 komponente vlastitog dizajn sistema i našli 188 propusta. Sveli su se na tri uzroka, a svaki od njih je bio nevidljiv za svaki alat u lancu.

Dizajn sistemi9 min čitanja

Napravili smo cross-platform dizajn sistem — 74 komponente, tri targeta, 430 testova i oko 2.450 redova vlastite provjere. Onda smo sve to pregledali, čitanjem, i našli 188 propusta.

Broj nije ono zanimljivo. Zanimljivo je to što su se sveli na tri korijenska uzroka, i to što sva tri prolaze cijeli toolchain. TypeScript je zadovoljan. ESLint ćuti. Build prolazi. Svaka automatska kapija koju smo imali rekla je da je kod u redu.

Razumijevanje zašto je svaki nijem — to je ono što nalaz pregleda pretvara u pravilo koje hvata sljedeći.

Jedan: ime bez nosioca

accessibilityLabel na čvoru koji nema rolu ne izgovara nijedna platforma.

Na webu, aria-label na golom div ne radi ništa. Ovo nije hir preglednika — ARIA specifikacija kaže da generička rola ne prihvata ime koje daje autor. Atribut postoji, ispravno je napisan, i ignoriše se.

Na nativnom, accessibilityLabel bez accessible se nikad ni ne pročita. Labela postoji u stablu; ništa je ne gleda.

Devet komponenti u našem sistemu je imalo ovo. Labela je bila napisana, neko je mislio na pristupačnost, a čitač ekrana nije izgovorio ništa.

Zašto je svaki alat nijem: atribut je validan. To je pravo ime, pravi tip, na pravom mjestu. Ne postoji statičko pravilo koje kaže ovaj atribut nema smisla osim ako je prisutan i susjedni atribut, jer to u opštem slučaju nije tačno — tačno je samo za ovaj par, na ovoj vrsti čvora.

Zbog čega se dao naći: ispravan obrazac je već postojao u istom paketu. Icon svoju labelu uvijek uparuje sa role="img". Kad se jednom vidi slučaj koji radi, devet pokvarenih postaje pretraga umjesto pregleda.

U šta se pretvorilo: u pravilo provjere. Labela bez role sada obara build.

Dva: naslijeđeni prop koji nikad ne stigne do elementa

Ovaj nam je najdraži, jer je razlog njegove nijemosti tako precizan.

Komponenta prima Omit<BoxProps, 'as' | 'ref'>. To ostavlja id, a11yRole, accessibilityLabel i pointerEvents u javnom ugovoru — tipovi kažu da ih pozivalac smije proslijediti, i pozivalac to radi.

Ali grana koja ih eksplicitno ne destrukturira prosljeđuje ih dalje u ...box, u pomoćnik za stilove koji vraća samo propove sa prefiksom $. Propovi se potroše i odbace. Nikad ne stignu do elementa.

Zašto je svaki alat nijem: izostavljen prop je undefined, a undefined je validna vrijednost za opcioni prop. Nema greške tipa, jer ništa nije pogrešno tipizirano. Ugovor je obećao da će prop biti prihvaćen, a ne da će biti upotrijebljen.

Taj jaz — između prihvaćen i upotrijebljen — nije nešto što sistem tipova modelira. To je runtime svojstvo implementacije koje potpis ne može izraziti.

Koliko to postane loše: imali smo četiri susjedne komponente sa četiri različita podskupa spojena. Jedna je proslijedila sva četiri. Dvije su proslijedile po dva, i to ne ista dva. Jedna nijedan. Isti osnovni tip, ista namjera, četiri različita ponašanja — i svaka od njih je prošla typecheck.

Zbog čega se dao naći: poređenje susjeda. Bilo koja od njih, pročitana sama, izgleda ispravno. Pročitane jedna uz drugu, nedosljednost je očigledna za nekoliko sekundi.

Tri: komentar koji opisuje raniju verziju sistema

Bilješka imenuje ograničenje. Kasnije se ograničenje ukloni. Bilješka ostaje.

Ovo je najpodmukliji od tri, i to je onaj na koji bismo najjače upozorili, jer način otkaza nije pogrešno ponašanje — nego pogrešno uvjerenje. Programer pročita da nešto nije podržano, povjeruje u to, i zaobilazi ograničenje koje je prestalo postojati prije šest mjeseci. Kod koji napiše je ispravan i nepotreban. Niko nikad ne sazna.

Postoji i gora varijanta. JSDoc blok se tokom izmjene pomjerio za jedan prop, pa jedan prop nosi dva opisa, a njegov susjed nijedan. To je već loše u editoru. U našem slučaju je bilo gore, jer se dokumentacija generiše iz izvora u katalog — pa je pogrešan opis postao javna dokumentacija tog propa.

Zašto je svaki alat nijem: to je komentar. Nigdje u JavaScript toolchainu nema alata koji provjerava da li je proza istinita. Linteri provjeravaju da je JSDoc dobro oblikovan, a ne da je tačan.

Šta ovu vrstu čini teškom: druge dvije imaju oblik koji se može tražiti. Ova traži znanje o tome šta sistem trenutno radi i poređenje s onim što tekst tvrdi — a to je zadatak čitanja, ne zadatak provjere. Od tri, ova ostaje ljudski problem.

Šta je zajedničko za sva tri

Svaka automatska kapija postoji da odgovori na određeno pitanje. Typecheck pita da li vrijednosti pristaju. Lint pita da li sintaksa poštuje pravila. Build pita da li se kompajlira.

Nijedna ne pita: radi li ovaj atribut išta? Stiže li ovaj prop do elementa? Je li ova rečenica još uvijek tačna?

To su pitanja o značenju, a značenje je upravo ono što alati ne drže.

Šta smo zaista promijenili

Dva od tri su postala pravila provjere — labela bez role pada, a propovi deklarisani u ugovoru moraju se moći pratiti do elementa. Treći nije, jer nema šta da se provjeri.

Veća promjena je bila u samom pregledu. Naći 188 propusta i popraviti 188 propusta bilo bi rasipanje; naći tri uzroka i popraviti njih značilo je da je sljedećih stotinu spriječeno, a ne pronađeno.

I trebali smo to uraditi na 30 komponenti, a ne na 74. Sva tri uzroka su već bila prisutna na 30. Tada su bila jeftinija za popravku, a svaka komponenta napravljena poslije naslijedila bi ispravljeni obrazac umjesto pokvarenog.

To je prava pouka. Ne tri uzroka — vaši će biti drugačiji. Pouka je da je pregled koji stane na nalazima uradio pola posla, a preskočena polovina je ona koja se gomila.

Ovaj pregled je rađen nad našim vlastitim dizajn sistemom za više platformi, koji pokriva Next.js, React Native i Vite SPA. Pročitajte studiju →

Srodno
Cijeli blog →

Biblioteka komponenti kojoj niko ne vjeruje?

Pregledamo ono što vaši alati ne vide i nalaze pretvaramo u pravila koja build provodi. Odgovaramo u roku od jednog radnog dana.

Kontaktirajte nas

Sistemi koji ne smiju stati — od arhitekture do produkcije.

© 2026 Micro Tech, Sarajevo