Zašto je važno izbegavati dupliranje u programiranju?

Proces održavanja aplikacije ne počinje onda kada je lansiramo — održavanje i reorganizacija sistema treba da budu stalan proces i sastavni deo programerskog pristupa.

Dubravka Vilotić - 27. Avgust, 2018.

Nastavljamo serijal članaka baziranih na i inspirisanih klasičnim naslovom Pragmatični programer, koji smo započeli tekstom o procenjivanju rokova.

Prenosićemo glavne teme iz ove knjige (za koju vas svakako ohrabrujemo da je pročitate u celosti), uz primere iz prakse, bilo kao dopune glavnim temama ili kao zasebne članke. Pošaljite nam svoje kritike ili predloge za primere iz prakse ovde.

Jasno je da je posao programera u velikoj meri skupljanje, organizacija, implementacija i održavanje znanja. Dokumentujemo znanje u specifikacijama, oživljavamo ga kroz kod i koristimo ga za provere u procesu testiranja. Međutim, znanje je promenljiva kategorija — menjaju se znanja pojedinaca, menja se kod, menjaju se pravne regulative, a menjaju se i zahtevi klijenata. To je svakom programeru vrlo logično, ali ta promenljivost može da se pretvori u problem kada govorimo o održavanju sistema.

Većina ljudi misli da proces održavanja počinje tek kada je aplikacija na kojoj radimo izbačena i da podrazumeva popravljanje bagova i doterivanje različitih funkcionalnosti. Međutim takvo shvatanje održavanja sistema je pogrešno.

Kako se naša znanja maltene svakodnevno menjaju, održavanje i reorganizaciju sistema ne treba raditi tek kada je aplikacija na kojoj radimo gotova, već ono treba da bude stalan proces i sastavni deo celokupnog programiranja.

Jedan od problema leži u tome što znanje sadržano u specifikacijama, procesima i programima vrlo lako postaje duplirano, čime proces održavanja sistema postaje posebno mučan i zahtevan. Zamislite to kao traženje igle u plastu sena, ali igala je više (ne znate koliko) i treba da ih pronađete sve. Da bi se ta noćna mora izbegla izuzetno je važno voditi se DRY principom — Don’t repeat yourself!

Suština DRY principa leži u ovome: Svaki deo znanja mora da ima pojedinačan, nedvosmislen i autoritativan prikaz unutar sistema.

Alternativa tome bi bila da ista stvar bude prikazana na dva ili više mesta. Ako je promenite na jednom, morate da se setite da je promenite i na svim ostalim mestima, u suprotnom vrlo lako može onesposobiti vaš program.

Primer iz prakse

Radili smo na funkcionalnosti kreiranja CSV fajla za štampanje nalepnica za klijenta. Kreiranje CSV fajla je podešena kroz kompleksnu metodu. CSV je uređen samo za određeni tip štampača koji je klijent u tom trenutku koristio.

Nakon određenog vremena, klijent je krenuo sa prodajom drugih vrsta nalepnica koristeći druge štampače. Kako je potreban različit CSV fajl za svaki štampač, metoda je kopirana umesto da je dorađena.

Umesto da joj je umanjena kompleksnost, posledica je bila kompleksan i nepredvidiv rast baze koda koji nije pregledan i iz kog nije bilo očigledno koji deo je neophodno promeniti da bi se izmenio određeni deo CSV fajla.

Logično, došlo je do refaktorisanja, tako da je sada kod podeljen na manje metode koje imaju jasno definisane funkcije koje su čitke i jasne same po sebi.

Ozren SrdićStuntCoders

Različiti načini dupliranja

Dupliranje je relativno česta pojava u developmentu (često uopšte nema veze sa samim kodiranjem), a većina dupliranja koje se dešava se uglavnom može svrstati u neku od sledećih kategorija:

Nametnuto dupliranje

Uprkos tome, često postoji način da i u ovakvim situacijama ispoštujemo DRY princip, korišćenjem ovih nekoliko tehnika.

Višestruki prikaz informacija

Do višestrukog prikaza informacija može doći kada pri kodiranju treba istu informaciju predstaviti u nekoliko različitih formi. Na primer ako pravimo klijent-server aplikaciju u kojoj koristimo različite programske jezike na klijentu i serveru, ali je potrebno da predstavimo neke zajedničke strukture u obe klase.

Često je rešenje napisati jednostavan filter ili generator koda. Strukture u više različitih jezika mogu biti kreirane zajedničkom metadata šemom koristeći prost generator koda svaki put kada se softver formira. Definicije klase mogu da se generišu automatski iz online šeme baze podataka ili iz metadata-e koja se koristi za prvobitno formiranje šeme. Trik je u tome što ovaj proces moramo učiniti aktivnim: to ne može biti jednokratna konverzija, inače smo opet u situaciji u kojoj dupliramo podatke.

Dokumentacija u kodu

Dokumentacija u okviru koda može predstavljati problem jer su programeri često samo naučeni da moraju pisati komentare uz kod, a ne zbog čega i kada treba da ih pišu. Da bi se ispoštovao DRY princip potrebno je komentare pisati uz zahtevne delove koda koje je teško razumeti, a one jednostavne ostaviti bez komentara. U suprotnom ćemo duplirati znanje i svaka promena će podrazumevati da menjamo i kod i komentare. Komentari će u nekom trenutku početi da zaostaju, a nepouzdani komentari su lošiji od koda bez komentara.

Dokumentacija i kod

