[ Blue82 @ 25.04.2011. 15:57 ] @
Imam jedan program koji je rastao i rastao i trenutno porastao toliko da vise ne mogu da uradim ni osrednju izmenu u njemu jer ne znam ni gde sta da trazim, ni sta ce ta izmena povuci sa sobom.

Moze pomoc, pretpostavljam da postoje programi u kojima se iscrtava nekakva struktura programa ili tome slicno, kako bi se i buduci narastaji snalazili u njemu? Sta bi ste mi preporucili za tu problematiku?
[ vuchko.vuchko @ 25.04.2011. 21:14 ] @
Možda neke Data Flow alate.....
[ Marko_L @ 26.04.2011. 02:28 ] @
Ne treba ti nikakvo crtanje strukture programa, niti nekakvi workflow chartovi. To je gubljenje vremena. To eventualno odradiš pre pisanja koda kako bi imao referencu po kojoj ćeš da radiš, ali ti neće kasnije olakšati razumevanje koda. Da bi imao kod koji je čitak i tebi, a posebno drugima, potrebno je ispratiti određena pravila prilikom pisanja koda, a posebno sledeća 3:

1. Pravilna nomenklatura (ovo važi i za promenljive i za kontrole i za funkcije i za procedure i za sve ostalo čemu možemo dodeliti sopstveni naziv)
2. Komentarisanje koda
3. Dobro struktuiran i uredan kod

I da malo pobliže objasnimo sva tri pravila.

Što se tiče nomenklature, postoje neki standardi koje bi valjalo ispratiti, recimo ovo. Naravno, to ne znači da moramo da se držimo tih pravila kao pijan plota, već možemo na osnovu toga napraviti i neki sopstveni model, ali bitno je imati taj neki model i ostati mu dosledan. Ako tako uradimo, za svaku varijablu i svaku proceduru ili funkciju ćemo na prvi pogled znati makar približno čemu služi. Šta to u praksi znači. Pa, recimo da sam viđao da programeri ostavljaju default imena kontrolama, pa tako imaju dugmiće koji se zovu Command1, Command2, Command3, Command4, itd., a svako od njih ima neku svoju funkciju. Ovo naravno nije dobro, jer kada gledaš kod ti apsolutno nemaš pojma koje dugme čemu služi, pogotovo ako prođe neko vreme od kada si poslednji put gledao taj kod. Mnogo je bolje dugmiće nazvati nekim opisnim imenom koje će nam ukazati na to čemu to dugme služi. Recimo da imamo dugme koje služi za izlaz iz programa. Umesto Command1, nazvaćemo ga jednostavno cmdExit ili cmdIzlaz (zavisno od toga da li odaberemo englesku ili srpsku nomenklaturu, a i jedno i drugo je ok, sve dok razumemo o čemu se tu radi).

Isto važi i za promenljive. Mnogo puta sam video da programeri promenljive iz nekog razloga krste sa jednim ili dva slova. To je možda ok kada se radi o nekoj promenljivoj koja je privremenog karaktera i služi isključivo za prolazak kroz petlju recimo, ali kada se radi o nekoj promenljivoj koja se koristi na više mesta u proceduri ili još gore, ako se radi o nekoj globalnoj promenljivoj, onda je smrt nazvati je jednim slovom. Zamisli recimo da imaš neku promenljivu čija vrednost treba stalno da se menja tokom korišćenja aplikacije. I šta si uradio ako promenljivu nazoveš jednostavno a ili ab ? Napravio si sebi problem, jer kada se posle nekog vremena vratiš aplikaciji ili kreneš da je proširuješ dodajući nove varijable tipa b, c, d, cd, ad, itd., ti više nećeš uopšte znati čemu koja služi, a pogotovo ona prva. Moći ćeš da nagađaš, ali dok ne prođeš ceo kod i analiziraš svaki deo gde se ta varijabla pojavljuje, nećeš biti siguran u to. E, zato lepo nazoveš promenljivu nešto poput g_iBrojVozila (recimo da ta varijabla treba da sadrži trenutni broj vozila na nekom parkingu) ili g_intBrojVozila i sam taj naziv će ti reći da se radi o globalnoj varijabli (prefix G) koja je integer tipa (prefix i ili int) i da se radi o nekakvom broju vozila, a pošto se radi o aplikaciji koja prati broj vozila na parkingu, znaćeš i kom se broju vozila radi. Naravno, možeš to da uradiš i na drugi način, recimo ja imam običaj, tako sam navikao, da ne stavljam prefix g na početku, već da globalne i lokalne promenljive razlikujem korišćenjem različitih prefixa za tip. Recimo za globalne koristim troslovni prefix a za lokalne jednoslovni, pa bi tako kod mene globalna varijabla za broj vozila glasila intBrojVozila, a lokalna iBrojVozila. Istom logikom, da je neka varijabla tipa string, globalna bi bila strNekiTekst, a lokalna sNekiTekst. Naravno, ti možeš da osmisliš neki tvoj sistem, ali bitno je da on bude logičan i da ti na prvi pogled da sliku o čemu se radi, odnosno da li je u pitanju globalna ili lokalna promenljiva, koji je tip podataka, kao i opis šta ta promenljiva zapravo sadrži.

