marți, 13 noiembrie 2012

Câteva cuvinte despre algoritmi în Java şi PHP (introducere)

O binecunoscută butadă relevă că în spatele oricărui „succes peste noapte” stau zece, cincisprezece sau chiar douăzeci de ani de muncă asiduă. Şi, deşi oricine cunoaşte acest lucru, foarte mulţi continuă să creadă în existenţa unor minuni care îi vor face să dobândească succesul instantaneu. Fac acest lucru din două motive: primul, fiindcă partea cu „munca asiduă” este extrem de neplăcută – deşi „nemunca” eîncă şi mai neplăcută, iar al doilea, fiindcă minunile evocate chiar se întâmplă! În domeniul material, de exemplu, prin intermediul loteriilor, al sistemelor de pariuri, al jocurilor de noroc, mulţi, foarte mulţi oameni au realizat câştiguri fabuloase! Cu adevărat fabuloase! Şi ... mulţi, cu adevărat mulţi: cam unul la zece, sau o sută de milioane de „ghinionişti”. 

Într-un celebru eseu din 2001, Peter Norvig, director de cercetare la Google Inc. îşi exprima speranţa că un om talentat şi interesat ar putea învăţa să programeze bine în doar zece ani! Şi încă singur! Articolul e plin de idei bune, dar trebuie tratat cu o oarecare circumspecţie, fiindcă, de atunci au trecut, totuşi, zece ani, şi lucrurile s-au mai schimbat, pe ici, pe colo, în sensul că „materialul de studiu” a devenit mult mai bogat, mai stufos, dar şi prin faptul că, pe alocuri, autorul pare a se contrazice: „lucrează la proiecte cu alţi programatori”. În alte cuvinte, învăţarea „de unul singur” trebuie să se producă, totuşi, „împreună”. 

Limba şi cultura în care ne-am născut au o influenţă majoră asupra formării noastre ca oameni, asupra „Weltanschauung”-ului nostru. Desigur, în timpul vieţii putem invăţa o nouă limbă, sau mai multe, putem să ne apropiem de o altă cultură, sau de mai multe, iar dintr-o astfel de experienţă putem realiza că paralelismul limbilor naturale este imperfect, că, pentru a exprima o anumită idee, sau concept, o limbă este mai potrivită decât alta şi că, pentru a crea o literatură, o bogată şi valoroasă literatură, este nevoie de o limbă evoluată şi puternică. 

Nu altfel stă treaba şi în ceea ce priveşte limbajele de programare, acestea constituind interfeţele prin care programatorul şi calculatorul pot comunica. Aşa cum nu toate limbile sunt la fel de potrivite pentru a exprima un concept, o idee, sau un termen concret – spre exemplu, ne putem imagina că, pentru un zulus este, în general, mult mai greu, decât pentru un yakut, să înţeleagă, să definească, să „poetizeze” termeni precum „ger pătrunzător” sau „permafrost” – tot aşa limbajele de programare, chiar cele de cel mai general uz, prezintă unele caracateristici care le fac mai potrivite sau mai puţin potrivite pentru o anumită aplicaţie sau/şi un anumit programator. 

În fapt, limbajele de programare, şi, mai general, softurile de creare de obiecte şi aplicaţii sunt orientate spre un anumit aspect, cum ar fi: creare de documente, imagini, sunete etc., sau creare de aplicaţii de uz ştiinţific, de uz economic, de uz didactic, pentru realizarea de comunicaţii etc. De asemenea, limbajele respective sunt create în legătură cu o paradigmă de programare. 

În spatele oricărui program de calculator stă un anumit algoritm. Sau, mă rog, mai mulţi algoritmi. Ce e un algoritm? 

