Când user-friendly e prea user-friendly

Post-ul de față este între altele un exercițiu de diplomație, pentru că am alergat după problema asta vreo oră şi ceva. Nu sunt enervat, doar respir ceva mai repede :-) .

Treaba e cam aşa: am zis să iau taurul de coarne şi să învăț să lucrez cu CocoaTouch, adică SDK-ul folosit la dezvoltarea aplicațiilor pentru iPhone şi iPod Touch. Seamănă leit cu Cocoa, doar că e adaptat unei platforme ceva mai limitate. Taurul are nişte coarne destul de insipide pentru mine din punct de vedere “istoric”: am lucrat cu OpenStep înainte ca Apple să schimbe instrumentele de dezvoltare, şi nici atunci prea mult. Ceea ce a ajuns Cocoa acum seamănă cu ce țineam eu minte, dar numai cât să mă înşele, fiindcă de fapt s-au schimbat cam toate detaliile. Dacă NeXT pusese la dispoziție un Developer’s Guide absolut excelent, Apple are o documentație pe care, după ce o lecturezi o zi întreagă, vii acasă şi-ți bați nevasta, copiii şi mai ales soacra, pentru că e foarte multă, foarte detaliată, foarte prost organizată şi foarte prost indexată.. Ceea ce înseamnă că poți găsi orice dacă ai timp să cauți. De asemenea, până nu demult, nu exista cam nicio carte decentă. Rezultatul e că eu învăț să folosesc CocoaTouch cu toate că n-am reuşit niciodată să folosesc Cocoa cum trebuie şi am uitat cam tot ce ştiam despre Openstep. Pentru mine, standardul în domeniu este Qt, care mi se pare un framework excelent în ciuda faptului că stă călare pe C++.

Unul dintre instrumentele cu care NeXT a rupt gura târgului atunci când a lansat NeXTStep este ceea ce astăzi a ajuns la Apple ca Interface Builder (Cocoa este de fapt fostul NeXTStep — în caz că se întreabă cineva ce-i cu NS-ul din fața tuturor claselor). Interface Builder-ul ăsta este, după cum îi spune şi numele, un program cu care poți desena interfețele — numai că face ceva mai mult de-atât, după cum o să explic imediat.

În cazul Qt, “traseul” uzual pentru realizarea interfeței este (sau ultima oară când am lucrat cu Qt, acum câteva luni, era), în mare, cam aşa: se porneşte prin a plasa butoanele, meniurile şi toate celelalte în Qt Designer. Qt Designer generează apoi (automat) o clasă care reprezintă interfața, clasa respectivă fiind însă “chioară” (constructorul ei nu inițializează conexiunile evenimentelor din interfață cu acțiunile din cod — fiindcă n-are de unde să ştie care-s alea). Pentru a realiza conexiunile respective, maimuța din fața tastaturii trebuie să scrie o clasă care o moşteneşte pe cea generată, în care să realizeze conexiunile necesare, să “numească” delegații ş.a.m.d.. Conexiunile se pot realiza şi automat, via nişte constrângeri legate de denumire a funcțiilor, dar când am folosit Qt prima dată (asta fiind, ce-i drept, acum vreo cinci ani) trebuiau făcute manual.

Prin comparație, treaba în cazul Xcode şi IB e mult mai simplă: obiectele din interfață care trebuie accesate prin cod sunt declarate punându-li-se IBOutlet în față, iar acțiunile la care evenimentele din interfață sunt conectate se declară punându-li-se IBAction în față; scrii clasa obiectului care joacă rol de controller (outlet-urile fiind între variabilele instanțelor respective, acțiunile aparținând controller-ului ca metode, strunjite evident în bunul spirit al MVC), după care IB “se prinde” automagic şi faci conexiunile respective prin cel mai tineresc drag’n'drop posibil.

Avantajul e că toată treaba durează puțin şi că metoda e fantastic de flexibilă. Practic, numai pe seama sus-pusei integrări, se sare peste o grămadă de etape (ceea ce am schițat mai sus e numai în linii mari şi am sărit peste câteva amănunte).