Sve to takođe važi i za funkcije i procedure. Nažalost, i ovde sam vrlo često viđao da programeri koriste nekakve generičke nazive tipa MyFunction1, MyFunction2 ili MyCalculation i slično. To naravno ne valja, jer se posle nekog vremena totalno zaboravi šta koja od tih funkcija radi i šta treba da vrati. Ali, ako upotrebimo neki opisni naziv za funkciju, recimo CalculateTotalPrice ili GetDateFromString i slično, opet na prvi pogled imamo koliko toliko jasnu sliku šta ta funkcija treba da nam vrati i gde se ona koristi.

Naravno, sve to važi i za bilo koju drugu stvar kojoj možemo dodeliti ime, module, klase, objekte...

Sledeće pravilo jeste komentarisati kod, često i što detaljije je moguće. To naravno ne znači da treba komentarisati svaku liniju koda, naprotiv, staviti ovakav komentar bi bilo glupo i suvišno
Code:
Dim a As Integer 'deklarisi integer promenljivu a
Dim i As Integer 'deklarisi integer promenljivu i
a = 10 'dodeli promenljivoj a vrednost 10
For i = 1 to a 'prodji kroz petlju onoliko puta koliko je vrednost a
   Print "A" 'ispisi slovo A
Next i 'predji na sledecu iteraciju

ali recimo, ovako nešto bi bilo sasvim ok i vrlo korisno
Code:
Dim a As Integer
Dim i As Integer
a = 10

'sledeca petlja ispisuje slovo A onoliko puta kolika je vrednost promenljive A. Svrha te petlje je to i to
For i = 1 to a 'prodji kroz petlju onoliko puta koliko je vrednost a
   Print "A" 'ispisi slovo A
Next i


Takođe, blok komentare treba stavljati na početku svake procedure i funkcije i taj komentar treba da sadrži:
-ime autora procedure i funkcije - ovo služi da ako neko drugi nekada bude radio na kodu, zna ko je tu proceduru pisao i kome treba da se obrati ako mu treba pomoć oko razumevanja ili modifikacije te procedure ili funkcije
-datum kreiranja ili modifikacije - ovo je važno zato što se često dešava da neku funkciju koju smo napisali želimo da koristimo u više aplikacija, a još češće da tu funkciju moramo malo da poboljšamo ili proširimo za potrebe nove aplikacije. I onda tako tu funkciju iskoristimo u tri, četiri, pet različitih aplikacija, a svaki put je malo modifikujemo, pa se onda još desi da treba neku stariju aplikaciju koja već sadrži tu funkciju malo da unapredimo, za šta nam treba modifikovana verzija te funkcije, pa je iskopiramo iz neke novije aplikacije i sve tako... i šta se onda dešava kada se sledeći put javi potreba za korišćenjem te iste funkcije ? Pa dešava se to da više nemamo pojma koja verzija funkcije je najnovija i u kojoj se aplikaciji nalazi baš ta verzija. Ako imamo datum, on nam odmah kaže koja je najnovija.
-opis funkcije ili procedure - dakle, kao što samo ime kaže, kratak opis šta ta funkcija ili procedura radi, kao i koju vrednost u kom slučaju treba da vrati (ukoliko se radi o funkciji naravno)
-parametri - spisak parametara koje funkcija ili procedura prihvata, ako ih ima, i naravno kratak opis čemu koji parametar služi

