printf(" SaltwaterC ");

Developer blog

  Archive for the ‘Programare’ Category


Firebug 1.5 + Firefox 3.5.7 + Ubuntu Hardy amd64

Firebug este o unealtă indispensabilă activităților de dezvoltare web pe care le execut. Din păcate, actualizările se lasă cu urmări câteodată. Precum zice în titlu, am încercat combinația nefericită de mai sus. Buba stă în Firebug: 64 bit Firefox on Linux crashes with Firebug 1.5.0. Am mers pe firul epic al poveștii de pe issue tracker și mi-am resetat preferințele. Crash-ul reapare atunci când se reactivează tab-ul Net sau Console. Din nefericire, echipa Firebug aruncă vina către Ubuntu, desi eu mi-am făcut propriul build personalizat de Firefox, deci problema cred că zace undeva prin ceva bibliotecă livrată cu Ubuntu din moment ce versiunea de Firefox îmi aparține.

Soluția de moment: downgrade la Firebug 1.4: http://getfirebug.com/releases/firebug/1.4/

PS: Firefox 3.6 sub Hardy amd64 este probabil cea mai instabilă versiune lansată vreodată. Am avut versiuni de Firefox Alpha sau Beta ce erau mai stabile de atât.

Dragă programatorule, dacă îți vine a copy-paste, fă refactor!

M-am săturat de cod prost scris ca de mere pădurețe. Nu mă refer la cod nefuncțional sau cu bug-uri. Mă refer la metodologia copy-paste la care se apelează intensiv din când în când. După care apucă-te și modifică ceva pentru a adăuga chestii noi. M-am săturat de gândire non-DRY datorită căreia apuc să modific în 5 locuri și 3 fișiere pentru a pune o chestie amărâtă care să arate la fel peste tot. În concluzie, pe lângă defularea de mai sus, m-am hotărât să mai dau niște idei.

Pe alocuri plângerile mele au avut succes. Acum două zile colegii de echipă mă ascultau în timp ce modificam niște chestii, iar involuntar am zis: iar de aici copiez dincolo … touche: “Ce-ai zis mă? Să copiezi?”. Exact ce ziceam mai sus … câteodată și mie îmi vine greu să nu scriu cod prost. Dar eforturile susținute = evoluție. În concluzie am luat linia aceea lungă (un apel înlănțuit de proceduri) și am pus-o într-o nouă metodă.

În concluzie vreo câteva idei, departe de a oferi o imagine completă:

  • dacă îți vine să faci copy-paste, fie ele și 3 linii de cod sau una lungă, înseamnă ca ai nevoie de un mic refactor.
  • o arhitectură bună, modulară, a aplicației, DRY (și preferabil KISS) compliant, duce la o mentenanță mai ușoară. Pentru a modifica ceva nu este nevoie să cauți toate instanțele aceleiași bucăți de cod.
  • dacă acea parte de ‘unknown’ umbrește puterea de a-ți crea arhitectura înainte de a o implementa, atunci orice model repetitiv din cod stă bine într-o metodă separată.
  • caută să înțelegi framework-ul pe care îl folosești. De exemplu în dezvoltarea web folosind MVC, nu prea are ce căuta într-un controller o chestie ce ar sta bine într-un helper/bibliotecă, pentru că atunci când este nevoie să fie apelată bucata respectivă din alt controller, fără refactor, o să fie trist. Desigur, excepție fac acele controllere moștenite, dar și acolo este o linie fină între ce se poate moșteni și ce ar trebui să fie apelabil global.
  • refactor, OOP, clase, interfețe, ‘design pattern’ (exemplu: singleton) ar trebui să nu fie doar cuvinte într-un vocabular de specialitate.

Importanța unui PHP framework bine scris

Spuneam la GeekMeet-ul din octombrie (damn it, iarăși fac referință la el) în timpul prezentării mele, pentru cei absenți, o abordare de la OS până la coder în privința Web Security, despre importanța folosirii unui framework ce să facă în mod implicit filtrare XSS și SQL Injection (SQLi) a input-ului, în biblioteca ce se ocupă de baza de date. Iar pentru chestii riscante, chiar o filtrare XSS cu HTML Purifier, o bibliotecă a cărui filtru XSS a fost creat să treacă de XSS (Cross Site Scripting) Cheat Sheet.

