Kako da razmišljate kao programer? (1.)

border=Za pisanje programskog koda potrebno je da se razmišlja na način koji je većini ljudi stran. Međutim, pisanje koda nije jedinstven proces. To u suštini nije ništa naročito. Ali, ljudi većinom nisu osposobljeni da razmišljaju na način koji je neophodan za dobre programere. To ne znači da oni nisu u stanju da sastave neki softver. Ko god zna gde su prave biblioteke može da skrpi softver kojim se postiže nekakav cilj, bilo to preuzimanje nekakve liste URL-ova, traženje rezultata i njihovo stavljanje u navedenu lokaciju za datoteke, ili možda slanje upita u neku bazu podataka i prikazivanje rezultata na neki određen način.

U jednoj od diskusija na sajtu TechRepublic, “Da li je diferencijalni račun pomogao vašoj IT karijeri” (Has calculus enhanced your IT career?) istaknut je problem sa tim kako ljudi razmišljaju o pisanju softvera. Isuviše često prilikom pisanja softvera propuste da gledaju dalje od trenutnog problema; toliko se usredsrede na drveće da ne vide šumu. Za pisanje koda nije potrebno “razmišljanje izvan okvira”. Potreban je pogled u kojem je okvir džinovski. Previše ljudi prilikom pisanja koda polazi od alata na koje su već navikli i sa kojima se dobro snalaze, pa posmatraju svaki problem iz te perspektive.

Jedan primer za to je prenošenje tabelarnih podataka (kao što su rezultati SQL upita) u nekom rigidnom formatu kakav je XML. Toliko sam često pisao o neefikasnosti XML-a kao formata; on je posebno neefikasan za ovu vrstu transfera podataka. Format ravnog fajla, sa poljima razdvojenim zarezima ili format sa fiksnom dužinom zapisa, bi se pravio, preneo i raščlanio kod klijenta znatno brže nego XML format. Ali programeri su navikli na XML; JavaScript ima ugrađene funkcije za njegovu obradu (engl. handlers), a metodi za rad sa njim su dobro dokumentovani. U stvari, bilo bi potrebno svega nekoliko minuta da se napiše proces za pisanje fajla sa fiksnom dužinom zapisa ili za polja razdvojena zarezima na serverskoj strani i samo još par minuta da se napiše JavaScript koji će prihvatiti taj fajl. Ali, malo je ljudi koji tako rade, zato što je XML format “iz kesice”, komotan je, poznat, a za njegovo korišćenje nije potreban rad. To je primer za izreku: “kada držite čekić, svaki problem vam liči na ekser”.

Decenijama su programeri bili naučnici ili matematičari koji su prešli na pisanje koda. Način razmišljanja potreban za pisanje kvalitetnog koda veoma je blizak načinu na koji fizičari, biolozi, matematičari, itd. prilaze svojim problemima. Ipak je zanimljivo da veliki deo literature u polju računarskih nauka skoro uvek na kraju prelazi u domen filozofije. Svaki razgovor o veštačkoj inteligenciji se u roku od tri sekunde pretvara u filozofsku raspravu; to se ne može izbeći. Neke od najzanimljivijih primena računara u istraživačke svrhe izvode filozofi koji rade na teoriji igara. “Filozofija” prosto znači, “proučavanje nečega što ne može da se kvantifikuje”. Kako određena oblast postaje rigidnije definisana, ona postaje podskup filozofije (kao što je psihologija u vreme Frojda i Junga). Na kraju, neko otkrije način da se oblast kvantifikuje, pa to tada postaje nauka (psihologija nakon Skinera).

Da biste bili ne samo dobar programer, već odličan programer, morate da shvatite kako razmišljaju naučnici i filozofi. To se prosto ne može izbeći. Radio sam za jednu kompaniju gde su programeri većinom imali diplome iz fizike i drugih sličnih grana nauke. Oni su bili izvrsni programeri. Programeri koji su prošli obuku gde su ih učili kako da pišu kôd prosto nisu bili tako dobri. Ta obuka se zasnivala na sintaksi nekoliko konkretnih jezika, učili su kako se obavljaju određeni zadaci. To je programiranje usmereno na kako. Ti programeri prosto nisu shvatali zašto to tako rade. Ono što vas diferencijalni račun (i druga predavanja iz više matematike) nauče nije sama ta matematika. Nauče vas kako da razmišljate o problemima. Taj način razmišljanja je od suštinskog značaja za svakog programera.