Ovo je recimo sasvim dovoljno, jer ne treba preterivati ni sa komentarima, jer oni itekako mogu da nepovoljno utiču na čitkost koda, pogotovo ako ih ima previše i ako su razbacani unaokolo. Naravno, ukoliko je nekome potreban još neki podatak, slobodan je upisati ga.

I konačno, dolazimo i do pravilnog struktuiranja koda, kao i urednost u pisanju istog. Kao i kod nomenklature i ovde postoje neki standardi koje valja ispoštovati, mada se ni toga ne moramo držati kao pijani plota, ali ono što je univerzalno dobra praksa jeste sledeće:

-identovati kod (ne znam domaću reč za ovo), ali se generalno radi o uvlačenju redaca. Na primer, ovo
Code:
If A = 10 Then
   For I = 1 To 5
      Print "S"
   Next I
End If

je mnogo čitkije nego ovo
Code:
If A = 10 Then
For I = 1 To 5
Print "S"
Next I
End If

-razdvajati logičke celine, recimo praznim redom, pa makar one bile i u istoj proceduri. Recimo, ovo
Code:
Dim a As Integer
Dim i As Integer

a = 10

For i = 1 To A
   Print "A"
Next A

MsgBox "Ispis zavrsen", vbInformation, "Info"

nego ovo
Code:
Dim a As Integer
Dim i As Integer
a = 10
For i = 1 To A
   Print "A"
Next A
MsgBox "Ispis zavrsen", vbInformation, "Info"

-ukoliko se neki delovi koda često ponavljaju u istom ili blago izmenjenom obliku, treba ih pretvoriti u funkciju ili proceduru (zavisno od toga da li treba da vrati neku vrednost ili ne), a ako se poziva sa više formi, onda je i ubaciti u modul kao Public. Na taj način, umesto kopiranja koda iznova i iznova, samo pozivamo jednu funkciju. To ne samo da je čitkije, već nam omogućava da je menjamo na jednom mesto, umesto da idemo kroz ceo kod i radimo istu promenu 10 ili više puta, uz rizik da negde nešto propustimo. Primer, ako imamo ovako nešto
Code:
Private Sub Command1_Click()
Dim a As Integer
Dim i As integer

a = 10

For i = 1 to a
   Print "A"
Next i
End Sub

Private Sub Command2_Click()
Dim b As Integer
Dim i As integer

b = 15

For i = 1 to b
   Print "B"
Next i
End Sub

Private Sub Command3_Click()
Dim c As Integer
Dim i As integer

c = 20

For i = 1 to c
   Print "C"
Next i
End Sub

To je prilično nepregledno, a da ne pričamo o tome šta se dešava ako hoćemo da promenimo nešto u petlji, recimo da pored slova upisuje i još nešto pride. Morali bismo 3 puta da radimo istu ispravku. zato lepo napravimo proceduru, pa bi kod izgledao ovako
Code:
Private Sub Command1_Click()
Call Ispisi(10, "A")
End Sub

Private Sub Command2_Click()
Call Ispisi(15, "B")
End Sub

Private Sub Command3_Click()
Call Ispisi(20, "C")
End Sub

Private Sub Ispisi(iBroj As Integer, sSlovo As String)
Dim i As Integer

For i = 1 to iBroj
   Print sSlovo
Next i
End Sub

i sad ako hoćemo da recimo pored tog slova stoji broj 1 u zagradi, sve što treba da uradimo je da promenimo proceduru Ispisi
Code:
Private Sub Ispisi(iBroj As Integer, sSlovo As String)
Dim i As Integer

For i = 1 to iBroj
   Print sSlovo & " (1)"
Next i
End Sub


-lepo formatirati komentare. Recimo ovo
Code:
Private Sub Ispisi(iBroj As Integer, sSlovo As String)

