Am auzit prima data de Share Cluj când încă era în stadiul de idee, când echipa încă lucra să clarifice scopul proiectului, se gândea cum să implice mai multă lume și cum să pună Clujul pe harta lumii. Inițial, rolul meu în proiect era de a fi un ambasador al Clujului, însă participând la o ședință de proiect și având pe masa de discuție partea tehnică a proiectului, am devenit imediat un membru al echipei.
Latura tehnică consta în a construi o platformă care să poată susține concursul din cadrul proiectului: orice persoană din Cluj și nu numai să promoveze Clujul în călătoriile sale, fie ele concedii sau delegații, împărtășind poveștile lor despre Cluj cu toți cei care încă nu au auzit de Cluj, și apoi să încarce pe rețelele sociale "dovada": o fotografie a mesajul "#sharecluj" în fiecare locație. Provocarea tehnică pe care am văzut-o eu a fost agregarea pe baza hashtag-ului "#sharecluj" (dorit în mesajul post-ului) a feed-urilor de pe Facebook, Twitter, Instagram și prezentarea lor pe site-ul proiectului www.sharecluj.com.
Nu am fost atât de încântată când am descoperit că există platforme/site-uri care pot face acea agregare, însă tot aveam ocazia să le studiez și să aleg opțiunea cea mai bună pentru nevoile proiectului: să expună un API ce să conțină feed-ul cu pozele concurenților de pe rețelele sociale. Am analizat ce oferă Rignite, Hashtagr, TINT, TagBord. Nici una dintre acestea nu expunea API-ul pe care mi-l doream, însă fiind servicii plătite, am presupus că se poate discuta cu cei care întrețin platformele și se poate găsi o soluție pentru a reuși o integrare cât mai rapidă și o lansare a proiectului cât mai curând posibil.
Era deja luna iunie, iar noi ne doream ca până în iulie să dăm drumul la concurs. În așteptarea răspunsurilor de la Rignite și TINT, am început să fac teste pentru anumite hashtag-uri pe care le tot vedeam în feed-ul personal de Facebook. Lucrurile nu erau prea roz, nu prea găseam nimic din ce mă așteptam, nici nu se punea problema de a găsi tot - cum ai putea ține un concurs dacă unii concurenți sunt înscriși și alții nu? Așadar, pe lângă integrarea încă sub semnul întrebării cu site-ul sharecluj.com, o altă situație mult mai dificilă se întrezărea: nu puteam folosi nici unul dintre serviciile existente. Deci trebuia să facem totul de la zero!
Când termenul propus era din ce în ce mai aproape, iar partea tehnică nu era nici pe-departe rezolvată, vă puteți imagina că nu eram prea fericită și nici prea încrezătoare că aș putea să termin tot singură în așa scurt timp. Supărată cum eram, am mers la serviciu și, cu jumătate de gură, mi-am întrebat colegii - pe Călin, Dan și Răzvan - dacă vor să facă voluntariat tehnic. Nu știu dacă starea mea de spirit i-a convins sau dacă și ei au văzut aceeași provocare pe care am văzut-o eu inițial, dar cert e faptul că doar în 10 minute ne-am stabilit o întâlnire la Dan, pe seară, la un pahar de vin, să ne facem un plan cum implementăm sharecluj.com. Până seară, ne-am făcut rost și de specificații funcționale de la Alina, care din manager de proiect s-a transformat instant în product owner.
Chiar dacă tentația e mare să experimentezi cu tehnologii noi când ai pe mână un proiect green field, ne-am decis rapid să folosim ca tehnologie de bază Java și framework-uri cunoscute: Spring MVC, JDO. Costul proiectului trebuia să fie cât mai mic posibil, deci nu se putea pune problema închirierii unui server, așa că am ales ceva ce nu am mai folosit până atunci: Google AppEngine cu o quota suficient de mare pentru stocare de date, operațiuni pe baza de date, ore de instanță, indecși, deploy-uri, etc. . AppEngine s-a dovedit a fi cel mai potrivit pentru proiect. Integrarea cu rețelele sociale urma să fie făcută folosind API-ul expus de fiecare prin scrierea de clienți care să aducă metadata post-urilor și să o stocheze în baza de date.
Pentru a ne asigura că vom reuși să terminăm tot ceea ce product owner-ul, Alina, ne-a cerut, am împins termenul limită către începutul lui august. Implementarea fiecărui punct s-a făcut prioritizat, în funcție de riscul pe care credeam noi că îl poate reprezenta.
Aplicațiile web bazate pe Java și Spring MVC nu reprezintă o noutate pentru echipa nou formată, așa că primul pas a fost investigația GraphAPI-ului oferit de Facebook - Facebook, fiind cea mai folosită rețea socială în România (deci și cea mai relevantă pentru proiect), dar și platforma care era cel mai rar regăsită în rezultatele testelor pe agregatoarele de hasgtag-uri, prezenta cel mai mare risc. De vreme ce exista posibilitatea de căuta din aplicația Facebook după un hashtag, aveam așteptări foarte mari de la GraphAPI ca acesta să-mi ofere exact ceea ce îmi doream: post-urile cu hashtag-ul "#sharecluj". Dar nici vorbă de așa ceva! Am aflat de alternativa de a folosi API-ul de search pentru cuvinte cheie, folosind hashtag-ul; căutarea funcționa după reguli bizare, unele post-uri apăreau printre rezultate, altele nu. Am făcut experimente pe contul personal: am postat mesaje de test conținand "#sharecity" (nu voiam să stric lansarea); am așteptat o zi, o săptămână să îmi apară - nimic; în plus, în scurt timp, API-ul urma să devină obsolete și retras. ( Nu mai este accesibil la momentul de față). În căutările după explicații, am dat peste secțiunea FAQ de la TINT, unde precizau că pentru a avea întregul feed este necesar un workaround și anume ca utilizatorii să posteze pe o pagină de Facebook sau să eticheteze (tag) un utilizator pe conținut. Nu tocmai cea mai "profi" soluție, însă am fost de acord toți că era singura.
O veste bună din zona Facebook a fost că pentru autentificare aveau OAuth2 și că se putea face și offline, dintr-u cron job - așa cum intenționam și noi. Peste GraphAPI s-au scris suficienți clienți Java, dintre care am ales RestFB - ușor de folosit și extensibil.
După experiența cu Facebook, așteptările generale față de orice API au scăzut; însăTwitter avea ceea ce ne doream: un API simplu, bazat pe hashtag. Conform descrierii endpoint-ului, Twitter nu garantează că absolut toate tweet-urile cu un hashtag vor fi returnate, deoarece se face automat o filtrare în funcție de relevanță/popularitate; alternativa oferită este de a ne lega și "asculta" la stream-ul public. În acest caz a apărut o altă dificultate: dacă alegeam stream-ul însemna că am avea nevoie de încă o instanță în AppEngine - ceea ce ar fi întrecut limitele gratuității. Luând în considerare și costul, dar și o eventuală consistență în procedură, am ales să folosim API-ul pentru mentions (un utilizator să fie menționat în tweet). Din fericire, integrarea a fost simplă: am folosit un client Java pentru API-ul Twitter: Twitter4j.
Instagram a fost integrat mai tarziu față de celelalte rețele, iar soluția nu a avut nevoie de nici o concesie. Am fost încântată să observ că au un API per hashtag, nefiltrat, singura limitare fiind la numărul de rezultate - la fiecare apel se returnează cel mai nou conținut și nu se reține starea completă (prin API) a tuturor post-urilor. Pentru Instragram, nu sunt atât de mulți clienți, însă cel ales, jInstagram, a fost suficient. În ceea ce ține de autentificare, și Instagram implementează OAuth2, însă nu se poate folosi și offline (pentru cron job), dar exact API-ul utilizat ( /tags/{tag}/media/recent) se putea folosi doar pe baza unui _clientid.
Mi-a plăcut să fac cunoștință cu întregul ecosistem Java din AppEngine - am putut să folosesc fără probleme toate framework-urile dorite. În primul rând, nu a trebuit să-mi fac griji că acest cod ar putea deveni public înainte să fie ceva cu adevărat valoros - pentru fiecare aplicație există un Git repo, nu se poate clona direct, ci prin SDK-ul corespunzător. Apoi, pentru integrare cu Maven, există atât un plugin pentru management, cât și un arhetip pentru proiecte web. Pentru interacțiunile cu baza de date se poate folosi atât JPA, cât și JDO la fel de ușor (am ales JDO). De asemenea, suportul pentru cron jobs este inclus, având ca premise existența unui serviciu REST pentru execuție și un fișier de configurare. Aplicația web construită cu Spring MVC expune servicii REST atât pentru a culege datele din rețelele sociale, cât și pentru a face datele accesibile pentru interfața web. Toate datele afișate se aduc asincron, prin apeluri de Ajax.
După toate problemele întâmpinate în locuri neașteptate, dar și "ajutorul" din partea tool-urilor bine făcute, am ajuns la următorul design, care a fost lansat pe 4 august, exact la termen.
Imediat după lansare, aproape întreaga echipă de dezvoltare a plecat în concediu. Nimic grav nu s-a întâmplat pentru că aplicația era stabilă,deși nu am avut un tester oficial în echipă. Însă, între timp, Facebook a lovit din nou! Pe măsură ce proiectul devenea tot mai cunoscut și poze cu "#sharecluj" erau upload-ate în diverse forme, descopeream tot mai multe probleme și lacune în API-ul Facebook-ului: unele poze, deși urmau întreaga procedură, nu erau returnate de serviciu. Am declarat în august un defect care abia la sfârșitul lui octombrie a fost rezolvat, dar nu complet, încă sunt concurenți care nu au fost înregistrați pe platformă - drept urmare, am declarat un nou bug.
După trei luni de când proiectul a fost lansat, aplicația este în continuare stabilă. Bineînțeles, ajustări minore au fost făcute pentru a corecta scăpări sau pentru a completa informații. A fost și va continua să fie până în octombrie 2015, o experiență foarte interesantă; nu credeam niciodată că voi ajunge să cunosc într-atât de aproape rețelele sociale sau că voi descoperi defecte la Facebook sau că voi face deploy-uri în producție de pe canapeaua de acasă.
În concluzie, mă bucur că am contribuit la proiectul Share Cluj și că am reușit să punem deja Clujul pe harta lumii în 36 de țări, printre care unele foarte exotice: Senegal, Singapore, Puerto Rico, Australia. Haideți să continuăm să "Share Cluj"!