border=Možete da postanete “instant” programer pomoću kurseva kao što su DeVry ili Chubb ili Kumar, ili bilo šta. Ali ako ne proširite svoje znanje, teško da ćete moći da postanete više od one vrste programera koji sastavljaju postojeće biblioteke. Teško da ćete moći da radite na projektima višeg nivoa, kao što je veštačka inteligencija, projektovanje kompajlera, jezika, jezgara, upravljačkih programa uređaja i tako dalje. Niko vas neće zaposliti da pišete mašinski kôd ili asemblerski jezik, ili neki drugi kôd nižeg nivoa ako pišete neefikasan kôd, ili ako ne shvatate principe algoritama i tako dalje.

U prvom delu teksta koji je izašao na IT Čitalištu, bilo je reči o tome kako je obrazovanje, pogotovo solidna osnova u matematici, suštinski važno da bi se postalo odličan programer. U ovom, drugom delu teksta, obradićemo neke stvari koje su veoma bitne za lični razvoj svakog programera.

Najkorisnije iskustvo broj jedan u mom procesu učenja je EdScheme. Nikad čuli za to? Zvuči nekako poznato? Pa, možda zvuči poznato zbog reči “Scheme”, jezik iz familije Lisp. Verovatno nikad niste čuli za to jer je manje više beskorisno. To je cela svrha jezika EdScheme. Jezik EdScheme sadrži samo nekoliko ugrađenih funkcija (manje od dvadeset, ako se dobro sećam), a nema uopšte biblioteke koliko mi je poznato. Kad radite sa EdScheme knjigama, vi polako gradite jedan mnogo bogatiji jezik pomoću oskudnih alata koji su vam dati. U tom procesu, vi mnogo naučite o stvarima kao što su rekurzija i efikasnost, i počnete da shvatate da obično postoji više puteva u raj. Jedan primer koji mi se zadržao u sećanju bila je izrada jednostavne funkcije za preokretanje stringa. Sećam se toga kao kroz maglu, ali mi se čini da prvo čak nismo uopšte imali stringove; samo tipove array, char, integer i floating point. Tokom tog kursa, gradili smo na osnovu svojih prethodnih projekata. Problemi i neefikasnosti koje nismo otkrili na početku ubrzo bi se otkrili kako smo napredovali u kursu.

To iskustvo me je naučilo kako da svedem problem na njegov najjednostavniji oblik, Okamova (Ockham) oštrica programskog razmišljanja. Od tada, imao sam mnogo više uspeha u analizi problema i uvek se pitam: “koji je najjednostavniji način da se ovo postigne?” Veoma često, programeri biraju rešenja neverovatno neelegantna, samo zbog toga što koriste metode i alate na koje su već navikli. Programeri ne bi trebalo da pišu samo da bude što više redova koda, ne plaćaju ih po broju pomoćnih rutina kao Čarlsa Dikensa. Plaćaju ih da prave rešenja koja zadovoljavaju potrebe njihovih korisnika. Sve preko toga je prosto oholost. Programeri nisu vlastiti klijenti. Iskustvo sa jezikom EdScheme mi je dokazalo da je najvažnije da se postignu upotrebljiva, održiva i izvrsna rešenja; ponositi se sklepanim nemogućim rešenjima od neadekvatnih delova ne dolazi u obzir.

