Posadi funkciju da sazrije

Evo jedan jednostavan zadačić koji nosi jaku lekciju. Barem moje osobno mišljenje da iza ovog jednostavnog principa kojeg ću pokazati stoji velika vrijednost, jer omogućuje kreiranje strukture programa koja je jednostavno proširiva, a bez narušavanja prethodno stvorenoga.

To je čest problem…svi mi svjedočimo da updateovi programa često za sobom nose more bugova koji iskaču iz prošlosti na taj neki novi update.

E sad, kad kreiramo neku funkciju, nikada ne možemo pretpostaviti što će donesti budućnost i kakvu ćemo prilagodbu morati raditi na toj funkciji da ona zadovolji sve naknadno nastale zahtjeve koji će se od nje tražiti…

Kod prvog kreiranja funkcije, dobro je malo misliti unaprijed…no nemoguće je uzeti sve u obzir što će doći… Zato temelje funkcije treba postaviti lako proširive, pa je čarolija upravo u tome da će novonastali zahtjevi forsirati “sazrijevanje” funkcije. Kroz par godina adaptacije funkcije prema novim zahtjevima…nastaje pravo čudo (rekao bih). Čudo zato jer kroz te godine je funkcija na neki način evoluirala…i to čak i neovisno od nas. Triger evoluciji nismo mi, nego zahtjevi koji iskaču iz okoline na koje nismo mogli računati prvog dana. Mi smo samo izvršni član, koji slijedi jednostavne principe da omogući traženu evoluciju, a da ne naruši postojeće veze. Kad se savladaju ti principi, mi smo nekako samo statisti koji “hranimo” te funkcije i gledamo njihovo sazrijevanje ka tolikoj kompleksnosti koju i sami teško kasnije razumijemo. Rekao bih da toj čaroliji ne podliježe samo neka tamo naša malena funkcija…nego i evolucija svih programskih tehnologija/jezika…od asembly-a …pa na dalje.
A divno je to, kad funkcije koje hranimo, postanu toliko kompleksne da ih i sami teško razumijemo…mi ih zapravo i dalje možemo “hraniti” sljedeći jednostavne principe koji ostaju uvijek u puno jednostavnijoj formi od ukupne kompleksnosti koja se stvara…
Ja taj proces zovem sazrijevanjem funkcija. No bitna stvar, da bi funkcije uopće mogle sazrijevati …treba ih prvo posaditi i držati u posudi u kojoj će rasti. (Što bi točno značilo posaditi, i posuda u kojoj rastu ? …o tom potom…može netko pokšati dati odgovor…)

E sada, ne očekujte nikakvu spektakularnu metodu…ali ljepota je upravo u jednostavnosti. I vjerujem da mnogi to i rade kako ću pokazati. No ova lekcija je inspirirana @belmin -ovom željom da uči, i praktički ovo je savjet njemu da razmotri ovu ideju. No svakako, svi su pozvani da daju svoje solucije na dat zadatak. A sada zadatak:

function getDayName(miliseconds)
	{
	var dayNames=['nedjelja','ponedjeljak','utorak','srijeda','četvrtak','petak','subota'];

	var date=new Date(miliseconds);
	var dayIndex=date.getDay();

	return dayNames[dayIndex];
	}

Ovo je jedna jednostavna JS funkcija koja vraća ime dana za ulazni parametar milisekunde.
Kreator ove funkcije nije imao velikih potreba, te je to napravio u najjednostavnijem smislu kojem je mogao…
…no tu nastupate vi koji trebate veću funkcionalnost iste ove funkcije. Vama treba da vam funkcija može vratiti ime dana i za broj od 0-6 (koji predstavlja index nekog dana u prikazanom arrayu), isto kao i za milisekunde.
Također vam ponekad treba da vam funkcija vrati samo short varijantu imena: (pon,uto,sri,cet,pet,sub,ned)

Kako biste to učinili? Traženo rješenje mora biti uklopljeno u postojeću funkciju, te ne smije naravno narušavati postojeću vezu ulaza izlaza gore prikazane funkcije. Što u prijevodu znači, gdje god se ova funkcija do sada koristila…ti djelovi codea moraju i dalje jednako raditi kao što su i dosad.

1 Like