Problem koji se često javlja jeste da se dokumentacija ne poklapa sa kodom. Pred krajnji rok predaje projekta kod se ubrzano menja, a dokumentacija biva zapostavljena i onda zaostaje za kodom. Kada je potrebno da program prođe sve testove problem može rešiti to da se prvo menjaju specifikacije i onda uvek na osnovu specifikacije piše kod. Time se garantuje da dokumentacija nikad neće zaostajati.

Primer iz knjige “Pragmatični programer” prenosimo integralno:

Dejv je radio na međunarodnoj teleks centrali. Klijent je sasvim logično zahtevao iscrpnu specifikaciju testova i tražio da njihov softver prođe sve testove pri svakoj isporuci. Da bi osigurali da testovi precizno predstavljaju specifikaciju, tim ih je generisao automatski iz samog dokumenta.

Kada bi klijent promenio specifikaciju, njihov program bi testove menjao automatski. Nakon što je tim uverio kijenta da je procedura valjana, za generisanje prihvatajućih testova bi obično bilo potrebno samo par sekundi.

Izazovi sa programskim jezikom

Mnogi jezici nameću dupliranje u izvornom kodu. To se najčešće dešava kada programski jezik odvaja interfejs modula od njegove implementacije. Ne postoji lak način da se ovaj izazov prevaziđe, jer smo generalno zaglavljeni sa onim što nam je dato.

Nenamerno dupliranje

Nekada dupliranje nastaje kao rezultat propusta koji su napravljeni u samom dizajnu. Ako pogledamo primer kompanije koja se bavi prevozom dobara, možemo imati kamion koji kao svoje atribute poseduje tip, registarski broj i vozača. Slično, kada za taj kamion sastavljamo rutu kojom će ići, ona kao atribute ima putanju, kamion i vozača. Zamislimo da nam se određeni vozač javi i kaže da je bolestan. Da li menjamo onda atribut vozača kod objekta kamiona ili objekta rute? Tu već uviđamo da nam je nešto u kodu loše. Sada moramo razmisliti da li kamion baš mora kao deo sebe imati atribut vozača. A ruta? Ili je možda najbolje imati još jedan objekat koji povezuje ova dva time što imaju zajedničko. Za šta god da se na kraju odlučimo, najbitnije je po svaku cenu izbeći prvobitno rešenje.

Možda ćete se kasnije u razvojom procesu odlučiti da prekršite DRY princip u korist performansa. U takvoj situaciji je bitno da lokalizujete uticaj te odluke.

Nestrpljivo dupliranje

Nestrpljivo dupliranje najčešće nastaje kada programer pokušava u žurbi da završi deo projekta i pribegne prečicama koje mu se u tom trenutku učine kao pravo rešenje, ali mu se vremenom obiju o glavu. Nestrpljivo dupliranje možete izbeći ako naučite sebe da budete otporni na vremenske pritiske jer je često krajnji rezultat zbrzavanja gubljenje vremena na kasnije ispravke. Kada padnete u iskušenje da “skratite krivinu” setite se aforizma: prečice su uzrok velikih kašnjenja.

Ovakav tip dupliranja se lako primećuje i ispravlja, ali je jedino rešenje disciplinovati se i žrtvovati više vremena pri prvom pisanju koda kako bi sebe poštedeo kasnijeg nerviranja.

Interdevelopersko dupliranje

Četvrto (interdevelopersko) dupliranje je tip dupliranja koji je najteže primetiti, ali i rešiti jer se takođe dešava nenamerno ali od strane više developera na istom projektu. Opšta preporuka za sprečavanje ovakvih situacija je postojanje jasnog dizajna, jasnih zaduženja i stabilnog tehničkog vođe projekta.

Praktičnije rešenje je česta komunikacija između developera. Odredite jednog člana tima čije bi zaduženje bilo olakšavanje razmene znanja. Još jedan savet je da jedni drugima pregledate kod. Nemojte gledati na to kao da im brljate po kodu – vi učite od njih. Takođe ne zaboravite da je pristup recipročan – nemojte zazirati od toga da i drugi gledaju vaš kod.

Savet: Učinite stvari jednostavnim za ponovno korišćenje. Ono što treba da uradite jeste da negujete sredinu u kojoj je lakše pronaći i ponovo iskoristiti već postojeće stvari nego pisati ih ispočetka. Ako nije jednostavno, ljudi to neće raditi. A ako ne uspete da stvari učinite ponovo iskoristivim, rizikujete da duplirate znanje.

Primer iz prakse

Kako u programiranju, tako i u drugim oblastima ljudskog poslovnog delanja, repeticija se nekad čini neizbežnom. Moj ulazak u upravljačke odnosno menadžerske vode obilovao je aktivnostima koje su se ponavljale iz nedelje u nedelju.

Naročito bolno je bilo kreiranje izveštaja o progresu timova, koje je zahtevalo prikupljanje i obradu informacija sa različitih izvora (issue tracker-a, version control sistema, nekoliko Excel sheet-ova…).

I kao što dobar savet programeru kaže da napiše generator repetitivnog koda, tako sam ja posao pravljenja nedeljnog deck-a prepustio generatoru PowerPoint prezentacije.

Trebalo mi je nešto vremena da nadjem tačno odakle koju informaciju programski kupim, i potom da to uobličim u objekte koje ppt razume, ali je kreiranje i održavanje prezentacije postalo pesma, a ništa manje i trijumf nad birokratijom.

PS — Valjalo bi imati na umu da je opisano jedna ilustracija automatizacije problema, ne i preporuka za to kako treba meriti rezultate tima.

Ivan Aksentijević, CTO Vibe Network

Rubrika pragmatično programiranje je pod pokroviteljstvom StuntCodersa →