Atenţie! Aceasta este o versiune veche a paginii, scrisă la 2007-10-27 13:31:34.
Revizia anterioară   Revizia următoare  

Infoarena3

Codul din spatele site-ului infoarena2 este intr-o stare foarte proasta si
trebuie rescris. Asta este o propunere foarte ambitioasa si riscanta si este
nevoie de o explicatie detaliata pentru a demonstra ca rescrierea soft-ului
din spatelei site-ul de la 0 este cea mai buna modalitate de a avansa site-ul.

Putina istorie

Site-ul infoarena1 a fost scris acum vreo 4-5 de Cristi pentru a fi prezentat
la infoeducatie, un concurs de soft de la Galaciuc. Site-ul era foarte
impresionant si a castigat concursul chiar timp de 2 ani la rand. Mai mult,
site-ul era atat de bun incat a intrat in "productie" si a adunat o comunitate
in jurul lui care a produs un numar impresionant de probleme si concursuri.

Soft-ul din spatele site-ului a ramas aproape identic cu ce a venit Cristi la
Galaciuc; s-au facut doar niste schimbari absolut necesare si bug-fix-uri. Am
incercat sa punem pe picioare site-ul trac, sa bagam codul in subversion dar
in realitate nimeni nu s-a atins de cod. Au crescut niste lucruri pe langa
cod; cum ar fi un "portal editabil" de informatica si o integrare foarte
neplacuta cu soft-ul media-wiki. Eventual am ajuns la concluzia ca nu se poate
face nimic si trebuie rescris de la 0.

In vara lui 2006 ne-am adunat 5-6 flacai, ne-am dus in munti si ne-am incuiat
in casa ca sa facem infoarena2 (multumim din nou lui vali). Intre noi il aveam
doar pe Cristi cu o oarecare experienta in web-development, in rest eram in
cea mai mare parte incepatori in php, mysql, etc. Site-ul nu a fost terminat
acolo in munti si a fost nevoie de un numar de "coding camp"-uri pentru a pune
site-ul pe picioare si a ajunge macar la nivelul de functionalitate din
infoarena1. Site-ul a fost eventual lansat spre sfarsitul lui 2006, dar parti
de genul editarea de runde si probleme (o cerinta critica) a fost finalizata
doar in 2007.

Softul infoarena2 este mult mult mai bun decat cel din infoarena1. Acest lucru
se poate vedea cel mai bine din calitatea si dimensiunile site-ului. Este
suficient doar ca numarul de probleme din arhiva este mai mult decat dublu,
dar acum este posibil pentru comunitatea site-ului sa ne ajute
mult mai mult.

Din pacate dezvoltarea la site-ul infoarena2 a stagnat de multa vreme. Au mai
fost tentative de coding-camp-uri si chiar s-au adaugat feature-uri

noi
, dar progresul este mult prea incet. Exista multe cauze pentru
aceasta stagnare, dar eu (Leonard) consider ca problema este este calitatea
codului. Infoarena2 este un soft complicat si incurcat in care este mult prea
dificil sa faci modificari, iar asta scade motivatia developerilor.

Putem sa incercam niste "boost-uri" de motivare prin coding-camp-uri dar
scopul este sa avem un grup de indivizi care lucreaza de acasa in timpul lor
liber. Pentru asta trebuie ca programarea sa fie usoara si distractiva, iar in
infoarena2 nu este cazul. Soft-ul nostru este mult mai "frumos" decat multe
produse comerciale, dar la infoarena2 nu exista motivatia financiara (si nici
nu vrem sa existe).

Problemele infoarena2

Pe parcursul dezvoltarii infoarena2 noi (Cristi, Leonard, Mircea, Vali,
etc...) am facut un numar de greseli majore la care acum simtim efectele. Daca
incepem din nou programarea la proiectul infoarena3 nu o sa facem din nou
aceleasi greseli si site-ul va fi mult mai bun. Daca stim ce am gresit si cum
sa evitam nu vom ajunge din nou in aceasi situatie.

Poate parea trist ca aruncam la gunoi aproape un an de efort, dar nu este
cazul. Vom pastra tot continului site-ului, care valoreaza enorm (si asta tine
de fapt infoarena.ro in viata). Si vom pastra lectiile infoarena2, care sunt
mult mai valoreasa decat codul efectiv scris in php. Ar fi cu totul altceva
daca alti oameni ar rescrie codul, ei probabil ca ar face aceleasi prostii si
ar fi mai bine sa se tina de treaba la infoarean2.

Am facut o lista cu ce anume am gresit in infoarena2 si cum putem face mai
bine (in infoarena3). Este posibil sa reparam multe dintre probleme in
infoarena2, fara o rescriere, dar multe dintre aceste greseli gresite vizeaza
arhitectura fundamentala a site-ului. Acestea nu pot fi reparate decat
printr-un efort enorm, iar acel efort cumulat ar fi mai mare decat rescrierea
de la 0.