Ako je poanta ovog zadatka ucenje, onda moran narusit ideju zadatka. Ucenje da jedna te ista funkcija mora vracat vise od jednog tipa outputa je ucenje krivih i losih praksi. Zato ti se i događa da ti funkcije “evoluiraju” u cudovista koja vise ne razumis.

Rjesenje je napisat razlicite funkcije za razlicite outpute. I voila, radi sve staro, radi sve novo, kod je citljiv, promjena jednog dijela ne utjece na ostatak.

Ako je poanta zadatka ucenje, onda valjda zelis naucit da funkcijama ne smis dozvolit da narastu u cudovista.

getDayNameByMiliseconds()
getDayNameByIndex()
getShortDayNameBy…

3 Likes

Ako bih već baš morao nastaviti razvijati navedenu funkciju, radio bih po principu klase ( ispravite me ako griješim ):

function getDayName(miliseconds,Class)
{
var dayNames=[‘nedjelja’,‘ponedjeljak’,‘utorak’,‘srijeda’,‘četvrtak’,‘petak’,‘subota’],
shortDayNames=[‘ned’,‘pon’,‘uto’,‘sri’,‘čet’,‘pet’,‘sub’];

    var date=new Date(miliseconds);
    var dayIndex = date.getDay();
    this.getShortDay = function(){
        return shortDayNames[dayIndex];
    }
    this.getMiliseconds = function(){
        return miliseconds;
    }
    if( typeof Class != 'undefined' )
    {
        if (!(this instanceof getDayName)) return new getDayName(miliseconds);
    }
    else return dayNames[dayIndex];
}

inicijalizacija funkcije ostaje ista, samo dodan parametar i po njema se štim funkcija.
Tako nekako otp?

Naravno, i to tako da kroz konstruktivnu raspravu svi možemo nešto naučiti. Zato sam i ostavio temu načetu pitanjem, da iznese svoje stavove tko želi…

Što se tiče tvoga, u jednu ruku se slažem u drugu ne.
Sigurno da je u praksi nekad bolje nadograditi funkciju, nekada raditi novu. …no imaš primjera kada je nužno ići sa nadogradnjom. (To možda nije moj dati primjer…ali zato sam napomenuo da rješenje mora biti uklopljeno u postojeću funkciju)

Inače, ako bi i mogli birati između nadogradnje i gradnje novih funkcija, treba svakako razmotriti prednosti i mane svakog od pristupa. Jer sigurno je da oba pristupa imaju prednosti i mane.

Što se tiče tvoga:
-ne raste ti kompleksnost funkcije, no raste ti broj metoda …koje opet teže ka velikom broju. (što povlači kompleksnost na drugom levelu) Kad bi sve granali u svoju metodu, nebi bilo kraja…
-no važan aspekt DRY (dont repeat yourself) …ti da bi se držao DRY koncepta, morao bi graditi i metodu koja ti vraća array s imenima dana… jer nebi smio taj array kopirati u svaku svoju metodu po DRY konceptu, koji ipak stoji iza svega.
…onda tu dolazi i array sa “short day names”…i sve ostalo što se može zakačiti po tom pitanju imena (Recimo dolazi novi jezik, ovo ono…), a tebe sve to tjera da gradiš nove metode. Tako da u tvom pristupu metode će rasti prilično nesrazmjerno sa kompleksnošću funkcije koju smo sposobni extendati i prilagoditi traženim zahtjevima.

Također, zašto imam prilično uvjereno stajalište da nisam daleko od ispravne priče…a to je da isti koncept koji predlažem uočavam redovito u Google-ovim API-jima, jQurey-ovom library-u …itd.
Ja sam se jedno vrijeme baktao sa čudno organiziranim parametrima funkcije…i kad sam isplivao na ovaj koncept, samo mi se upalila lampica: “Aaaaaa, zato tako izgledaju Googlovi API-ji, i ostali…bemu kako nisam ranije to skužio!”

Recimo, googleov geocoder:

geocoder.geocode({latlng:coordinate},callback); //geokodiranje lokacije pomoću latlng koordinata
geocoder.geocode({address:‘Zagreb’},callback); //geokodiranje lokacije pomoću imena adrese

Po tvome bi bilo praktičnije:
geocodingByLatLng(latlng, callback);
geocodingByAddress(address, callback);

