Meni

Razvoj in zastaranje programov – izziv in nočna mora programerjev

Saša Divjak

Sam sodim v starejšo generacijo, saj sem svoje prve programerske izkušnje pridobil leta 1967 na legendarnem računalniku Zuse Z32. Začetek 70. let prejšnjega stoletja je bilo obdobje luknjanih kartic in perforiranega traku. Takrat je programiranje prvih mikro-, včasih pa tudi miniračunalnikov potekalo na zanimiv način. Kot periferno enoto računalnika smo uporabljali »Teletype«, ki je poleg tipkanja in tiskanja združeval še čitalnik in luknjač papirnega traku. Priprava in izvedba programa je potekala tako:

Najprej si moral v računalnik vnesti urejevalnik teksta, ki je bil pomnjen v binarni kodi na traku. Zatem si napisal svoj program in to izvorno kodo (pogosto v zbirnem jeziku) naluknjal na nov trak. Sledilo je branje zbirnika (angl. assembler), seveda spet binarno zakodiranega na drugem traku. In nato branje »svojega« programa v izvorni kodi. Kolikor se spomnim, je tudi to branje potekalo v dveh korakih, saj zbirnik za svoje delo potrebuje vsaj dve fazi. In končno, če je bilo (skoraj) vse v redu, si lahko naluknjal nov trak, tokrat s svojim programom v binarni kodi. Sledila sta branje binarno kodiranega novega programčka in njegova izvedba. Za to, kar danes naredimo v drobcu sekunde, si potreboval kar nekaj minut in upal, da se nisi kaj zmotil. Sicer si moral celoten postopek praktično ponoviti.

Pri programiranju mikroračunalnikov si svoj strojno zakodirani program običajno še »zapekel« v EPROM (integrirano vezje, ki je predstavljalo del pomnilnika mikroračunalnika). Tako smo razvijali različne mikroračunalniško podprte avtomatizacije. Programerji pa se radi motimo. Ker je celoten ciklus potreboval kar nekaj časa, smo pogosto (če se je dalo) popravke vnesli kar v strojno kodo in preskočili zamudno luknjanje traku. Posledično smo imeli na koncu pravilno delujoč program v EPROMU, izvorna koda pa temu ni več povsem ustrezala. Seveda je to zelo narobe.

Miselno prehajanje med programi v zbirnem jeziku in njihovo strojno kodo je bilo nekaj vsakdanjega. Nenazadnje smo v tistih časih pogosto vpisovali zagonski nalagalnik (t. i. bootstrap loader) kar prek stikal na konzoli računalnika. In, ker smo to pogosto počeli, ni bilo nič nenavadnega, da smo si na pamet zapomnili tudi zaporedja več 10 ukazov na strojnem nivoju. Take so bile na primer moje izkušnje s prvimi računalniki iz družine Digital PDP 11 v 70. letih prejšnjega stoletja.

Pred nadaljevanjem naj povem, da sem na Fakulteti za računalništvo in informatiko predaval predmete s področja programiranja, sistemske programske opreme in operacijskih sistemov. In, kar me je še posebej veselilo, računalniške grafike. To se odraža tudi v nekaterih spominih, ki jih bom navedel v nadaljevanju.

Danes je na svetu registriranih več kot 9.000 različnih programskih jezikov in tudi načini programiranja so se zelo spremenili. Na takratni Fakulteti za elektrotehniko in računalništvo na študijskem programu računalništva in informatike smo v 80. letih pri programiranju uvedli programski jezik C, ki je še danes »latinščina« in dobra osnova za marsikateri drugi programski jezik. V letu 1997 pa smo uvedli še programiranje v programskem jeziku Java. Kot nosilca predmeta me je vedno skrbel stalen razvoj tega, takrat še novega programskega jezika, ki je v naslednjih letih doživel kar nekaj bistvenih sprememb, saj smo aktualne jezike uporabljali tudi v okviru različnih projektov.