Știu, nu vreau să fac “carieră” din astfel de post-uri pe blog și nu prea cred că o să mă vedeți vreodată să trimit chestii către http://hackersblog.org/. Sunt preocupat de a proteja, de a-i învăța pe alții cum să se protejeze, și mai puțin de a demonstra vulernabilități. Sunt orientat către ce nu ar trebui să facă aplicația și mai puțin înspre a demonstra cum ajungi acolo. De altel aș prefera ca lumea să nu se ia de ‘junk’-ul de WordPress ce rulează pe blog, sunt prea ocupat pentru a scrie un engine sigur cu un număr echivalent de facilități. Mă rog, va urma un contra-exemplu pentru a susține cele din paragraful anterior.

Povestea începe de la faptul că am avut o mică discuție cu necenzurat despre importanța folosirii unui framework, dar el o susținea pe a lui cu alea 10 kile de cod. Doar pentru ce îți trebuie un framework de 1.25 megi (dimensiunea minimă, maxim 1.49) pentru o aplicație banală? Pai în primul rând bune sunt cele de PHP5 folosind OOP și clase cu auto-load. Poți face multiple instalări folosind aceleași surse ale framework-ului exceptând aplicația în sine. Folosești ce încarci. A da, și ai filtrare implicită. De ce? Pentru că nimeni nu este perfect. Greșeli apar și în codul programatorilor ce au trecut de fazele tatonării. Vorbesc din experiența lucrului și mai mult din experiența lucrului în echipă. Dacă tu ca programator nu o dai de gard, se prea poate să dea altul.

Acu recunosc, am trișat puțin. M-am uitat puțin prin cele 10 kile de cod astfel încât buba a fost oarecum imediată. Dar nu imposibil de descoperit cu puțină răbdare și stil având în vedere regulile simple de URL rewrite, destul de evidente, și faptul că era vorba de un singur parametru vulnerabil. De fapt am reușit 3 in 1: XSS, blind SQLi și disclosure în același input.

A da, a folosi mysql_error() în producție este una dintre cele mai proaste idei. XSS-ul și disclosure-ul au fost posibile prin intermediul acestei funcții magice ce ar trebui folosite doar pentru dezvoltare, nu și pentru producție.

Momentan nu dăm poze, așteptăm să aplice patch-ul trimis :) .

PHP sub Windows, Zend Server, WinCache și un cluster FastCGI cu Process Manager

La GeekMeet-ul din Octombrie de la Sibiu, Todi Pruteanu ne zicea printre altele despre WinCache – un accelerator de PHP dedicat platformei Windows. Nelămurirea mea legată de WinCache a fost următoarea: dacă Microsoft iși anunță colaborarea pentru a susține PHP sub Windows, atunci de ce nu au colaborat cu echipa APC (Alternative PHP Cache) din moment ce acesta este proiectul de casă și va fi introdus în nucleul PHP începând cu versiunea 6? Întrebarea a rămas fără răspuns. Cu toate acestea, experimentând puțin, am găsit un loc pentru această extensie, deși am impresia că acceleratorul ‘closed source’ de la Zend, ZendOptimizer+ alăruri de Zend Data Cache ce oferă un API de caching compatibil cu APC poate să preia aceeași funcție. Poate pentru că echipa Zend a scris printre altele un modul de Apache, tot closed source, ‘Zend Enabler for Apache’ ce oferă un FastCGI Process Manager pentru Windows suficient de deștept, dar care face o chestie: rularea de mai multe procese FastCGI care deservesc același server web. În plus, Zend Server oferă suport și pentru Microsoft IIS, deci backend-ul PHP nu este restricționat la Apache.