Cuvântul provine din limba persană şi reprezintă varianta latinizată a numelui unui matematician foarte important, din secolul IX. De fapt, reproduce acea parte din nume care face referire la localitatea de baştină a savantului: Muḥammad ibn Mūsā al-Khwārizmī (particula „ibn” înseamnă „fiul lui”, iar „al” face referire la locul de baştină) –azi, localitatea se numeşte Khiva şi este un oraş cu vreo 50.000 de locuitori, situat în oaza Khwarezm, provincia Xorazm, Uzbekistan. 

La modul cel mai general cu putinţă, un algoritm reprezintă o metodă, o modalitate de rezolvare a unei probleme. Iar activitatea de programare are exact acest obiectiv, şi anume rezolvarea de probleme cu ajutorul calculatorului. 

Prin urmare, aşa cum învăţarea unei limbi ne poate facilita comunicarea, transmiterea unor idei, dar nu ne este de niciun folos în absenţa acestor idei, tot aşa, un limbaj de programare este foarte util pentru a „înfăşura” un anumit algoritm într-un „ambalaj” care să poată fi înţeles de către calculator, dar nu ne este de niciun folos dacă nu avem ce algoritm să „înfăşurăm”. 

Algoritmica este, aşadar, ştiinţa pe care trebuie să o studiem şi să o înţelegem înainte de a ne apuca, propriu-zis, de programare, şi fără de care nu se poate vorbi de niciun fel de programare. Pentru că, până la urmă, un program nu este o succesiune de linii de cod, corecte din punct de vedere sintactic, dar care nu rezolvă, de fapt, nicio problemă, ci transpunerea, într-un limbaj de programare, a unui algoritm de rezolvare a unei probleme. Iar asta înseamnă, de fapt, 99% matematică. 

La începuturile ştiinţei calculatoarelor, se cunoşteau nenumărate exemple de diverşi algoritmi, dar o ştiinţă sistematizată a algoritmilor nu exista, propriu-zis, şi, din acest motiv, fiecar programator îşi crea programele mai mult intuitiv, în funcţie de „fler”, intuiţie şi experienţă. Fiecare program păstra „amprenta” creatorului său, şi, din acest motiv, erau greu de înţeles şi depanat de către un alt programator. 

 Acest „stil” de programare a condus destul de repede la o criză a acestei activităţi. Pe măsura creşterii dimensiunii lor, programele au devenit din ce în ce mai greu lizibile şi, ca urmare, costurile legate de depanarea şi actualizarea lor sau/şi de creare a noi programe au crescut exponenţial. Trebuia făcut ceva, iar acest „ceva” s-a numit programarea structurată. 

Ideea de bază a programării structurate este cea exprimată în celebra teoremă de structură a lui Böhm-Jacopini, din 1966, care afirmă, grosso-modo, că, pentru a crea orice program de calculator, sunt suficiente doar trei structuri, şi anume cea secvenţială, cea de decizie şi cea de ciclare. Şi, de asemenea, că orice program poate fi rescris în aşa fel încat să nu mai utilizeze instrucţiunide salt, cum ar fi „goto” (sau „jump”, în alte limbaje). 

În acele vremuri, un program era, de fapt, un text compus dintr-un anumit număr de linii (instrucţiuni, propoziţii, enunţuri). Fiecare linie instruia calculatorul asupra unei acţiuni pe care o avea de efectuat, îi furniza o anumită informaţie etc. – aici, lucrurile nu sunt fundamental diferite nici astăzi. Toate aceste linii, sau măcar o parte din ele erau etichetate, ceea ce înseamnă că li se asocia un anumit simbol, de obicei un număr natural, dar şi un text scurt, în alte situaţii, iar programul conţinea linii care forţau calculatorul să continue nu cu execuţia următoarei linii, ci cu o alta, cu o etichetă precizată. 