Po drugi strani smo pri razvoju spletnih aplikacij že v poznih 90. letih uporabljali še danes popularni JavaScript. Objektno usmerjenemu programiranju so se pozneje pridružili drugi pristopi. Med njimi je pomembno komponentno programiranje, ki pomeni uporabo različnih problemsko usmerjenih knjižnic in tako sestavljanje novih aplikacij s kombiniranjem lastne razvojne kode in funkcionalnih modulov, ki jih take knjižnice nudijo. Zakaj bi izumljali toplo vodo, če pa nekatere rešitve že obstajajo, na primer za podporo 2D in 3D računalniške grafike, pa za izvajanje različnih bolj ali manj kompleksnih, že preskušenih in računsko učinkovitih rutin. Tak pristop po eni strani predvideva poznavanje tako imenovanih API-jev (Application Programming Interfaces), hkrati pa zelo pospešuje razvojno delo. Vendar hkrati skriva tudi pasti, ki jih predstavlja razvoj novih in novih verzij, kar sčasoma nujno pripelje do neskladja posameznih komponent naših aplikacij in posledično zastarelosti našega programja. V tem smislu je posebej nevarno »mešanje« tehnologij različnih proizvajalcev, saj vsak sledi svojim standardom in usmeritvam. Kot primer naj navedem danes že praktično pozabljeni VRML (Virtual Reality Markup Language), ki se je pojavil sočasno s programskim jezikom JavaScript in je omogočal za tiste čase kar spodobno 3D-vizualizacijo in animacijo 3D-scen. Kombiniranje jezikov VRML in JavaScript je omogočalo izdelavo zelo atraktivnih 3D-vizualizacij in interaktivnih simulacij naravoslovnih pojavov. Danes so ti primeri že povsem zastareli in jih ne moremo več kazati (res pa je, da je današnja 3D-grafika vse kaj drugega). Spomnimo se še javanskih apletov, ki so omogočali raznovrstne aplikacije (in tudi 3D-vizualizacije) v naših brkljalnikih. Pa so ugotovili, da ima taka tehnologija preveč varnostnih lukenj, saj je omogočala tudi delovanje izven oglaševanega varnega »peskovnika«. Ponudniki brkljalnikov so to začeli drug za drugim onemogočati v novejših verzijah. Danes si lahko to ogledamo le na računalnikih, ki imajo v ta namen nameščene za današnje razmere zastarele operacijske sisteme in brkljalnike. Pri tem si pogosto pomagamo z »virtualkami« (navideznimi napravami) na našem računalniku. Razvijalci smo nujno iskali rešitve v sorodnih tehnologijah v upanju, da bomo sedaj pa imeli mir. Tako je marsikdo »preklopil« na nekdaj popularni Flash in na njegov programski jezik ActionScript. V nekaterih primerih je lahko tako ohranil tudi do 80 % svoje programske kode. Kasneje smo lahko ugotovili, da smo se »ušteli«. Danes je Flash (in s tem ActionScript) že izumrl. Prava usmeritev je bila v JavaScript oziroma v jQuery zaradi večje programerske učinkovitosti. Spet si običajno pomagamo z različnimi knjižnicami za učinkovito in poenoteno pripravo grafičnih uporabniških vmesnikov ipd.