Još jedno iskustvo koje mi je pomoglo da proširim svoju svest o tome šta je dobro programiranje bio je jezik Perl. Perl je najelegantniji jezik koji sam ikad koristio. Veliko je zadovoljstvo kad se napiše jedan red koda koji obavi ono za šta bi u nekom drugom jeziku bilo potrebno pet, ili čak deset redova. Pre izvesnog vremena, preradio sam modul SoundEx CPAN iz Perla u jednu VB.Net klasu. Razlike u načinu pisanja koda su bile zapanjujuće. Nije samo to što Perl ima regex-e ugrađene kao string operator, a za VB.Net je potreban regex objekat. Bio je to celokupan stav ta dva jezika. Kad pišete VB.Net to je kao da se obraćate detetu od četiri godine; programiranje u Perlu je kao razgovor sa odraslim. Tačno je, kôd u Perlu može brzo da pređe u nečitak nered, pogotovo ako se preterano koriste implicitni operatori. Takođe je tačno da Perl sadrži priličan broj kontradikcija i nedoslednosti. Ali Perl je jezik tako neverovatno poučan i moćan. Negde oko 2000. sam pisao neki softver za trgovačku korpu (engl. shopping cart). U 1.609 redova koda (uključujući prazne redove, komentare, itd.) uspeo sam da upakujem sistem baze podataka sa ravnim fajlovima (to je bilo pre nego što je svaki računar na Vebu imao MySQL), potpun sistem šablona koji smatram boljim i moćnijim od PHP-ovog (to je bilo pre nego što je svaki računar na Vebu imao PHP), sam sistem trgovačke korpe, rutine za sesiju (niste mogli da računate da je instaliran CGI modul), evidentiranje grešaka, sve kompletno. Čak je postojao sistem modula za brzu izradu dodatnih modula. Priznajem, nedostajao mu je sistem onlajn administriranja; takođe verujem da je bio dovoljno jednostavan da mu taj sistem nije ni bio potreban. Kao i za EdScheme, pisao sam vlastite, prilagođene verzije koda za stvari koje većina programera uzima zdravo za gotovo, zato što je jedan od projektnih zahteva bio da se sme zahtevati jedino FTP pristup i Perl 5.

Za dublje razumevanje dobro napisanog koda, toplo vam preporučujem da pronađete projekat sa otvorenim kodom koji ne pripada “velikim zverkama” i pokušate da ga menjate i prilagodite svojim potrebama. Nedavno sam radio za ZenCart. Takav kakav jeste, sam softver je u redu. Ali moj klijent je imao izuzetne potrebe, pa “takav kakav jeste” nije nikako bio dovoljan. Morao sam da se udubim u kôd, do te mere da čak promenim osnovno funkcionisanje. Užasnuo sam se. Kôd je ličio na najgore primere iz lekcija Computer Science 101. Tu su bile ugnežđene petlje sa iteratorima kao što su “m”, “n” i “o”. Tu nije bilo doslednosti u imenima promenljivih. I tako dalje i tako dalje. Sam kôd je bio u redu, što se tiče funkcionisanja. Ali je bio tako nečitak da je ponekad čak i za minimalnu promenu bilo potrebno više sati samo da bi se pronašlo pravo mesto gde da se izvrši izmena. To me je učvrstilo u uverenju da treba razviti stil programiranja i držati ga se čvrsto. Ja imam poseban stil za svaki jezik koji koristim. Ali ostajem dosledan u okviru tog jezika, toliko da mogu da kopiram i prenesem kôd iz jednog projekta u drugi uz vrlo male (obično nikakve) izmene. Sitnice su veoma značajne, na primer da se iteratori uvek isto zovu. Kad neko vidi šta konkretna promenljiva znači u jednoj funkciji, odmah zna šta će da radi u sasvim odvojenoj funkciji u drugom delu koda, čak i u drugom programu koji sam ja pisao. Posebno je važno da timovi programera razviju zajednički stil i drže ga se.