Programarea structurată a impus eliminarea acestor instructiuni de salt, iar efectul imediat a fost acela de creare a unor programe mult mai simple, mai clare şi mai uşor de depanat. Entuziasmul şi beneficiile create de această paradigmă au fost atât de mari, încât profesorul Niklaus Wirth, de la Universitatea din Zürich, Elveţia a creat, în 1972, un limbaj de programare special pentru învăţarea programării structurate, pe care l-a denumit Pascal, in cinstea marelui savant şi filosof Blaise Pascal. Extrem de popular, la un moment dat, în mediile educaţionale, limbajul Pascal şi-a atins, cu prisosinţă, obiectivul pentru care a fost creat, dar, din păcate (sau nu), nu a devenit foarte popular în industria de software, datorită, în principal, multiplelor sale limitări „didactice”. Oricum, datorită simplităţii sale şi modului în care introduce elevul în învăţarea principiilor programării structurate, limbajul Pascal este utilizat, în continuare, în mediile şcolare şi chiar universitare din România.

 „Biblia” programării structurate este, până în zilele noastre, lucrarea din 1972, a profesorilor O.J. Dahl (Oslo), E.W. Dijkstra (Eindhoven) şi C.A.R. Hoare (Belfast), intitulată Structured Programming. 

Un alt progres a fost reprezentat de apariţia programării procedurale. Ce este programarea procedurală? 

Programatorii au observat relativ curând că, în decursul unui program erau siliţi să repete, identic sau aproape identic, anumite secvenţe de cod, corespunzând unor operaţiuni efectuate de mai multe ori, cum ar fi, de exemplu, ordonarea unui şir, aşa după cum, de exemplu, se repetă refrenul în textul unui cântec. Şi atunci, soluţia firească găsită a fost aceea a creării unor programe de dimensiuni mai reduse, care să îndeplinească anumite operaţiuni frecvente, şi care să poată fi apelate (invocate) folosindu-le doar numele, şi nu rescriind tot codul. Astfel de progrămele – de fapt, unele, deosebit de complexe – au fost denumite - în funcţie de faptul că returnau un rezultat, sau efectuau doar o prelucrare, precum şi în funcţie de limbajul respectiv – funcţii, proceduri, metode, (sub)rutine etc. au uşurat foarte mult munca programatorilor. Mai mult decât atât, limbajele de programare au început să conţină, în ele însele, biblioteci sau module de funcţii (metode) de dimensiuni absolut impresionante – e vorba de mii si mii de funcţii, care „fac” o mulţime de lucruri deosebit de utile şi necesare. 

Apariţia programării procedurale uşurează enorm munca programatorilor (ori de câte ori nu o complică într-un mod inacceptabil), dar mai realizează un lucru foarte important: permite reutilizarea unor componente ale unor programe. În alte cuvinte, până la programarea procedurală, regula era: o problemă = un program, altă problemă = alt program. De la programarea procedurală încoace, regula este, de fapt, alt problemă = acelaşi program, uşor modificat. 

Următorul pas a fost reprezentat de programarea pe obiecte. Ideea programării pe obiecte a pornit din observarea naturii înconjurătoare, în care nu există „date” sau informmareaţii „pure”, ci numai asociate unui anumit obiect. În alte cuvinte, în natură nu întâlnim lungimi, pur şi simplu, ci lungimi ale unor obiecte, mase, ci mase ale unor obiecte, şi aşa mai departe. Acestea nu mai sunt, aşadar, noţiuni abstracte, ci devin atribute concrete ale unor obiecte. Apoi, orice obiect „ştie să facă” ceva, ceva ce un alt obiect „ştie” sau nu: de exemplu iepurele „sare”, pisica „miaună”, iar brânza „pute”; acestea sunt metodele obiectelor respective. În plus, obiectele pot fi clasificate după modul cum derivă unele din altele, clasificare inspirată din taxonimia inventată de botanistul suedez Carl Linnaeus (von Linné). Astfel, de exemplu, iepurele este un „rozător”, „rozătoarele” sunt, la rândul lor, „mamifere”, „mamiferele”, „vertebrate”, şi aşa mai departe, iar unele din „metodele” iepurelui, de exemplu aceea de a „roade” nu este o „invenţie” proprie, ci este comună întregului grup, pe când metoda „este drăguţ” îi aparţine în totalitate, celorlalte rozătoare (şoareci, şobolani etc.) aplicându-li-se, mai degrabă „metoda” „este respingător”. 