ia_parameter_values

Unul dintre tintele infoarena2 a fost sa avem mai multe tipuri de runde si
probleme. Fiecare tip de runda sau de problema are alti "parametri", ne-am
gandit sa tinem toti acei parametri intr-un sigur tabel de forma "id-obiect",
"nume-parametru", "valoare". Este o idee foarte proasta care nu are absolut
nici un merit.

Ar trebui sa avem pentru fiecare tip de problema sau runda un tabel de genul
ia_classic_task, care contine o coloana task_id si apoi cate o coloana pentru
fiecare parametru. Eu (Leonard) am incercat aceasta transformare dar nu am
reusit (din cauza repercursiuni in restul site-ului) si am renuntat.

ia_score

Tabelul ia_score are coloanele: score_id, user_id, task_id, round_id si score.
Primele 4 coloane sunt sunt nulabile, asa ca tabelul nu are PK. Idea era sa
tinem scoruri per runda cu task_id NULL si eventual statistici per task/round
cu user_id NULL. Este un tabel oribil si mi-e rusine de ce am facut acolo.

Este prea greu sa faci query-uri in tabel si din pacate infoarena1 avea de
fapt mai multe statistici decat infoarena2. Asta cred ca este singurul punct
in care infoarena1 depaseste infoarena2.

Acest tabel ar trebui spart in mai multe tabele fara coloane nulabile. Idea
fundamental gresita de aici este economisirea numarului de tabele din baza de
date, care este o prostie. Este ca si cum ai incerca sa folosesi mai putine
functii facand copy-paste.

Id-uri VARCHAR

Id-urile pentru utilizatori sunt numere, dar restul sunt VARCHAR cu niste
validari facuta in cod prin regex-uri. Ar fi mai bine sa avem task_id ca numar
si task_name ca string absolut peste tot. task_name se poate obtine foarte
usor din task_id adaugand un join trivial.

MySQL nu face index pe hash-uri DOC LINK HERE pentru tabele pe disc, el
sorteaza id-urile tinand cont de colatii (latin2). Tinand string-uri peste tot
crestem dimensiunile tabelelor, si asta este oribil pentru tabele de genul
ia_score sau ia_job. S-ar merita de facut niste teste de performanta comparand
un tabel de scor exclusiv numeric cu unul plin de string-uri.

Securitatea, si magia din wiki

Pe parcursul dezvoltarii infoarena2 ne-am dorit sa evitam pe cat posibil
functionalitatea magica din wiki, si am mers prea departe. Am pornit de la
idea ca orice pagina este o pagina de wiki, si paginile de runde sau probleme
sunt doar un caz oarecare de pagina wiki. Securitatea paginilor de utilizatori
si de probleme este totusi subordonata problemelor, si asta am realizat
adaugand un "descriptor de securitate" ca string pentru fiecare pagina de
wiki. Pagina problema/adunare are la securitate un string "task: adunare", asa
ca vizibilitatea depinde de vizibilitatea task-ului. Este un sistem prea
generic, incurcat si greu de folosit sau extins.

Ar fi mai ok ca orice url de format problema/xxx sa intre prin controller-ul
de task-uri, care subordoneaza textblock-urile care incep cu problema/xxx.
Similar am avea controllere de news, blog, user page care subordoneaza tot ce
incepe cu news, blog sau user/costel. Pentru restul paginilor am avea un
controler DISTINCT de wiki. Codul pentru bucatile de editare si istorie poate
fi refolosit in 1000 de moduri, dar nu este acceptabil sa nu poti ajunge de la
editarea de enunt la editarea de problema fara sa modifici in address bar.

Nu este nimic gresit in a avea tabele ia_news, ia_blog_post si ia_wiki care
sunt "deasupra" lui ia_textblock, iar ia_textblock sa fie folosit doar pentru
versionarea unor bucati mari de text. Securitatea private/protected/public
(care este FOARTE utila si absolut OK) poate fi un simplu enum in ia_wiki.

Efortul necesar pentru o astfel de transformare in infoarena2 mi se pare
absolut enorm.

Layer de logica

Infoarena2 pretinde ca foloseste o arhitectura MVC, dar MVC este o notiunea
foarte larga si vag definita. Nu este interesanta o discutie detaliata asupra
ce inseamna MVC, asa ca voi discuta doar ce se foloseste efectiv in site-ul
infoarena2.

Url-urile sunt parsate in index.php si in functie de o logic complicata si nu
foarte interesanta fiecare request http este pasat la un "controller", care
este in principiu o functie php de prin www/controllers. Acel controller face
ceva cu requestul, de obicei baga niste request-uri in baza, si apoi face un
hash de "date pentru afisat" care il trimite la un view.