Dandanes se srečujemo s številnimi mobilnimi napravami, od pametnih telefonov prek tablic do večjih ali manjših prenosnih in namiznih računalnikov. Zaradi raznolikosti zaslonov se je uveljavil »odzivni dizajn« (angl. responsive design), ki omogoča enako uporabniško izkušnjo na različnih napravah ne glede na velikost in resolucijo našega zaslona. Kako si lahko pomagamo pri razvoju takih aplikacij? Nekako logičen korak se zdi uporaba knjižnice jQuery Mobile, ki omogoča načrtovanje grafičnih uporabniških vmesnikov, ki so primerni za različne naprave. No, obstajajo tudi druge možnosti, na primer popularni Bootstrap. Vse lepo in prav, a le nekaj časa. jQuery je iz verzije 1 prešel v naslednje verzije (v času pisanja tega prispevka obstaja verzija 3). In razvojna orodja kar naenkrat razvijalcu pošiljajo opozorila (angl. warning), da so delci naše kode zastareli (angl. obsolete, deprecated). Če drugega ne, je to grdo in nas mora skrbeti, saj postaja naša koda stara in bo verjetno sčasoma neuporabna. Dobro, pa bomo izvedli migracijo (spremembo) naše kode, da bo ta skladna z novimi napotki. Posebno pri daljših programih se nam to zamudno delo upira, saj terja sistematičnost, a je nujno, če želimo slediti razvoju. A tu se skriva še kakšna dodatna past. Tako se je na primer razvoj pri jQuery Mobile ustavil in novim različicam jQuery ni več sledil. Preostane nam še dodaten prehod oziroma opustitev kode, ki jo predstavlja taka zastarana knjižnica.

Danes govorimo o izumrlih jezikih in delo programerja se ne zaustavi pri razvoju morda atraktivne aplikacije. Njeno vzdrževanje z leti terja dodaten napor.

Eno od vprašanj, ki se programerju poraja, je, komu sploh zaupati in slediti, da ne bo njegovo vloženo delo prehitro zastaralo. Gotovo so to »veliki svetovni igralci«, pa še tu se včasih zatakne. Če se povrnem na 3D-grafiko, se spomnim Microsoftove tehnologije Silverlight, ki je nudila možnost zelo lepih vizualizacij 3D-svetov in njihovih animacij. Past, ki se je pri tem skrivala, je bila ta, da je bil to pač Microsoftov izdelek. Ali mu bodo sledili tudi drugi? Poleg MS Windows imamo tudi druge operacijske sisteme. In res, Silverlight se ni prijel in je danes opuščen.

In tudi sedaj se razvijalci srečujemo s podobnimi dilemami. Nedvomno je zaradi popularnosti mobilnih naprav zanimiv razvoj aplikacij za operacijske sisteme Android in iOS. Kar nekaj razvijalskih platform najdemo na Internetu. Kateri naj zaupamo, katera se bo obdržala vsaj malce dlje? Katera pa bo hitro izumrla? Je to React? Ali pa morda Flutter, ki spet temelji na novem jeziku (Dart)? Le zakaj je to potrebno? Beremo forume, ustvarjamo svoje vtise in upamo, da gremo v pravo smer.

Če nek projekt začenjamo na novo, si moramo prej dobro ogledati, kateri trendi so danes uveljavljeni. Prevladujejo spletne aplikacije in čedalje bolj računalništvo v oblaku. Že kar nekaj časa je uveljavljena uporaba jezikov HTML5, pa CSS in AJAX/JSON. Jezik JavaScript (ali bolje JQuery) je izpodrinil Flash. Apleti so že davno izumrli.

Tudi načini razvoja programov so se spremenili. Uveljavljajo se metode hitrega inkrementalnega razvoja, ki zamenjujejo sekvenčni pristop. V sklopu istega projekta včasih uporabljamo po več jezikov in poznati moramo različne aplikacijske programske vmesnike (API). Kompleksnost programov se povečuje.

Zaznamo lahko polarizacijo programiranja: po eni strani uporabljamo visokonivojske programske jezike, ki omogočajo večjo produktivnost programerjev, pa tudi paralelizacijo in delo v oblaku. Po drugi strani so včasih pomembni učinkovitost kode in večanje hitrosti izvajanja ter uporaba asimetričnega računanja (tudi zaradi večjedrnih sistemov). Hkrati zasledimo »demokratično« računalništvo, ki pomeni, da si lahko kaj malega sprogramira ali vsaj priredi tudi vsak manj poučen (a motiviran) uporabnik. In omenimo še »nevarno računalništvo«. Če nekaj postane prekompleksno, si pač omislimo novo ogrodje (angl. framework), ki morda nadgrajuje nekaj prejšnjega. Stvar se kopiči podobno kot sklad umazane posode ali krožnikov in v sebi skriva neučinkovitost kode, pa tudi kakšne varnostne luknje.