Dar, mai pe larg despre programarea pe obiecte vom mai avea ocazia să vorbim. 

Toate aceste paradigme ţin de programarea imperativă, sau programarea cu reguli. Este vorba de acea programare în care calculatorului „i se spune”, in mod clar, ce trebuie să „facă”. În fapt, într-o astfel de perspectivă, calculatorul este „luat de prost”, în sensul că i se comunică destul de puţine lucruri sau chiar deloc, despre problema pe care urmează să o rezolve, accentul căzând pe ceea ce urmează să facă, în mod efectiv. Sunt, însă, şi abordări care „umanizează” foarte mult calculatorul, privindu-l (aproape) ca pe o fiinţă umană, cu gânduri, sentimente, preferinţe şi abordări proprii. Dintr-o astfel de perspectivă, calculatorului nu i se mai „dau ordine”, ci i se comunică „probleme”, şi el însuşi construieşte/alege o metodă de rezolvare etc. Practic, însă, o asemenea abordare mi se pare forţată. Calculatorul nu este, nu poate să fie „creativ”, în mod „natural”, dar poate deveni astfel dacă i se „impune” acest lucru. În alte cuvinte, tot la programare imperativă ajungem. 

Spuneam, în cele de mai sus că, pentru a rezolva o anumită problemă, algoritmul este determinant, iar limbajul de programare în care decidem să implementăm acel algoritm contează, dar nu chiar aşa mult. 

Îmi propun ca, în continuare, să exemplific modul de funcţionare al algoritmilor, folosind, preponderent, două limbaje extrem de cunoscute, şi anume Java şi HP. 

Java este un limbaj de programare extrem de popular, dezvoltat la inceputul anilor ’90, de către James Gosling şi echipa sa de la Sun Microsystems (între timp compania a fost achiziţionată de Oracle). De la bun început, Java a fost concepută ca un limbaj universal, ceea ce înseamnă că poate fi rulat fără niciun fel de probleme pe tot felul de calculatoare, telefoane mobile, alte dispozitive inteligente etc., cu condiţia ca acestea să aibă instalată un program specific, numit Java Virtual Machine (JVM). Cum, practic, toate sistemele de operare conţin această maşină virtuală, rezultă că un program scris în Java poate fi rulat pe aproape toate maşinile de calcul. 

Java este un limbaj puternic, robust, tipizat, complet orientat pe obiecte şi cu o colecţie impresionantă de biblioteci de metode. Este conceput în trei variante principale („ediţii”), şi anume Standard Edition, care permite crearea de aplicaţii standalone (menite a rula pe un singur calculator), dar şi de appleturi, care sunt programe ce pot fi incorporate în diverse situri web, majoritatea browserelor moderne fiind capabile să opereze cu astfel de programe. Java Enterprise Edition este destinată creării de software industrial, adică de aplicatii distribuite, rulând pe mai multe calculatoare si accesând baze mari de date. În fine, Java Mobile Edition este destinată creării aplicaţiilor menite a rula, îndeosebi, pe dispozitive de tipul telefoanelor mobile etc. Popularul sistem de operare Android, dezvoltat de Google, este scris în Java şi menit să lucreze împreună cu aceasta. 

Şi, poate cel mai important aspect, este open-source, aceasta însemnând că poate fi descărcat oricând de pe internet, în mod gratuit, împreună cu toate bibliotecile sale, cu IDE-ul propriu NetBeans – deşi la fel de bine se poate folosi Eclipse, sau orice altceva. 

Limbajul Java este compilat şi interpretat. Aceasta înseamnă că programele scrise în Java sunt compilate de programul specific javac, din orice distribuţie de JVM, şi transformat în programe aşa-numite bytecode, care sunt independente de maşina de calcul, putând fi, apoi, mai departe, interpretate. Această caracteristică are o oarecare influenţă negativă asupra performanţelor de viteză ale programelor scrise în Java, influenţă pe deplin compensată de alţi factori cum ar fi, de exemplu, portabilitatea. 