'=========================================================
' Autor: Marko Losonc                                   
' Datum: 26.04.2011                                      
' Opis: ova procedura ispisuje odredjeno slovo    
'         odredjen broj puta zavisno od                
'         prosledjenih parametara
'=========================================================
' Parametri:
'    iBroj - odredjuje koliko ce se puta ispisati
'             odredjeno slovo
'    sSlovo - odredjuje koje slovo ce se ispisivati
'=========================================================

Dim i As Integer

'--------------------------------------------------------------------------
' ova petlja ispisuje odabrano slovo(sSlovo), odabran broj puta (iBroj)
'--------------------------------------------------------------------------
For i = 1 to iBroj
   Print sSlovo & " (1)"
Next i
End Sub

je dosta preglednije nego
Code:
Private Sub Ispisi(iBroj As Integer, sSlovo As String)

'Autor: Marko Losonc                                   
'Datum: 26.04.2011                                      
'Opis: ova procedura ispisuje odredjeno slovo odredjen broj puta zavisno od prosledjenih parametara
'Parametri:
'iBroj - odredjuje koliko ce se puta ispisati
'odredjeno slovo
'sSlovo - odredjuje koje slovo ce se ispisivati

Dim i As Integer
'ova petlja ispisuje odabrano slovo(sSlovo), odabran broj puta (iBroj)
For i = 1 to iBroj
   Print sSlovo & " (1)"
Next i
End Sub


Ima tu još nekih stvari, ali već sam se dovoljno raspisao. No, i ovo napisano je sasvim dovoljno da se ubuduće kod piše kako treba i da svako sa njim može da se snađe, bez obzira da li ga unapređuješ svakodnnevno ili mu se vraćaš posle više meseci. Što se tiče tog koda koji već imaš, nema ti druge nego da kreneš kroz kod, deo po deo, provaljuješ šta koji deo radi i počneš da primenjuješ neke od ovih stvari, za početak iskomentariši delove koda, a posle možeš da probaš i drugačije imenovanje, kao i bolje struktuiranje koda.
[ MasterOfDisaster @ 26.04.2011. 10:04 ] @
Moram da priznam pridrzavam se 90% ovih pravila i skoro sam radio update neke aplikacije posle duzeg vremena i nisam imao tolikih problema oko ne razumevanja
i udaranja glave "sta li ovo bese".

Takodje jedna koristna stvar je da neki skup funkcija koje su na neki nacin povezane stavis u jedan modul i nazoves ga karakteristicno za njihovu ulogu i samim
tim podelis program na vece celine i onda znas sta mozes da ocekujes od tog modula i obavezno komentare iznad pocetak f-je i tokom programa naravno.

Nesto imam utisak da ne pomazemo mnogo coveku ovom pridikom :P

Pozdrav
[ Marko_L @ 26.04.2011. 10:21 ] @
Pa možda mu ne pomažemo trenutno, ali mu sigurno pomažemo za ubuduće, jer jedina stvar koja je gora od aplikacije u kojoj ne možeš da se snađeš jeste dve aplikacije u kojima ne možeš da se snađeš :) A i nikad nije kasno da se neka od ovih pravila primene, čak i ako je aplikacija već poluzavršena ili skroz završena. Istina, lakše je to raditi u toku pisanja koda, ali šta sad. Meni se recimo dešavalo da zbog brzine jednostavno nemam vremena da pišem komentare, pa onda to uradim naknadno, dok je sveže. Najgore je u stvari kad se posle više meseci vratiš nekoj aplikaciji, a ništa nisi iskomentarisao, niti si vodio računa o nomenklaturi, pogotovo što si u međuvremenu verovatno dosta toga novog naučio i neke stvari rešavaš skroz drugačije nego što si ranije to radio, pa onda kad naletiš na neki stariji svoj kod, prosto se zapitaš "Ma jesam li ja ovo pisao ? I zašto ?" :)
[ Shadowed @ 26.04.2011. 10:36 ] @
Citat:
Marko_L: pa onda kad naletiš na neki stariji svoj kod, prosto se zapitaš "Ma jesam li ja ovo pisao ? I zašto ?"


To je povod za one komentare tipa "dear future me,..."


