Lucrez de mai mult de
doi ani la o aplicaţie complexă. Am pornit cu framework pe
care l-am dezvoltat mai degrabă din plăcere decât dintr-o
necesitate concretă. Am încorporat aici o mulţime de
funcţionalităţi pe care mi le-am imaginat tipice pentru o
aplicaţie din domeniul evidenţei, începând de la
colecţii de obiecte organizate ierarhic, trecând prin
modalităţi flexibile de structurare şi restructurare dinamică a
stocării, prin mecanisme automate de generare a formularelor şi a
interacţiunii cu utilizatorul şi ajungând până la
fluxuri de documente, "metafora" centrală a întregului
demers. Când s-a ivit ocazia unei implementări concrete, am
fost entuziasmat, iar munca investită s-a recuperat aproape imediat:
prima versiune funcţională a fost gata într-un timp record
(mai puţin de trei săptămâni, în condiţiile în
care proiectul era evaluat la un an). Am avut şi şansa ca aplicaţia
să pornească odată cu afacerea clientului, aşa încât
nu am avut nicio "moştenire istorică": nici date, nici
utilizatori cu obişnuinţe formate, nici cultură organizaţională
refractară la schimbare. Părea situaţia ideală.
Dar curând au
început problemele. În scurt timp, numărul de clienţi
ai beneficiarului a crescut iar aplicaţia a devenit
mission-critical. Cum ştie
orice proiectant de software, o astfel de aplicaţie nu se termină
practic niciodată. Pe măsură ce încărcarea a crescut,
clientul a avut noi şi noi cerinţe. La început, "cârligele"
pe care le-am prevăzut pentru a trata situaţiile atipice au reuşit
să păstreze coerenţa ansamblului, dar urgenţele au ajuns curând
să impună soluţii improvizate, scurtături, hacking şi structuri provizorii care,
teoretic, ar fi trebuit standardizate pentru a se încadra
uniform în construcţia coerentă a framework-ului.
Din păcate, am început să fac compromisuri, uneori chiar la
nivelele de jos ale construcţiei. Mai mult, am pierdut posibilitatea
testării "la rece" a noilor funcţionalităţi, datorită
faptului că în producţie aplicaţia comunica cu aparate
complexe, pe care nu aveam cum să le simulez. Probabil ştiţi una
din celebrele legi ale lui Murphy, care spune să orice soluţie
provizorie tinde să devină permanentă. Pot depune mărturie: aşa
este.
Rezultatul este
previzibil: aplicaţia a devenit stufoasă, greu de înţeles
şi, mai ales, greu de întreţinut. Încapsularea
funcţionalităţilor s-a deteriorat şi fiecare intervenţie tinde
să propage efecte laterale şi victime colaterale. Ceea ce în
urmă cu un an îmi cerea o jumătate de oră de muncă, acum
îmi cere două ore de concentrare, dintre care mai mult de
jumătate sunt dedicate descifrării unor fragmente de cod pe care nu
le mai pot califica altfel decât mizerabile. Debugging-ul
a devenit o teroare permanentă. Documentaţia a rămas în urmă
şi în mare parte şi-a pierdut actualitate, ceea ce face
aproape imposibilă colaborarea. Iar ceea ce ar fi trebuit să fie un
motiv de sărbătoare (contractul pentru o nouă instalare) a devenit
un motiv de îngrijorare.
Nu există decât
o singură soluţie: refactoring. Lucrez din nou cu plăcere,
pe un cod curat şi pe specificaţii clare, deşi ştiu foarte bine
că nu va fi uşor să mut o clădire pe o nouă temelie, cu
locatarii înăuntru (iar ei nici nu trebuie să simtă). Dar cu
siguranţă nu sunt singurul care a ajuns în situaţia asta.
Până la urmă, face parte din ciclul de viaţă firesc a
fiecărui produs software. Mai mult chiar, e poate unicul domeniu în
care avem şansa să reconstruim din mers.
Să nu vă imaginaţi
că voi încheia cu sfaturi moralizatoare (şi, desigur,
inutile) despre reguli de stil în codificare, documentaţie,
specificarea detaliată a funcţionalităţilor în contracte şi
altele asemenea. În schimb, sunt gata să trag nişte concluzii
despre softul open source. În primul rând, nu-l mai cred
pe Perens atunci când afirmă în Catedrala şi bazarul
că, în cea mai mare parte, calitatea înaltă a
programelor open source se datorează depanării atente şi
îndelungate (conform legii lui Linus: "given enough
eyeballs, all bugs are shallow").
Calitatea vine tocmai din libertatea pe care o au proiectanţii de a
reconstrui mereu aplicaţiile, din temelii. E o libertate, dar şi o
obligaţie: câtă vreme codul nu este clar, pertinent comentat
şi perfect structurat, colaborarea între hackeri devine
dificilă iar proiectul moare. Aşa funcţionează selecţia
naturală.