Dezavantajul vine pe urmă, dacă ai făcut vreo trăznaie. În cazul meu, trăznaia în cauză a fost aceea de a greşi clasa unui view controller. Mai exact, conectasem un view la un controller care nu era al lui (era vorba de acelaşi tip de view — un picker — doar că unul avea două “roți” şi celălalt — una singură). Inutil de spus că nu mergea. Mesajul de eroare?

*** Terminating app due to uncaught exception ‘NSUnknownKeyException’, reason: ‘[<DatePickerViewController 0x525a60> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key doublePicker.’

Din păcate, tot ce am înțeles din mesajul ăsta era că încercam să accesez valorile afisate de un DatePicker folosind cheia “doublePicker”, ceea ce mi se părea extrem de improbabil pentru că nu obişnuiesc să scriu programe când sunt beat mangă. Ok, să zicem că o exegeză mai atentă a textului m-ar fi convins că e vorba de altceva, dar tot nu e destul.

Problema cu care mă confrunt în momentul ăsta e că nu “văd” tot codul din spatele aplicației. E foarte tare faptul că o bună parte din cod e generată de IB şi de Xcode, dar eu nu sunt învățat să depanez altceva decât cod din ăla bătrânesc, cu text. Sursa problemei am găsit-o până la urmă, dar cu foarte mare greutate fiindcă era într-o fereastră din InterfaceBuilder.

Bineînțeles, vina e în principiu a mea, cu atât mai mult cu cât trecerea de la C şi ASM e foarte zgrunțuroasă pentru mine. Însă e interesant cum o parte din zgrunțul trecerii ăsteia vine din faptul că instrumentele cu care am de-a face au o paradigmă atât de diferită. Dacă aş fi făcut o greşeală de genul ăsta lucrând cu Qt, reflexul meu imediat ar fi fost să mă uit pe codul generat de Qt Designer şi moc, şi probabil că mi-ar fi luat cinci minute să mă prind de unde vine. Nu pentru că Qt e mai tare şi nici pentru că Apple sunt nişte capitalişti infecți, ci pentru că mintea mea e mai învățată cu liniile de cod decât cu imaginile. Pentru mine, nivelul ăsta de user-friendly e prea… user-friendly, şi trebuie să mă învăț :-) .

1 comentariu

  1. Aram Hăvărneanu a zis,

    aprilie 25, 2009 la 2:32 pm

    Într-adevăr :D .

    Toți developerii Mac pe care îi știu, citează “simplitatea” și “naturalețea” Cocoa când o compară cu altceva.

    Wtf? Probabil oamenii ăștia au creierul montat invers. Mie Cocoa mi se pare de departe cel mai complicat framework pe care l-am folosit vreodată. Mi se pare mult mai simplu să scrii cod kernelspace eficient pentru sistemul de operare preferat. De departe.

    Trebuie să ai o intuiție specială pentru a deveni productiv în Cocoa. Pur și simplu trebuie să știi cumva ce trebuie să faci.

    Cocoa e plin de noțiuni fantastic de abstracte pentru mine, cum sunt run loops. Mie îmi plac pointerii. Nu pot să folosesc run loops fără să știu cum funcținează în prealabil. Programatorii Mac însă se mulțumesc să asambleze bucățile fără să știe în realitate ce se întâmplă de fapt și că procesorul ăla functionează cu regiștrii, stive și adrese de memorie, și nu cu obiecte, containere și alte nebunii care nu există cu adevărat.

    Momentan îmi desenez interfețele în Interface Builder, scriu un wrapper foarte thin Objective-C pentru controller peste adevăratul controller scris în C++. Modelele sunt de asemenea scrise în C++. Da, e complicat C++, e foarte neomogen și plin de greșeĺi ce trebuie păstrate pentru compatibilitate. E simplu Objective-C. E imposibil să scrii cod eficient, simplu de înțeles, scalabil și mentenabil în C++ dacă nu ești guru C++. Asta e, știu prea bine C++, e a 2a limbă. Îmi iese mai bine în C++.


Posteaza un comentariu