Konačno, preporučujem da se prihvatite niza različitih jezika i pokušate da napišete isti mali projekat u svakom od njih. Brzo ćete naučiti šta se može a šta se ne može, za svaki jezik. Većina programa, na kraju, je u suštini CRUD (Create, Read, Update, Delete – napravi, čitaj, ažuriraj, briši) mehanizam; uzeti podatke od nekud, prikazati ih negde, dozvoliti da se nešto promeni i vratiti promene u izvor podataka. Neki jezici su u tome bolji od drugih. Na primer, .Net jezici su izuzetno podesni za neposredne funkcije baza podataka-na ekran-i nazad. Ali pokušajte da te podatke programski obradite pa će se pokazati ozbiljne mane jezika Visual Basic i C#. To su slabi jezici, nesposobni da bog zna šta urade bez džinovskog okvira .Net Framework iza sebe. Java je približno ista. Perl je neverovatno snažan jezik za obrade, pogotovo za tekst, ali njegovi sistemi kojima se podaci nude korisniku i uzimaju od njega su ispod poželjnog standarda. On je nastao kao proceduralni jezik i zato nije zabavno na njemu razvijati korisnički interfejs na kraju. I tako dalje. Dok budete učili razne jezike, imaćete takođe priliku da vidite kako stvari mogu da se urade. Što budete imali više alatki u svojoj kutiji, veća je verovatnoća da ćete upotrebiti pravu alatku za konkretan zadatak.

Znam da na ovaj spisak ima još mnogo toga da se doda. U suštini, želeo sam da bude jasno ovo: uvek širite svoje granice, nikad nemojte prestati da učite, i nemojte previše da se vežete za jedan jezik ili jednu metodologiju. Naučite šta u kojoj situaciji pomaže, pa ćete biti u stanju da odgovorite na svaki izazov.

Jedna od najvećih grešaka koju stalno susrećem u svetu tehnologije je problem kratkoročne koristi nasuprot dugoročnih rešenja. Previše često programer koristi prečice: ono što je najlakše, uzima alatke koje već ima, ili tehnologije koje su trenutno popularne. Te vrste kompromisa dovode do sistema koji su sklepani, postaju zastareli kôd koji je skoro nemoguć za održavanje, neefikasan i spor.

Nedavno smo na sajtu TechRepublic imali veliku diskusiju o tome da li programer treba da proba da predvidi buduće potrebe svojih korisnika. Deo te diskusije se vrteo oko pitanja do koje mere bi kôd trebalo da bude generički, što se svodi na kompromis između trajanja početnog razvijanja i fleksibilnosti na duže staze. Na primer, u nekom objektno orijentisanom jeziku, programer može svaki deo koda da primeni kao klasu i zanemari verovatnoću da se u budućnosti pokaže da je bilo bolje da je ta klasa bila interfejs. S druge strane, pisati sve kao interfejs koji će da koristi samo jedna klasa značilo bi uložiti neverovatnu količinu vremena u proces razvoja. Granica je zaista uska.

Jedno mesto gde kompromisi nisu dozvoljeni je oblast čitljivosti koda. Bez obzira na tesne rokove završetka, ne postoji nikakvo opravdanje da se promenljive zovu “a”, “b” i “c”. Ti dodatni bajtovi neće probiti budžet. U stvari, svakom polovinom sekunde koju uštedite kod pisanja koda, vi verovatno dodajete tri minuta na vreme traženja grešaka.

Još jedna prečica koja kasnije stvara velike probleme je neefikasno korišćenje biblioteka. Toliko je primamljivo da se učita milion biblioteka samo zbog jedne funkcije koja bi lako mogla da se kopira. Konačni rezultat je aplikacija koja je loša za skaliranje. Uzmite onu malu aplikaciju za Veb koju ste napisali, onu sa milion zavisnosti, pa pogledajte koliko memorije koristi. “Ali, ona koristi svega nekoliko stotina kilobajta!” kažete vi. Pomnožite to sa onim što se dešava ako vaša aplikacija iznenada postane jako popularna, ili se upotrebljava u okruženju velike korporacije. Pomnožite “koristi svega nekoliko stotina kilobajta” sa 70.000 istovremenih korisnika, i iznenada sistemski administrator lupa na vaša vrata i viče “preraditi kôd”. Ako učitavate celu biblioteku samo zbog jednog ili dva mala pozivanja, upitajte se da li vam to zaista treba i da li biste mogli isto da napišete u okviru svog postojećeg koda. To je jedna dobra osobina otvorenog izvora, možete da uzmete ono što vam treba a sve drugo da ostavite.

2051-kako-da-razmisljate-kao-programer-1