Paragraful anterior rezumă problema, dacă citim printre rânduri. Problema sub Windows este rularea mai multor procese FastCGI ce să servească pe același port, practic un cluster local cu ’round robin load balance’. Tehnic vorbind – se poate. Dincolo de un simplu FastCGI wrapper cum este spawn-fcgi, proiect de casă al lighttpd, a apărut o versiune nativă de Windows pe forurile respective. De curiozitate am luat sursa, am compilat-o cu MinGW (gcc -O2 -lws2_32 -o spawn-fcgi-win32.exe spawn-fcgi-win32.c) și am început să mă joc. Într-un mod așteptat, suportul pentru PHP FastCGI childs nu funcționează sub Windows, din motive tehnice. De fapt cercetând sursele PHP pentru cgi SAPI (php-src/sapi/cgi/cgi_main.c) partea cu child process este pusă între niște blocuri de preprocesare pentru compilator: #ifndef PHP_WIN32 … #endif ceea ce practic anulează FastCGI Process Manager-ul rudimentar implementat de către echipa de dezvoltare a PHP. Motivele sunt simple: spre deosebire de *NIX, sub Windows nu există conceptul de fork() al proceselor. Ba mai mult, sub *NIX există PHP-FPM(FastCGI Process Manager) ceea ce dă apă la moară și mai mult unei platforme non-Windows pentru PHP. Fanii nginx știu despre ce este vorba.

Vestea bună este faptul că acel spawn-fcgi-win32.exe știe să lanseze mai multe procese ce să servească pe același port TCP. Dă și idei despre cum ar trebui implementat un FastCGI Process Manager sub Windows pentru PHP. Ba mai mult, cum ziceam și în paragraful anterior,  acestea vor servi prin round robin load balance. Această arhitectură multiproces, deși nu se pretează stilului Windows ce este preponderent multithread, rezolvă problemele cu extensiile de PHP ce nu au implementat acel ‘thread safety’, iar clusterul poate să facă uz de o arhitectură SMP, fără a apela la threading.

Acum poate apare întrebarea: de ce mai multe procese FastCGI pentru a procesa scripturile PHP? În primul rând practica ne invață că un ’segmentation fault’ poate să apară oricând, iar în producție nu este faptul cel mai de dorit. Arhitecturile multiproces s-au dovedit a fi cele mai potrivite. Vezi cazul Google Chrome cu 1 proces per tab. În al doilea rând, un proces PHP ce servește cereri FastCGI are o limită de 500 de cereri după care acel proces se închide. Acea limită este codată în sursele PHP (tot în cgi_main.c). Acea limită se poate altera prin ‘environment variables’, și anume prin: PHP_FCGI_MAX_REQUESTS. Problema care se ivește: o limită mare poate duce la probleme de memorie ocupată abuziv (memory leaks). În concluzie, această limită este necesară. Prin design-ul serverului FastCGI al PHP, limita este obligatorie și finită deci este nevoie de un PHP FastCGI Process Manager. Apache are ceva extensii (mod_fastcgi si mod_fcgid, doar mod_fastcgi știe să folosească TCP binding) sau soluția Zend Server: Zend Enabler for Apache, IIS are propriul manager. Piața de web servere de Windows ce întâmplător știu de FastCGI nu se termină aici. Spre exemplu eu folosesc versiunea nativă a nginx sub Windows pentru simplul fapt că folosesc nginx și sub alte platforme. Am o târlă de motive pentru care nginx este trecut în preferințele subsemnatului ca web server excelent. Dar, în același timp, nu pot să mă iau după toate ‘tutorialele’ de PHP FastCGI sub Windows unde ‘php-cgi.exe -b 127.0.0.1:9000′ este suficient pentru a rula. Este suficient până la primul crash sau până la 500 de cereri. În plus, eu ca web developer poate că îmi doresc o soluție complet separată de web server.