…ali onoliko kombinacija koliko možeš ispratiti igranjem s parametrima, teško da ćeš ispratiti građenjem zasebnih metoda, a da se još više ne pogubiš.

I da ne bude zabune, ja nisam spominjao čudovišta koja nisu razumljiva…nego teška razumljiva dok se promatraju u cijelosti. No bitniji je onaj dio da i pri tolikoj kompleksnošću mi i dalje imamo jedostavne principe s kojima ih možemo hraniti da i dalje sazrijevaju. Zato jer više nije ni bitno skroz razumjeti cjelost takve funkcije, i njenu interakciju u cijelom sistemu…samo treba dobro razumjeti pojedini spreg ulaz-izlaz koji se odluči promatrati…te znati kako nadograditi neki od tih spregova da se ne naruše ostali.
Razumjevanje cijele funkcije bi u tvojoj varijanti bilo razumjevanje svih metoda od jednom…i kako promjena jedne metode može poremetiti rad drugih. Uzmi u obzir da tvoje metode koje nastaju paralelno, moraju koristiti izvore nekih trećih metoda da bi se držali DRY koncepta. (To bi recimo u ovom primjeru bilo dohvaćanje imena dana iz nezavisne treće metode) …i onda opet imaš istu vrstu problema (ali u težoj varijanti, jer se metode daleko više granaju, nego logička igra sa parametrima) Tako da ako moraš čačkati po tim trećim nezavisnim metodama, teško je ponekada imati ideju što će se sve narušiti zbog toga čačkanja… te smo izgubili ono da problem možemo svesti na jedinstveni ulaz-izlaz, iako se na prvu čini da će organizirane metode to postići.

No, ako uopće zanemarimo vaganje između nadogradnje funkcije i gradnje novih metoda…treba biti svjestan da je nekada nadograđivanje nužnost, tako da samo iz toga aspekta mislim da rasprava o nadogradnji funkcija je skroz na mjestu.

Hmm…koliko vidim, ti si napravio da za slučaj ako je zadan Class, da funkcija vraća klasu koja će imati svoje metode…i onda bi sa tim metodama ispunio proširenje funkcionalnosti.

Iako trenutno ne simpatiziram to rješenje, jer se ovo može rješiti i bez klasa. Mislim nisu klase loše…ali miču sada fokus sa prilično jednostavnog principa igranja parametrima funkcije.
Kada bi ovo bila neka uvodna lekcija u nekoj knjizi o funkcijama i parametrima i što se s njima može…nebi imalo smisla da se rješenje nudi pomoću klasa, ako kapiraš na što mislim.

Nego kad si već krenuo tim pristupom, nisi rješio drugi dio problema koji kaže da dohvaćanje imena dana trebamo moći napraviti i pomoću parametra misliseconds, i pomoći broja koji je index od 0-6.

…a ova metoda getMiliseconds() nije nigdje spomenuta. Ne kužim čemu ona tu?

Nadalje, malo mi grdo izgleda poziv ovako definirane funkcije/klase, koji bi bio:

var shortDayName= getDayName(miliseconds,1).getShortDay();

…prilično grdo si tu uprakirao klasu :frowning: …i način pisanja poziva, a i sa optimizacijske strane ti kreiraš instancu klase za svaku pretvordbu mislisecond -> dayName

I da još dodan…ovo što želim pokazati je uporabljivo koristile se klase ili ne. Pomaže i korisno je u oba slučaja. A to je još jedan razlog da jednostavnost ovog primjera ne narušavamo sa klasama.

Jako puno toga si napisao, ali ne mijenja se poanta.
Jedini razlog, U PRAKSI, da ti metoda/funkcija ispadne cudoviste je lijenost. Jedini. Kao imam nesto dodat, necu sad refaktorirat stvar da bude citljivija, nego cu stavit tu jedan if i gotovo. I tako par puta. Ali to nije ni zeljeno ni normalno. I svaki programer koji mi takvo lijeno rjesenje pokaze na code reviewu se srami toga sta je napisa uz tipicno “jebiga, tribalo je bit gotovo tad i tad, nije mi se dalo kopat i minjat to” opravdanje.