Sprašujemo se lahko, kaj je še pred nami. Še vedno se moramo spomniti na znani Moorov zakon, ki govori o tem, da se število tranzistorjev (torej gostota integriranih vezij) podvaja vsaki dve leti. A kaj, ko obstajajo tako imenovani štirje Nathanovi zakoni, ki govorijo o tem, kaj se dogaja s programi. Že davnega leta 1997 jih je postavil Nathan Myhrvold, nekdanji glavni tehnološki direktor pri Microsoftu. Pri teh zakonih dobimo zanimivo asociacijo na Newtonove zakone, a le poimensko. Oglejmo si jih:

1. Nathanov zakon: Programje je kot plin.

Programska oprema se vedno razširi tako, da na koncu zasede katerikoli vsebnik (torej kapaciteto računalnika), v katerem je shranjena. Primere take rasti zasledimo pri novih in novih verzijah operacijskih sistemov, kot sta Windows in Linux, pa tudi pri razraščanju kode brkljalnikov.

2. Nathanov zakon: Programska oprema raste, dokler je ne omeji Moorov zakon.

Sprva se širi hitro, podobno kot se širi plin. A rast neizogibno upočasni zmožnost aparaturne opreme. Zato sleherni procesor prej ali slej poklekne. To se običajno zgodi malo pred pojavom novih modelov.

3. Nathanov zakon: Rast programov omogoča Moorov zakon.

Zato neprestano kupujemo nove računalnike. Integrirana vezja v njih so čedalje hitrejša, a cena računalnikov se bistveno ne spreminja. Več dobimo za isti denar. Ta fenomen se ponavlja, ker se pojavljajo novi in novi programi.

4. Nathanov zakon: Programe omejujejo le človeške ambicije oziroma pričakovanja.

Nikdar nam ni dovolj. Srečujemo se z novimi aplikacijami. In novimi pogledi, kaj je moderno.

Programi in tudi samo programiranje je tako venomer v krizi. Kar koli dosežemo, običajno ne dosega pričakovanj uporabnikov. Lestvica pričakovanj se neprestano dviguje.

Programiranje je umsko zahtevno tudi za izkušene programerje. Stalno preslikavamo med različnimi miselnimi modeli v naših glavah in pretvarjamo različne predstavitve v kodo in nazaj. Programi so pravzaprav abstrakcije in pri njihovem razumevanju si pogosto pomagamo s konkretnimi primeri.

Pomagamo si s pristopi, kot je objektno usmerjeno programiranje, in z uporabo višjih programskih jezikov. Pogosta praksa je tudi pristop kopiraj/prilepi, ki temelji na uporabi »izrezkov kode« (angl. code snippets).

Vemo, da še otroci bolje razumejo nekaj, kar vidijo, v primerjavi s tem, kar le slišijo. Kar čutimo, takoj razumemo, besede pa moramo najprej analizirati, če želimo vedeti njihov pomen. To ni problem pri kratkih stavkih. Dolga besedila pa terjajo več časa in napora. Tako je tudi s programsko kodo. Nekateri izvorni programi so težko razumljivi in včasih je enostavnejše, da jih razvijemo kar znova.

Bo kar držalo, da so programski jeziki namenjeni ljudem in ne računalnikom in da smo še v zgodnjem obdobju zgodovine programiranja. Velik premik je predstavljal prehod od luknjanih kartic in trakov na interaktivno delo za računalniškimi zasloni. Naslednji premik pa bo moral upoštevati, da v nekaj desetletjih pričakujemo razvoj tako sposobnih računalnikov, ki bodo dosegli inteligenčno raven ljudi. Le kako bomo take računalnike programirali? Ali se bodo takih veščin učili sami? Si bodo sami izmišljali nove standarde? Bodočnost bo vznemirljiva. Morda pa nas mora skrbeti.