Prima variantă a limbajului PHP a fost lansată în 1994 de programatorul suedez Rasmus Lerdorf. Iniţial, a fost vorba de un set de scripturi Perl, create pentru a-şi întreţine pagina personală de web. De aceea şi denumirea a fost, la început „Personal Home Page”. Ulterior, programatorii evrei Zeev Juravski şi Andi Gutmans, au rescris în intregime codul iniţial şi au redenumit limbajul în „Hypertext Preprocessor”, aşa cum este cunoscut până în prezent. Ulterior, cei doi au fondat compania Zend Company, care a dezvoltat următoarele variante ale limbajului. 

Dintru început, PHP a fost conceput ca un limbaj destinat, în special, creării şi dezvoltării de situri web. PHP este, alături de alte limbaje, „responsabil” de apariţia şi dezvoltarea siturilor web dinamice, adică a acelor situri car permit un mare grad de interactivitate cu utilizatorul, aceasta presupunând existenţa unor opţiuni ale utilizatorilor precum înr postarea de conţinuturi înrgistrarea, postarea de conţinuturi, transmiterea de mesaje, in timp real, altor utilizatori etc. Pentru a realiza toate aceste operaţiuni, PHP are nevoie să interacţioneze cu un mediu de gestiune a bazelor de date, aşa cum este, de exemplu MySQL. 

Cuplul PHP & MySQL este folosit pe scară largă la crearea şi întreţinerea unor situri precum Wikipedia, Facebook, Google sau Youtube. 

 Pentru a „vedea” un site web, un utilizator are nevoie, in primul rând, de un program numit browser (ex: Internet Explorer, Google Chrome, Firefox, Opera, Safari, Sea Monkey etc.), care îi permite să identifice şi să manipuleze fişiere aflate pe alte calculatoare, în conformitate cu URL-ul acestora (Uniform Resource Locator), acesta fiind un cod care „descrie” browserului adresa/locul unde se află fişierul respectiv şi cum poate fi el accesat. Pe baza acestor informaţii, browserul încearcă să identifice şi să afişeze conţinutul fişierului precizat. Dacă acel fişier conţine doar text sau cod nativ HTML, atunci el este recunoscut şi afişat ca atare de browser, altfel el trebuie interpretat în prealabil, iar de acest lucru este responsabil un program special numit server, care trebuie să existe în calculatorul apelat. Sunt mai multe tipuri de servere, dintre care cel mai popular este Apache, dezvoltat de o comunitate deschisă de programatori sub emblema Apache Software Foundation.

Apache, MysQL şi PHP sunt programe open-source, ceea ce înseamnă că, pentru a le descărca şi utiliza nu trebuie plătit niciun ban! De aceea, cele mai populare medii pentru crearea / dezvoltarea / întreţinerea siturilor web sunt LAMP, WAMP sau/şi MAMP (unde prima literă înseamnă Linux, Windows sau MacOS, A corespunde serverului Apache, M vine de al MySQL, iar P de la PHP – dar poate însemna, la fel de bine, şi Python sau Perl). 

PHP nu a fost conceput, de la bun început, ca un limbaj de programare universal, şi nici ca un limbaj orientat pe obiecte, dar a dobândit, intre timp, aceste caracteristici. Oricum, în PHP este posibilă atât abordarea stilului de programare structurat, cât şi a celui orientat pe obiecte. PHP este un limbaj interpretat, ceea ce permite o mare versatilitate a tipurilor de date. 

În cele ce urmează, îmi propun să prezint o serie de rezultate legate de proiectarea algoritmilor, urmând ca implementările corespunzătoare să fie efectuate, aproape in totalitate, intr-unul din cele două limbaje de mai sus, Java şi PHP.

Niciun comentariu:

Trimiteți un comentariu