Rast broja metoda nije nikakav argument. Pa bilo kakav projekt danas ce imat tisuce, desetke tisuca metoda; koga brige? To je nevjerojatno nebitan podatak, i ne podize kompleksnost koda (a upitno je podize li i kolicinu koda, mada je to također apsolutno nebitan podatak).
Dobit shortname dana je jedna metoda. Nije 101 metoda. Ako ti treba shortname, ne treba ti fullname. I naravno da ne bi array kopirao u svaku metodu. Takve stvari su definirane konstante van funkcija, zajedno sa translacijama (konstante u svojim fajlovima), i funkcije onda samo referenciraju vanjske konstante.
Manje metode također imaju prednost iskoristivosti na vise razlicitih mjesta. Ne zelis se dovest u situaciju da svako par linija koda zoves gigantsku getAndCalculateEverything()

Definirat vanjski API i definirat jednu funkciju nije ista razina problema. Također imat jednu funkciju koja tolerira razlicit tip unosa, a ima definirani output, i imat jednu funkciju koja ima i razlicite inpute i razlicite outpute su dvi jako drugacije stvari (da ne govorim da bi to bila apsolutna nocna mora za debugirat). Osobno bi reka da je i jedno i drugo jednostavno lose programiranje, iako definitivno postoje iznimke pravila di je tolerirat razlicit input sasvim ok (tipicno user input kojeg ne zelis prisilit na strogi unos, nego resolvas input prije zvanja tih malih zasebnih funkcija).
API definitivno spada u takve stvari. Api funkcija koja ce uzet koordinate latlng ili string iza sebe vjerojatno poziva druge funkcije koje onda resolvaju takav input. Sigurno nije sve utrpano u jednu funkciju u dev environmentu. U produkciji ima smisla radi minifikacije koda, ali tu vise ne pricamo o dobrim dev praksama, nego o necem drugom.

[quote=“bozoou, post:4, topic:28154”]
Zato jer više nije ni bitno skroz razumjeti cjelost takve funkcije, i njenu interakciju u cijelom sistemu…samo treba dobro razumjeti pojedini spreg ulaz-izlaz koji se odluči promatrati…
[/quote].

Vidis, ovo sta si napisa je vise opis onog sto ti ja pokusavan sugerirat. Zamijeni “cijelost takve funkcije” sa “cijelim appom” i “pojedini spreg ulaz-izlaz” sa “funkcijom”. Nije bitno znat sve moguce funkcije koje su ti dostupne u appu kojeg pises; bitno je razumit ulaz-izlaz one funkcije koju zelis koristit. Da tvoj getDayNameByIndex(0) vraca ponedjeljak. Koga brige kako shortnameSomething radi u ovom slucaju?

Finalno, ovo sto ti ja tipkam nisu moji “stavovi” i nisu produkt (samo) teoretiziranja i kontempliranja o problemu. Ovo sto ti ja tipkam su opceprihvacene dobre prakse koje se svakodnevno dokazuju u izrazito kompleksnim i velikim projektima. Zelim rec, ne moras mi opisivat kako pisanje cistih jednostavnih funkcija dize kompleksnost codebasea jer ja znam da to ne samo da nije istina, nego je potpuno obratno - smanjuju kompleksnost i cine razvoj kompleksnih sustava puno jednostavnijim.

4 Likes

Kužim ja tebe…i odmah sam napisao da u nekim varijantama je bolje ići na novu metodu. No, čini mi se da ti mene ne kužiš iz možda razloga što gore dati primjer si uzeo kao referencu, a ja pričam općenito. Pa ću pokušati sa prihvatljivijim primjerom.

Ako pričamo općenito, ne postoji nikakav array koji možeš prikazati konstantnom. U ovom slučaju array,ali on samo predstavlja nešto zajedničko što te tvoje metode dijele. Ako bi tvoje metode djelile neku zajedničku logiku, umjesto arraya…onda bi tu logiku morao upakirati u posebnu metodu. I to je opet normalno za neke slučajeve…no za neke nije.

Idem sada sa malo upečatljivijim primjerom, znači novi zadatak:

function makeDiv(width, height)
	{

	var div=document.createElement('div');

	div.style.width=width;
	div.style.height=height;

	return div;
	}