@Blue82, kreni ti to lepo da radis od pocetka i pridrzavaj se ovog sto je Marko napisao. Usput imas priliku da na poznatoj aplikaciji predjes na novije tehnologije tipa .NET (pre ili kasnije ces verovatno svakako preci).
[ Blue82 @ 26.04.2011. 11:46 ] @
hehe e baš ste me slatko nasmejali, i baš mi je prijalo u ovoj muci :)

To stvarno lepo izgleda, ali stvarno ne znam koliko vam treba da sve tako skockate. Kada krenem nešto da radim pa mi dođe nadahnuće često ne stignem da upišem ni majosnovniji komentar pa kada sve proradi onda se vraćam unazad i tutnem po neki tu i tamo. Ovako deluje mi da više pišete komentare od samog programa :) Mislim znam, sve je to korisno i praksa je to isterala da se radi u tom obliku.

Posebno mi se dopada onaj deo sa Šta je gore od aplikacije u kojoj ne možeš da se snađeš... pa ću pokušati da se pridržavam toga.
Jbg, nisam skolovan programer i jedno vreme dok se time baviš više manje sve držiš u glavi a onda ubaci ovo, ubaci ono, dodaj ovako, izbaci onako i na kraju imaš fijasko. Trebalo mi je juče pola sata samo da shvatim redosled operacija i šta u kom formatu gde šalje i šta čeka na prijemu. Preznojao sam se a još nisam ni počeo da prepravljam šta sam hteo. Zaista mučno. Pogotovo kad se uzme u obzir da u poslednje vreme retko programiram, ne stižem nikako i onda kad uhvatim malo slobodnog vremena i naoružam se strpljenjem ovo me izbaci iz takta.

Ok, a znate li neki free programčić za crtanje algoritma, možda nekada dobro dođe?
[ goranvuc @ 26.04.2011. 14:11 ] @
Nešto ti meni puno pominješ algoritme i sl. - da nisi malo preterao sa korišćenjem GOTO?

Ako nisi, onda bi ti verovatno pomoglo da odredjene blokove koda koji pretstavljaju celinu a nalaze ti se u velikim procedurama prebaciš u posebne procedure, uz naravno poštovanje svih prethodno navedenih pravila.
[ Blue82 @ 26.04.2011. 18:02 ] @
Ma ja sam to krpio s brda s dola, pocelo je kao zaebancija, pa se dodavalo malo ovoga, pa malo onoga i tako je to raslo i raslo a pravljeno bez mnogo planiranja vec onako stihijski. Sam program ima oko 15MB sto je meni jako mnogo kao uslovno receno noobu u toj oblasti. I sada kada hocu nesto da ubacim to mi zaista zadaje glavobolju a kroz program se provuklo oko 5.000 korisnika i sad moram da vucem dalje.

Moja greska je sto tako kad mi nesto padne na pamet ja sklepam na brzinu ne bi li to radilo pa semnogo stvari nalazi na mestima gde ih ni sam kasnije ne bih ocekivao. Sve je postalo preobimno i moram nekako da ga sredim da shvatim celinu jer trenutno sam u fazi da nemam pojma sta ce se desiti ako izbacim ovaj segment programa dok ga ne pogledam veoma detaljno a ne retko moram sebi na papiirce da nacrtam ceo proces i sta se u kom slucaju desava a to mi je postalo prezamorno. Tako bih makar mogao da pojednostavim stvari tako sto cu jednom sebi graficki napisati gde mi se sta nalazi da ne radim to 1000 puta dok sve ne sredim kako treba.

U sustini poprilicno mi je zamorno kad idem kroz program pa kaze u nekom sub-u call Ime procedure, pa call ime funkcije,pa call ProveriOvo pa call VidiOno i dok ja tako skacem sa jedneg suba na drugi, sa drugog na treci zaboravim sta sam uopste i hteo, i ne mogu da sagledam celinu. Ovako ako napisem proverava ovo, pa otkljucava ovo, pa ako je ovo radi to onda bacim pogled na sliku i sve mi je jasno umesto sto to trazim po kilometarskom kodu.
[ mkaras @ 27.04.2011. 17:07 ] @
Možda mogu da pomognu : Visustin v6 Flow chart generator i Code Visual
to Flow chart 6.0. Solidno odrađuju posao ali, na žalost, moraju da se plate