View-urile nu sunt functii, sunt fisiere .php oarecare din www/views. Lansarea
unui view este o operatie sinucigasa, se executa fisierul de view folosind
hash-ul de date si se trimite direct pe "teava". In acel view este posibil sa
se foloseasca textile, care poate executa macro-uri care(de obicei) se duc
pana in baza. Asta inseamna ca poti sa te duci in baza dupa executia
controller-ului, dar nu mi se pare nimic rau in asta. Macro-urile sunt
efectiv niste mini-controllere.

Problema este ca noi din controllere ne ducem direct in baza si logica fragila
de genul securitate este imprastiata si combinata cu cod jegos de
parsat/validat request-ul (in controller) sau construit query-uri sql (in
functiile de db). Aceasta problema are o rezolvare destul de clara si
bine-cunoscuta (dar nu de catre noi in vara 2006).

Intre codul de controller(UI) si codul de baza de data(DB) sa mai pune niste
cod de "business logic"(BL). Tot ce inseamna parsarea request-ului se face in
UI, tot ce inseamna contruirea de SQL se face in DB. BL contine de fapt tot
codul cu adevarat interesant pentru functionarea corecta a site-ul. Codul de
DB nu trebuie sa aiba grija decat sa construiasca query-uri (si sa evite sql
injection) iar codul de UI se ocupa de a vedea ce butoane a apasat
utilizatorul.

Unul dintre avantajele majore este ca se pot scrie usor teste pentru BL, iar
daca BL-ul nu are greseli atunci UI-ul nu poate sa strice nimic (decat
experienta utilizatorului). A se vedea punctul urmator.

Testele pe baza de curl

PHP este un limbaj foarte fragil, unde este foarte usor sa faci greseli
grosolane. Asta este o problema generica a limbajelor dinamice de genul php,
python, ruby, javascript fata de limbajele de genul C, C++, C# si java, si in
PHP este mult mai important sa testezi codul.

Teste curente sunt facute pe baza de curl, curl fiind o librarie de access
http. Testele construiesc un request complet http pe care il trimit pe fir,
asteapta ca apache sa raspunde si apoi verifica niste chestii din request (in
cea mai mare parte prin preg_match si strstr). Ambele faze sunt greu de facut,
dar are ca avantaj ca se trece prin tot codul si este foarte "realist".

Pentru a usura testarea am facut controllerele noastre de editare sa accepte
un parametru de form absent drept "nu vreau sa editez acest parametru". Asta
este necesar in teste dar e un comportament artifical care a "nascut" niste
bug-uri foarte urate. In retrospectiva a fost o idee proasta, care a introdus
o cuplare oribila intre controllere si codul de test. Ambele sunt acum foarte
greu de modificat.

Ar fi mai bine sa testam functii BL care nu au nici o treaba cu HTTP. Daca
BL-ul este ok atunci sigur bug-urile din UI nu pot sa strice nimic in baza.
UI-ul se poate testa apoi de mana.

ia_textblock, ia_textblock_history

ia_file

Caching exagerat

Un plan de atac

Branching

Nu am folosit eficient branch-uri. Absolut toate modificarile le-am facut
direct in trunk iar asta nu este o idee buna. Exista mereu schimbari mari,
care au nevoie de mai multe commit-uri pentru a fi complet functionale, iar
Astfel de schimbari trebuie facute intai intr-un branch special si abia apoi
copiate in trunk.

In asa fel trunk-ul devine mult mai stabil si nu este nimic rau in a abandona
o idee. In trunk-ul infoarena2 avem cod mort pentru idei abandonate, care acum
este dificil de extras. Branch-uri ar fi trebuit sa facem pentru cache-ing, editoare de probleme,
validate_array, tag-uri, blog, dataset-uri etc.

LINK TO PRODUCING OSS

Responsabilitati

Codul infoarena este open-source, iar oamenii lucreaza doar in timpul lor
liber. Dar daca vrei sa ajuti infoarena atunci trebuie sa te tii de treaba si
rezolvi tichetele pana la o anumita data. Ar ajuta mult ca un tichet
"acceptat" sa aiba un owner care este trebuie sa rezolve acel tichet pana la o
anumita data.

Bineinteles ca nu avem cum sa fortam pe nimeni sa lucreze la infoarena, dar se
presupune ca un individ care vrea sa ne ajute cu adevarat nu vrea sa frece
menta. Astfel de dead-line-uri ar fi un impuls interior pentru fiecare din
noi. Atentie: nu ma refer la dead-line-uri de genul "ar fi frumos sa avem #123
rezolvat pana luna viitoare", ma refer la lucruri de genul "eu rezolv #124
pana maine si #125 poimaine".

Ordine in tichete

Demo-uri

  • Framework-uri
  • SqlAlchemy
  • Selenium
  • Form-uri
  • Tabele
  • BL prin HTTP
  • Wiki si atasamente in subversion.

Arest la domiciliu