Ova funkcija predstavlja jedan generator div elementa. Konstruktor očito nije puno mislio unaprijed, kad je kao ulazne parametre zadao samo width i height. Njemu je očito tako trebalo i to bilo dovoljno.
Kasnije se u programu pokazalo da generator divova treba malo više customizacije.
Prvi zahtjev koji je nastao, da ponekada trebaju crveni div elementi. Prema tome, najbolje je da se može prilikom generiranja diva, odmah zadati i background color. Kako prilagoditi postojeću funkciju da može odgovoriti na nametnuti zahtjev?

Eto, ista priča upakirana u malo drugačiji zadatak.
Sada, kad bi ono gornje što pričaš bilo univerzalno, rješenje problema bi bilo
makeRedDiv(width, height)
…pa jednog dana makeGreenDiv() , makeYellowDiv() … a po meni je logično da ako se ukazala prilika, da ćemo problem rješiti uvođenjem parametra.

Točno tako, ali s druge strane…ni ti se ne želiš dovesti da za svaki drugačiji ulazni parametar imaš posebnu metodu. (Kao što je gore prikazano sa bojama)
Ne vidiš li da je to ono što se mora znati balansirati?? Nije crno bijela situacija da se može prevagnuti samo na jednu ili samo na drugu stranu!!!

Da, ali treba malo bolje razmisliti što je različiti output. Dali je crveni div i zeleni div, dali su to različiti outputi? U jednu ruku da, no realno ne, jer su tematski povezani.
Isto tako su tematski povezani “pon” i “ponedjeljak” te se ne moraju nužno promatrati kao različiti outputi. Opet se vraćamo da ne mora biti isključivo crno ili bijelo. Treba znati svako za sebe odvagati što mu spada pod istu metodu što ne. No nikako ne možeš tvrditi, da svaka minorna razlika će zahtjevati vlastite metode…što se nadam pokazao sa generiranjem customiziranog div-a.

Pa to sam napisao apsolutno svjestan analogije koje spominješ. No napisao sam zato uz to gdje se onda u tvom slučaju skriva kompleksnost za koju misliš da ne postoji kad razbiješ sve u svoju metodu. A postoji… kad bi baš za sve imao svoju metodu poput makeRedDiv, …YellowDIv… …bome bi se pogubio u njihovim interakcijama (što se tiče develop perspektive)…a da ne govorim u korištenju istoga (kao korisnik svojih tehnologija.)

Nisu džabe API-ji takvi kakvi su. Oni su orijentiratni da budu maksimalno user-firendly. Ti kao korisnik svoga vlastitoga codea također moraš biti user-firendly sam prema sebi. Tako da ne kužim zašto ignoriraš relevantnost strukture API-a?
Naravno da se ti API-ji unutar sebe pozivaju na svoje metode…no to ja nigdje nisam ni osporio. Samo nema smisla sve razbijati. Pa i u slučajevima kad se razbija, često je dobro ostaviti prema korisniku (sebi) mogućnost parametriziranog upita…a to dalje rasčlanjivati, ili ne, u metode…po potrebi.

Što se tiče “pon” vs “ponedjeljak” …što ako programski nekim parametrom odabireš hoćeš li ispisati kratko ili dugo ime?

Ako je upit parametrom određen, to ćemo izvesti skroz jednostavno…no ako upit ide kroz dvije različite metode, onda ćemo imati nešto tipa:

if(needShortName) var day=getShortDayName()
else var day=getDayName()

Znači, preselili smo samo taj if na drugo mjesto. No ako ovakav poziv imamo na deset mjesta, onda imamo 10 if-ova umjesto jednog. I to te opet onda tjera da se kreira još jedna nova metoda koja će podržavati upit na koji će reagirati sa fullName ili sa shortName. Gdje dolazimo do metode koja ima parametriziran upit… (za što ja tvrdim da je to prvi korak, a rasčlanjivanje metoda ide dalje po potrebi…ako se ukaže da sazrijevanje ide u tom smjeru. )

Priča se dodatno zakomplicira, ako imaš varijatnu fullName, shortName i varijante getByMiliseconds, getByDayIndex…
da vidimo, po tvojoj tvrdnji trebamo sljedeće metode:

getShortDayNameByMiliseconds()
getFullDayNameByMiliseconds()
getShortDayNameByDayIndex()
getFullDayNameByDayIndex()