Bun, acum am pus bazele ideei despre cum ar trebui făcut un Process Manager. Una dintre probleme este acel ‘race condition’: dacă toate procesele au aceeași viață, spre exemplu un cluster local de 4 cu limită implicită de 500, atunci acestea se vor termina în modul următor: la cererea 1997 – primul, la cererea 1998 – al doilea, la cererea 1999 – al treilea, la cererea 2000 – ultimul. Dacă process managerul nu se prinde de faptul că nu mai exista cineva care să proceseze ceva.php, atunci web serverul va servi clasica eroare 504 (Gateway Timeout) iar clienții conectați la webserver vor fi nemulțumiți. Acel php-cgi.exe nu oferă o metodă de identificare a faptului că rămâne fără cereri. Nu există în cod suport pentru IPC (Inter Process Communication) cu un manager. În concluzie, după bootstrap, un manager poate doar să monitorizeze clusterul. Nu susțin faptul că nu s-ar putea implementa. Ori, această monitorizare poate avea întârzieri, și pe un server încărcat aceasta nu este de dorit. În concluzie, printr-un algoritm, managerul ar putea mări artificial și temporar viața proceselor 2, 3 și 4 pentru a pune un interval de întârziere și a fi cineva acolo care să servească până monitorul se prinde de faptul că lipsește cineva. Altă idee ar mai fi modificarea pentru Windows a serverului FastCGI ca să suporte respawn (autospawn), înainte de a se închide, deși încă nu am investigat dacă această posibilitate este realizabilă din punct de vedere tehnic. Teoretic ar fi OK, cel puțin din câte mă prind citind despre varii funcții din Windows API. Ar rezolva problema existenței unui child care să servească, in concluzie managerul s-ar transforma în simplu monitor de procese după secvența de bootstrap unde lansează clusterul. Idei am, din păcate n-am mai pus mâna pe C decât ocazional în ultimii 5 ani. Din fericire mai pricep ce e prin codul altora :) . Ziceam și pe Twitter: De ce nu există un PHP – FastCGI Process Manager sub Windows? Pentru că nimeni nu și-a dat interesul să scrie unul. Posibilităti există!

Ceea ce ne aduce iarăși la WinCache. N-am început degeaba cu el. Unei platforme PHP îi stă bine și cu un opcode cache (PHP accelerator, whatever). Pe lângă PHP din Zend Server – ce vine cu multe jucării de la mama lui, Zend, cred că se poate pune un nginx. Problema acceleratorului și al Cache API-ului ar fi rezolvată. Ba ar fi compatibil codul cu un eventual APC folosit în producție, chiar dacă în teorie, având în vedere soluțiile multiple, se recomandă o bibliotecă abstractă cu drivere pentru varii extensii PHP. Bun, ar zice unii: dar APC ce are? Păi, ultima versiune pusă la dispoziție de unul dintre oamenii ce se ocupă de build-ul de PHP pentru Windows, precum și de dezvoltarea lui, a pus la dispoziție o chestie compatibilă PHP 5.3.x ce din păcate pusă în setup-ul multiproces expus mai devreme duce la crash. Practic din 4 procese, 3 crapă, unul rulează relativ stabil. Contravine ideii de multiproces. XCache deși este excelent, nu foloseste shared memory pentru data cache, deci practic acesta va fi împărțit într-un număr egal cu numărul de procese. Nu știu code cache-ul cum se comportă. WinCache știe doar code cache, dar face uz de shared memory și funcționează bine cu load balancer-ul. În concluzie, cel puțin pe termen scurt WinCache are un rol acolo. Mai mult, WinCache funcționează doar cu versiunile de PHP non-thread-safe, compilate cu Visual C++ 9, și teoretic cu IIS, practic Microsoft a mințit. Funcționează cu nginx fără probleme și de ce nu, cu alte servere.

Altă idee: un server web sub *NIX ar putea folosi un server FastCGI sub Windows. nginx poate să folosească backend-uri multiple, eventual cu load balance între mai multe mașini. Deși încă sunt de părere că PHP sub Windows cam suge datorită faptului că are multe lacune iar majoritatea bibliotecilor ce le integrează provin din *NIX, are un atu: suportul COM/.NET – ceea ce înseamnă că într-o arhitectură existentă se poate adăuga un server Windows cu PHP ce să poată beneficia de anumite SDK-uri comerciale ce se distribuie sub formă de COM.

Agile OpenSpace la Cluj, Scrum și Software Craftsmanship – Code retreat