interestatno. To ti govorim, ne može biti crno bijelo…jer u tvojoj krajnosti ti broj metoda raste esponencijalno sa brojem parametara. Ovdje su samo dva parametra koja imaju svaki po dva stanja. 22=4 metode. Što bi bilo da je pet parametara, svaki sa pet stanja. Ja ću to vrlo čitljivo upakirati u jednu metodu od par linija. Ti ćeš imati 55=25 linija samo da se popišu nazivi svih metoda…

Kužiš li sad koja je tvoja krajnost i između čega treba odvagati za odabrati jedan pristup ili drugi.
No tema nije inicijalno započeta sa objašnjenjem što ćemo odvagati,nego za slučaj ako smo odlučili extendati postojeću funkciju, kako to možemo napraviti.

Pa izmisljas primjere i nudis rjesenja koja idu u prilog onome sta zelis rec :smiley: Reddiv, yellowdiv su besmisleni neargumenti.
Za ovaj “needShortName” se to tako ne radi. Ako znas jel ti triba short ili long, odmah pozoves potrebnu funkciju. Ako je to dio nekog settingsa kojeg korisnik postavi (razlog da ne znas unaprijed), onda ne zoves direktno funkciju nego (bubam bezveze) user.settings.formatDayName(), a ta metoda ce znat jel korisnik zeli short ili long, i imat jedan if iza kojeg ce zvat potrebni mali formatter.
Taj tip funkcije (formatiranje outputa dana, sata, valute itd), tipicno stavljamo u nekakav helper objekt formatera, i lomimo ga na najsitnije moguce djelove, jer je to poanta formatera - da neku jednostavnu vrijednost lokalizira ili na drugaciji nacin prilagodi korisniku.

Sta se onih gore divova tice, pricamo o generatoru. Output nije crveni div, ili plavi div. Output je div, a background boja je po specifikacijama vec property diva bez obzira na tvoj kod, jednako ka visina ili sirina. Ako pricamo o generator funkcijama, onda svi propertyi koji mogu bit dio rezultirajuceg objekta (required i optional parametri), su ili dio konstruktora klase, ili imaju svoje settere koji vracaju punu vrijednost objekta, ili, ako vec zelis napisat to u obliku funkcije, idu kao argumenti funkcije.

I sad kad moras odlucit kako zelis napisat svoj generator divova, koristis common sense valjda.
Sto ti se cini kao citljiviji kod, ovo:
interestingDiv = createDiv('100px', '500px', null, null, '#c3c3c3', '#fff', 'left', 'col-sm-6', null, null, null, null, 'Roboto')