Vineri și sâmbătă subsemnatul și Ciprian și-au mișcat fundurile pătrățoase până la Cluj pentru o întâlnire informală anunțată de către AgileWorks Romania, ca urmare a efortului curent de a ne ‘agiliza’. Deși inițial s-ar fi anunțat mai multă lume, prezența clujeană a fost destul de restrânsă – ceea ce într-un fel a fost trist, din moment ce au apărut și speak-eri de talie mondială ce în mod normal ar veni pe finanțe dese la o conferință. Noi i-am prins pe ‘moca’. Cei ce au ajuns totuși, în ordinea în care au stat la masă și s-au prezentat:

- Mihai Brehar

- Maria Diaconu

- Aici ar trebui să am un nume, dar am un lapsus în schimb

- Ovidiu Negrean

- Ciprian Stăvar

- Ștefan Rusu (adică subsemnatu’)

- Alex Bolboacă

- Paul Nagy

- Jurgen Appelo

În fine, timpul a fost scurt, au fost ceva probleme cu locația, s-au propus mai multe teme, s-a vorbit în mare parte despre estimări. Am trecut repede la fapte, cu berea în față (am specificat: cadru informal) dar cu atenția spre Agile. Paul în special și restul au oferit câteva informații valoroase:

- estimările se pot face pe task-uri ce nu depind de alte task-uri. Un dezvoltator pricepe mai bine care-i treaba cu dependința.

- este mai ușor să măsori în unități relative comparat cu unități bine stabilite. Exercițiul a constat în faptul că l-a pus pe Mihai Brehar să estimeze distanța dintre ei. Răspuns: 1,5m. Următoarea chestie a fost: pune degetul unde crezi tu că este jumătatea distanței dintre noi. Ochiometric a fost bine, iar dacă treceam la măsurători precise, a doua estimare ar fi mai bună – de unde și povestea cu velocity points. Pe de altă parte acele velocity points sunt valabile pentru o echipă. Schimbi oameni din echipă – ai altă echipă. Ajungem la filosofia Agile – oameni, nu unelte, dar despre asta era vorba în primul rând, nu?

- pentru cei ce vor să estimeze task-urile în timp, Paul a fost ferm: ‘am o veste proastă pentru dezvoltatori – nu puteți’. Se leagă de povestea de mai sus.

-  au fost prezentate mai multe metode de estimare, pe lângă clasicele numere incrementate sau luate ca valori din șirul lui Fibonacci, Alex a prezentat un tabel ceva mai complicat (nu îl pot reproduce, am reținut doar chestia cu numerele la tricouri :) ), iar Paul a vorbit despre metoda cărților de poker.

- ca idee, este nevoie de date suficiente pentru a face calcule. Ideea este luată oarecum din teoria numerelor mari din statistică. Numerele mici dau statisticile peste cap cu variații mari când ai date puține … dar când ai date multe, situația se schimbă.

- încă o reprezentare grafică a fost o chestie ce arăta partea de ‘known’ și partea de ‘unknown’ ce înconjoară acea zonă. Se leagă de chestiile de mai sus. Scopul este de a trece mai repede de la ‘unknown’ la ‘known’ prin învățare – cu cât înveți mai repede, cu atât mai repede se produce tranziția – și prin feedback.

Pentru că discuția a rămas începută, am schimbat locația datorită micilor probleme pomenite mai sus. Mai multă bere (beer is priceless!) și discuții mai aprinse. Ca niște concluzii: Agile este o filosofie (nimic nou sub Soare aici) ca răspuns celor ce debitează pe această temă. Paul (din nou) a venit cu o completare la idee prin ‘Scrum este un framework’. Ba mai mult, este un framework minimal – dacă scoți din el, se duce naibii totul, dar mai departe pe el se poate construi și personaliza metodologia de lucru. De altfel, cred că Jurgen a spus aceasta, sper să nu atribui greșit citatul/adaptarea, cei ce ‘fac Scrum’ au tot atâtea șanse de a ‘face Scrum’ câte șanse are un programator de a instanția o clasă abstractă. Lucru ce vine în completarea ideii despre Scrum ca framework.

Altă discuție interesantă la bere ce merită menționată a fost motivul pentru care managerii nu trebuie să pună presiune pe dezvoltatori. Din nou Paul la balon – da a fost vedeta serii. Cercul vicios sună/arată cam așa: presiune de la manager catre dezvoltator -> grabă + hack -> cod prost -> maitenance -> mai puțini oameni activi. Ultimele 3 duc la frustrare, buguri care mai departe duc la și la mai multă presiune, iar frustrarea adaugă încă o doză de cod prost și bug-uri.

A doua zi a fost dedicată Code retreat-ului, deși a apărut prin zonă doar Mihai Brehar și mai târziu Ovidiu Negrean. Deși mă simțeam ca după o bătaie cu parul (motiv necunoscut), am luat parte la toate cele trei iterații ce s-au făcut pe problema jocului de poker, problemă pentru care am apelat la PHP ca limbaj și Kohana ca framework pentru simplitatea de a încărca automat clase și a face rapid un prototip. Primele două au fost alături de Mihai unde am exersat varii tehnici (TDD, pair programming), ultima a fost cu Alex. Ultimele două iterații au fost bazate pe TDD. Ca rezumat:

- prima iterație = FAIL. Cică era de așteptat. După 45 minute de pair programming, codul a fost rulat o singură dată și a returnat un simplu 0 – ceea ce nu rezolva prima mână. S-a văzut importanța testelor și ca o paranteză la implementare – folosirea limbajului de business cerut de client (black și white pentru jucători, nu hand1 și hand2).

- a doua iterație, TDD based, nu doar că a fost cu succes, dar am avut și timp de refactoring plus 5 minute de relaxare. Alex a fost prin zonă cu o mână de ajutor deoarece nimeni nu știa cum să facă TDD.

- a treia iterație a mers tot pe mâna TDD, am folosit o abordare diferită a problemei (altă echipă). Inițial ne-am propus să rezolvăm problema full house, iar în final am rezolvat și careul deoarece soluțiile erau înrudite în contextul respectiv. De data aceasta am fost creativ și am folosit o metodă matematică ce nu presupune parcurgerea mâinilor, ci calcule. Problema s-a redus la una de rezolvare a unui sistem de clasa a VI-a:

{ 2X + 3Y = 4X + Y

{ 2X + 3Y = X+ 4Y

ce rapid ajunge la X = Y  pe ambele ecuații (două drepte suprapuse, ca reprezentare în plan x0y) de unde și concluzia că soluția este funcțională pentru cele două cazuri (full + careu), deoarece X = Y presupune ‘five of a kind’ cum erau la acele jocuri obosite de poker ce se găseau prin varii baruri. E bună și matematica aceasta la ceva în programare și mi-am adus aminte de ce sunt bune unele modele: dacă sunt demonstrate corect și implementate corect, sunt ‘bug free’ din punct de vedere logic. Excludem erorile de limbaj/runtime.

Pentru că puțini pricep cum se face TDD, iau ca exemplu un feature ce trebuie să returneze -1, 0 sau 1 – folosit și în tratarea cazurilor la jocul de poker (black, tie, white).

- se scrie primul test (am folosit assert($obj->method() == -1);, nu am apelat la PHPUnit)

- se implementează un mock în method (return -1;)

- se rulează testul => OK

- se scriu celelalte teste (assert($obj->method() == 0); și assert($obj->method() == 1);), se rulează și evident, eșuează

- se implementează codul funcțional propriu zis

- se rulează iar testele, iar dacă totul e OK, refactor și teste

Chiar aveam într-o metodă o eroare de logică, TDD a arătat rapid sursa problemei, iar debug-ul a durat 10 secunde. Avantajele sunt clare. Ca idee: TDD se potrivește doar pentru core functionality, nu pentru interfețe. Nu poți testa un capcha sau un CSS pe IE 6 prin TDD. Pentru aplicații ce folosesc baze de date, este nevoie de un mock. În rest, metoda își arată utilitatea. Noapte bună!


Designed by: studentzFM | Theme made for free by: Casino , punkzFM and mygroovez | Heavily modified by SaltwaterC