ili ovo:
interestingDiv = createDiv() .setHeight(100px) .setWidth(500px) .setBackgroundColor(#c3c3c3) .setColor(#fff) .setFloat('left') .setClassNames('col-sm-6') .setFont('Roboto')

Dakle ok, neko je krenio pisat div generator samo sa width i height. I to je okej. Ali onaj ko je isa na to “nadogradit” funkciju, i samo je poceo dodavat parametre u funkciju, je napravio to iz ciste lijenosti, i stvorio uzasnu funkciju koju triba zapalit.

I samo da se referenciram na samo jos jednu tocku - ne, kod ne triba bit user friendly u smislu da mozes bilo sta turnit ko input metode. To je uzasno programiranje koje vodi bugovima, i izrazito teskom odrzavanju kasnije. Kod mora bit user friendly u smislu citanja i lakog razumijevanja (ie, da samo po imenu metode znas sto ona radi, bez da ides citat njen kod), i kod mora bit sto jednostavniji za debugiranje.

1 Like

Naravno da izmišljam primjere…jer si se ti uhvatio prvog primjera kao da o tome pričamo. Ali ne pričamo o tome! Nebitan je i shortName…nebitan je i redDiv i yellowDiv …zato nema smisla tumačiti niti jedno od toga pojedinačno.

Ja bacam primjere samo da potkrijepim prvotnu tezu da postoje slučajevi kada trebamo extendati funkcionalnost neke funkcije koja je ograničena prvotno postavljenim ulaznim parametrina. Naravno da istoj ne narušimo postojeću funkcionalnost.

Pazi, ja sam se od starta s tobom složio da postoje slučajevi kad treba graditi novu metodu. To nisam uopće osporavao.
No temu sam počeo za onaj drugi slučaj kad želimo malo customizirati rad već postojeće metode, a da ne narušimo “Backwards Compatibility”.
Ako ti tvrdiš da se nikada metoda ne updejta po novonastalim potrebama, onda naravno da ću ti izvući primjer koji pokazuje da ponekada je ipak bolji odabir updejtat funkciju.

A ovo što želim pokazati je zapravo toliko banalno, da nam je rasprava pomalo smiješna.

Sto ti se cini kao citljiviji kod, ovo:
interestingDiv = createDiv('100px', '500px', null, null, '#c3c3c3', '#fff', 'left', 'col-sm-6', null, null, null, null, 'Roboto')

ili ovo:

interestingDiv = createDiv()
.setHeight(100px)
.setWidth(500px)
.setBackgroundColor(#c3c3c3)
.setColor(#fff)
.setFloat('left')
.setClassNames('col-sm-6')
.setFont('Roboto')

Nijedno. Iako ovo drugo može proći. Ali elegantnije mi se čini (i daleko češće srećem) …ovako:

	interestingDiv =createDiv({
		height:'100px',
		width:'500px',
		backgroundColor:'#c3c3c3',
		color:'#fff',
		float:'left',
		classNames:'col-sm-6',
		font:'Roboto'
		})

Na tu ideju se i svodi ova tema. Ako postoji više parametara koje ćemo prosljeđivati funkciji, treba ih prosljeđivati kroz assos_array kako bi bili dohvatljivi po ključu. (imenu).
Sada se jednostavno unutar funkcije poigrati sa malo logike…te po želji i potrebi izvrtiti drugačiju logiku ukoliko su nam neki parametri stigli…a neki nisu…

Ukolik imamo situaciju da je neka funkcija zadana kao gornji createDiv(width,height) , ne moramo ju nužno zapaliti …nego ju lako prilagodimo radu sa assoc_array parametrom…i voila…sve radi.
Naravno, ovako nešto createDiv(width,height) bi i ja zapalio…ali u praksi, nekada je korisno da istoj funkciji možemo zadati parametre na način someFunk(a,b,c) …i na način someFunkc({…})…ili na način someFunkc(a,b,c,{…})
To dođe vrlo praktično ako su u 95% slučajeva jedino potrebni a, b, c za rad te funkcije…a samo u 5 posto slučajeva trebamo dodavati optionalne parametree…

Proslijeđivanje objekta parametara u gornjem slucaju je skroz okej rjesenje za taj konkretni slucaj; programer XY zna da objekt ocekuje css parametre, a od web developera ocekujes da zna sto je u tom slucaju validan parametar, a sto nije. I to su sve parametri koji se jednostavno primjene na objekt, bez ikakve business logike iza slanja parametra i podizanja kompleksnosti funkcije. Dakle OK.

Međutim, moras bit svjestan limitacija takvog pristupa u nekakvom opcenitom primjeru. Odmah u glavu, linter se nece bunit ni da posaljes { float: undefined }, ili { 15 }, ili { data: null, error: PERMISSION_DENIED }. Funkcija ocekuje objekt, dobila je objekt. Stack trace ti nece pokazat problem u liniji koja poziva funkciju, nego ce ti negdje unutra na nekoj liniji koja pokusava dohvatit property, length, whatever, izbacit nekakvu opskurnu undefined is not a function, i tako tebe natjerat da console.log-as liniju po liniju pokusavajuci shvatit gdje je problem, da bi shvatio da problem uopce nije u toj funkciji. Kriterij dobrog programiranja nije (samo) da stvar radi.
Sto bi znacilo da bi ti u svim funkcijama kojima tako saljes objekte trebao pisati validaciju ulaznih parametara, sto je recimo u ovom slucaju poprilicno naporan proces.

Drugo, sasvim je ocekivano da se svejedno pojavi potreba za public setterima takvog objekta; ie, iz vana negdje zelis samo background color promijenit. Okej, mozes mu samo poslat { backgroundColor: user.settings.getPreferedBackgroundColor(); }, ali imat setter metodu znaci znat tocno gdje je stvar puknila, ili koju liniju koda treba promijeniti kad se zahtjevi promijene, jer opet, kad stvar pukne, tebi ce javit unutar metode neku liniju koja je pukla - neces imat pojma da je pukla jer poziv na endpoint koji dohvaca user settingse je dobio undefined vrijednost na user background color, i krenut ces debugirat poziv funkcije na skroz desetom mjestu, tamo gdje kreiras div ili nesto deseto.

Al da se vratim na originalni post:

Razlog sta san uopce ista pisa tu je sto je ovo opasan stav. Ako je funkcija kompleksna dovoljno da instant (da naglasim - INSTANT, samo ovlas pregledom) nije jasno sta se tocno tu događa, to ne samo da znaci da je ne smis cinit jos kompleksnijom, nego znaci da je vec problem i da je treba refaktorirati, napisati jednostavnijom, razbiti, whatever.

1 Like

Mozda nije prava tema, ali ne da mi se otvarati novu.

Koliko vas je pocelo koristiti ECMAScript 6 ? Meni kao pocetniku izgleda dosta jednostavnije od ES5, nekako lakse za citati i shvatiti.

Pored svega toga dosle su neke stvari koje se nisu nalazile u ES5.

Edit: Vidim da je i ES7 na pomolu :smile:

ES2015 a ne ES6 :smile: Promjenili su ime u zadnji tren.

Igram se pomalo već odavno. Puno toga je novo i specifikacija je masivna(oko 600 stranica). Od ove godine će JS imati godišnji release cycle ES2016, ES2017 itd. Moj savjet prvo ES3 i ES5 pa tek onda ES6. Puno toga je novo i osobno će mi trebati godine da to sve proučim u detalje.

Poceo sam se i ja igrati sa ES2015, jer moram kuckati JS-u u njemu i cini mi se jako OK, jedan banalan primjer koji sam koristio za vjezbu.

'use strict';

class Car {

	constructor(brand,model,year) {
		this.brand = brand;
		this.model = model;
		this.year = year;
	}

	toString() {
		return `
			<h2>${this.brand}</h2>
			<p>This is ${this.model} from ${this.year} year.</p>
		`;
	}

	print() {
		const wrapper = document.getElementById('wrapper');
		wrapper.innerHTML += this.toString();
	}
}

const bmw = new Car('BMW', 'e46', 2005);

bmw.print();

Izgleda prilicno objektno-orijentirano ali u teoriji nije.

Ima tu jos stvari dosta stvari koje nisam koristio, kao sto su arrows, rest and spread, default parameters, moduli etc.

@bozoou sorry za off-topic, otvaranje nove teme je besmisleno, jer vjerovatno niko ne bi nista napisao.Sta mislis ti o ES2015, koristis li ga, ili si jos na ES5 :slight_smile:

Iskreno, nisam se ni sreo s tim pojmovima…

function sum(...numbs) {
	
	return numbs.reduce((prev, current) => prev + current );

}

console.log(sum(3,5,7,39,15));

Po meni jedna jako korisna stvar us ES2015, rest parametar, funkcija moze primiti koliko hoces vrijednosti, bez dodavanja u ovom slucaju 5 argumenta.

Pored toga u ovom primjeru je demonstirana i arrow sintaksa koja mi se isto dopada.Ukoliko je single vrijednost unutar funkcije onda mozes ici bez zagrade, a return keyword se podrazumjeva tako da se ne mora ni pisati.

return numbs.reduce( prev => this.prev );

Nesto tako npr.Dosta je tu korisnih stvari koje mi se dopadaju, i lakse su mi citljive.

Nije sve u sintaksi. Arrow funkcije imaju i neke druge stvari koje nisu iste kao kod standardne function a(){} sintakse(npr. leksički this binding). Ako nisi upoznat istrazi to malo.
Ja više volim staru sintaksu gdje vidim return keyword. Taj return me podsjeća na izlazak iz funkcije i čitljivije mi je nekako.

Nisam upoznat, jer prije 2-3 dana sam poceo da kopam po ES2015, pogledati cu svakako.

Sto se tice return keyworda, meni ovo izgleda OK, jer cim vidim arrow u kodu i bez return keyworda znam o cemu se radi.Mada moze se korisiti i return, kod ce i dalje normalno raditi.

Zgodna stvar su i moduli, ali mora se koristiti neki module bundler, poput webpack, jer nisu podrzani nativno u browserima.


Copyright © 2020 WM Forum - AboutContact - Sponsored by: Mydataknox & Profit Monkey