Ny artikel ute nu, diskutera gärna om den här. Om ett språk har stöd för Design by Contract, när utförs Require- och Ensure-villkoren? Är det vid kompileringen eller vid exekveringen? Då blir det mycket extra kod som körs. Det vore bättre att köra sådana kontroller redan vid kompileringen. Visst hade det fungerat om du kunde förutsäga precis alla tänkbara värden som kan komma att skickas in. I vissa fall kanske man kan, men majoriteten av värden skulle jag säga är okända vid kompilering <b>majoriteten av värden skulle jag säga är okända vid kompilering</b> Jag har förslag på svenska ord för precondition och postcondition: previllkor respektive postvillkor. Det låter som en blandning av latin och svenska... För- och eftervillkor skulle vara en mer fullständig översättning av termerna. Jag har en kommentar om det sista exemplet i artikeln (där du skulle visa två knappar baserat på en Arrays totala antal poster). Jag är en vän av tydlig och lättläst kod, men håller inte med om att lösningen med en if-sats är tydligast. Problemet är att den innehåller liknande kod två gånger i onödan, dvs. metodnamnet SetArrowButtonsEnableMode. I det utökade exemplet med två metodanrop är det ännu tydligare, där är inte bara metodnamnen upprepade i onödan, utan även parametervärdena true och false. Jag tycker att prefixen "pre" och "post" är vanliga nog i svenskan för att fungera utmärkt även för nya ordbildningar (några exempel: prefix, prejudikat, preliminär, prenumerera, postmodernistisk, postoperativ, postum). Förvillkor och eftervillkor är också bra förslag som fungerar. Men får jag välja så föredrar jag "pre" och "post" eftersom orden då liknar de engelska motsvarigheterna mer. Bra artikel, men angående "SetArrowButtonsEnableMode", och if-satserna, så finns det ju ett annat sätt att lösa det på, genom att använda en separat variabel för det. <b>prefix, prejudikat, preliminär, prenumerera, postmodernistisk, postoperativ, postum</b> Jag håller med Jens och Niklas om detta med if-satser och undrar om verkligen Aha, så om man vill vara konsekvent latininspirerad så är det "prekondition" och "postkondition" som gäller. Det låter inte som några speciellt bra varianter. "Kondition" i betydelsen "villkor" är ju inte så vanligt förekommande. Du har övertygat mig Per, förvillkor och eftervillkor är de bästa orden. En snabb google-sökning visar även att dessa former är vanligare än pre/post-varianterna. Nu skall jag svara lite här :-) Jens, EDIT!!!! <b>Jag frågade om vi var i en testmiljö och fick ja till svar. Så jag skrev med glädje in ’—som lösen. (PLEASE Don’t try this At home ;-) ) och bad honom köra detta. Inget speciellt hände så jag hånades lite. Dock ringde support efter fem minuter och undrade varför inga kunder kunde logga in. Per, Vilka synpunkter har ni på följande... Det behövs ingen else-gren. Jag tycker att det ser bäst ut med felhanteringarna som egna satser och huvudkoden för sig: I och med att båda fallen är var sin typ av return så känns det ganska egalt. Men om det istället hade varit en return och en kodsnutt med lite annat, så känns det för min del rätt att man sätter returnen först. För skojs skull valde jag en godtycklig fil ur källkoden för Linux (http://lxr.linux.no/source/fs/namespace.c). Där blandas olika stilar.Strukturera din kod.
http://www.pellesoft.se/area/articles/article.aspx?artid=898
Mvh JohanSv: Strukturera din kod.
Sv: Strukturera din kod.
Sv:Strukturera din kod.
Sv: Strukturera din kod.
Jag håller med men det är inte det jag talar om. Om värdena skulle vara kända, skulle det vara ännu bättre eftersom kompilatorn skulle kunna optimera koden på ett annat sätt.
Vad jag menar pratar om är att de flesta (dock inte alla) villkor som skall gälla för indata skulle kunna uttryckas med datatyper och därför skulle kunna testas av kompilatorerna.Sv: Strukturera din kod.
/ JensSv:Strukturera din kod.
Sv: Strukturera din kod.
Det jag tycker är dåligt är inte i första hand att upprepningarna ger mer kod. Det större problemet är att det är svårt för läsaren att se om det verkligen är fråga om en upprepning. Det kanske står "SetArrowEnableMode" i det ena fallet och "SetArrowDisableMode" i det andra. Ett vanligt misstag när man ska göra utökningen till två metodanrop är att skriva metodanropet för det första fallet och sedan använda copy-paste till det andra fallet men att då glömma att ändra false till true. Man får då följande felaktiga kod, och det kan vara svårt att upptäcka:
if(listMenuItemContainer.Count == 0)
{
SetArrowButtonsEnableMode(false);
SetEditButtonsEnableMode(false);
}
else
{
SetArrowButtonsEnableMode(true);
SetEditButtonsEnableMode(false);
}
Jag skulle därför rekommendera din kollegas variant och om sanningsvärdet ska användas till flera saker skulle jag använda en variabel för att spara värdet. Så här:
boolean gadgetsEnabled = (listMenuItemContainer.Count == 0);
SetArrowEnableMode(gadgetsEnabled);
SetEditButtonsEnableMode(gadgetsEnabled);
/ JensSv: Strukturera din kod.
/ JensSv: Strukturera din kod.
typ (i c++):
bool ArrayIsEmpty = (listMenuItemContainer.Count == 0);
SetArrowButtonsEnableMode(ArrayIsEmpty);
SetEditButtonsEnableMode(ArrayIsEmpty);
på så sätt får man ju kort kod för en löjligt enkel operation, och ser samtidigt tydligt vad som händer.Sv:Strukturera din kod.
I dessa exempel är även stammen av latinsk härkomst, till skillnad från i fallet pre-/postvillkor.Sv:Strukturera din kod.
private bool IsSeatFull()
{
if(this._seats.Count < 250)
return ( true );
else
return ( false );
}
skulle vara mer lättläst än
private bool IsSeatFull()
{
return (this._seats.Count < 250);
}
Detta för tankarna till http://thedailywtf.com/ShowPost.aspx?PostID=27003
Sv: Strukturera din kod.
/ JensSv: Strukturera din kod.
Kul att det pratas om detta, det var mitt mål.
Först, kod kan skriva på flera olika sätt, vi har olika dialkter och tolkar koden efter hur vi själva oftast är vana att läsa den. Vi kan ta exemplet:
<code>
if(this._seats.Count < 250)
return ( true );
else
return ( false );
</code>
man kan visst i detta fall skriva
<code>
return(this._seats.Count < 250);
</code>
Jag valde här att inte göra så för att förtydliga för andra mitt konditions resultat. Temporära variabler hade jag oxå kunnat använda mig av, dock blir det lite jobbigt att ta med alla olika exempel i texten, jag var tvungen att välja ett och tog det som ni alla läste lika snabbt som jag :-)
Fördelen är att ni tom snabbt hittade sätt att effektivisera den, vilket är tecken på att det faktiskt var lättläst och ni hajade direkt hur man ev kunde skriva det på färre rader, det är just vad jag även talat om att se detta är tecken på självskrivande kod.
När jag valde att skriva artikeln var tanken att även ha koden så lättläst som möjligt så man inte slapp använda huvudet för mycket för att se att detta kondition ger en true eller false. Vill man veta varför dessa svar kan man efter hand läsa det kondition jag har. Och vill man minimera antal rader så är det frivilligt, men se då till att utökningen av koden oxå sker med samma omsorg så det inte blir som jag sa i sista delen risk att man av lathet placerar kod som inte hör hemma i den metod i just den metoden för att slippa ändra den syntax man hade innan.
Jag håller med om att
<code>
return(this._seats.Count < 250);
</code>
eller mitt Arrow ex hande sett snyggare ut på detta sätt än på det sättet jag gjorde.
Nu är det ju så att
<code>
return(this._seats.Count < 250);
</code>
behöver läsas för att först dess kondition. 250 är ett magiskt nummer som jag egentligen inte hade satt på detta sätt heller om jag hade gjort en verklig kod utan satt den i variabel. Vilket skullr kräva mer tanke o ev kankse tom hoppande i koden för att förstå den. Vi pratar om pytte pytte lite tid och inte alls så mycke hjärnarbete men har man redan en massa i huvudet kan man lätt tappa bort sig. Och om konditions i andra exempel skulle vara större än dessa jag har i artikeln så är det extra viktigt att behöva använda hjärnan så lite som möjligt och bara visa det som är direkt viktigt att se.
Kom även ihåg, jag säger inte man skall skriva på detta sätt, bara att det kan ge mer förtydligande och minimera risken att slarva. Det viktiga är att ni skriver kod för att ni själva efter några månader eller kanske tom nått år skall komma ihåg vad ni gör och varför men även att andra som inte ens sett er kod lätt skall förstå den, det är viktigare än att hålle nere en rad eller två och ju fortare man kan läsa rutinerna och ju mer man måste beräkna i huvudet ju snabbare kan man sätta sig in i den och hitta fel eller brister.
Detta är bara exempel inte kod i verkliga livet, sådan kod skulle absolut se tyngre ut än de få rader jag tog med, syftet var att visa en bild där man snabbt kunde hitta fel eller förstå vad som sker och kanske to m hitta andra sätt att effektivisera rutinerna utan att behöva tänka för mycket oavsett om de är på flera rader och eller flera konditions.
Mvh JohanSv:Strukturera din kod.
Absolut. Det går alltid att effektivisera kod.
Jag skulle dock inte ha med både Enable och Disable i metodnamn utan hålla mig till en o samma namnstandard gällande detta i hela min kod. Detta för att minska det missförstånd du faktiskt tar upp om en metod hette Diasable o en annan Enable... Till strukturerad kod ingår ju självklart en gudieline där man tydligt inom organisationen gör klart för sig att Enable är det vi använder och aldrig anger en Disable metod utan ser till så vår Enable tar false i så fall.
Exmeplet med en temporära variablen fungerar kanon. Men det kanske inte förtydligar rutinens berättelse i alla lägen? med andra lägen syftar jag på mer avancerad kod än de enkla exempel jag tog med för att bara visa lite hur tankarna existerade kring dem.
Tänk dig en IsSeatFull metod av detta metodnamn förväntar du dig säker att en kontroll sker som kollar om sätet är fullt eller ej. I vårt huvude ställer vi oftast automatiskt en if (om) fråga. Att då använda if i koden kan ge bättre förståelse än att undvika dem genom en temp variabel, att läsa koden som en berättelse hur vi skulle tänka oss den efter dess metodnamn, ger oss mer lättläst kod även om rader kod kan bli lite fler. Undan tag finns ju alltid dock.
<code>
public bool IsSeatFull() 'Är sätet fullt?
{
if(seats.Count < 250) 'om sätet är mindre än 250
return ( true ); ' ge sant
else 'annars
return ( false ); 'ge falsk
}
</code>
eller:
<code>
public bool IsSeatFull() 'Är sätet fullt?
{
bool seatsFull = seats.Count < 250; 'sätet sätts till nått om dess antal är mindre än 250 annars nått annat.
return ( seatsFull ); 'returnera något.
</code>
Andra exemplet må se bättre ut, men är det lika självförklarande som första? svaret är ja, men
vilket förstår man fortast och vilket tänker man mist på? nu är blir det någon nano sekund här, men rutinen hade kunnat vara mer komplex. I första exemplet ser du nästan bara att titt apå det att nått kommer ge true eller false men i det andra ser du inte lika fort var du förväntar dig att ge i retur. I andra exmeplet är < mer intressant än if och elsen. Det hade ju lika gärna kunnat stå !< vilket du kanske måste läsa i ex två men som du inte behöver ta hänsyn till i ex ett då du bara är intresserad av att snabbt hänga med vad som häner och kanske snabbt även kunna lägga till en händelse vid false eller true utan att behöva kolla seatFull i ex två för att lägga till ett annat undantag.
Meningen med sista stycket (vilket jag troligen inte fick fram så tydligt) var att egentligen visa att det allternativ jag tog upp kan minimera risken till att spagettikod kan komma till i framtiden...
Att du som utvecklare kanske har en rutin som är god säger inte att någon annan som tar över koden kanske har samma rutin. I min kod har jag mer eller mindre _tvingat_ nästa programmerare att lägga ny kod i if eller else scopet. En mindre erfaren och ostrukturerad kodare hade kanske som jag skrev lagt koden i metoden som tog booleanvärdet och hårdkopplat den till nått annat och börjat skapa spagettikod för att han/hon inte vill ändra den rutin som redan finns där. Om alla i organisationen skriver på exakt samma sätt och är lika rutinerade hade jag lätt gjort på ditt sätt. I mitt fall ang sista stycket var jag på ett konsultuppdrag där jag inte riktigt hade koll på hur de oliak skrev sin kod och vilka eller vem som skulle underhålla den, då kändes det lättare att förtydliga det hela. För jag skrev koden för andra inte för mig... Kanske är fel att tänka så? när jag skriver kod till andra jag inte känner till dess skrivsätt eller dialekt skriver jag koden mer som om det var för ett barn än för en vuxen för jag vet att både ett barn och en vuxen skulle förstå den.
några synpunkter på detta?
Mvh JohanSv: Strukturera din kod.
Har ändrat en del i sista delen av min artikel då jag kände att jag inte förtydligade exakt hur jag tänkte eller tänker. För er som redan läst och inte orkar läsa igen har jag i princip lagt till följande.
När du skriver kod för några eller någon du inte känner till. Lätt hänt om man jobbar som konsult och är med en mindre tid i ett projekt där man int ehinner lära känna de andra utvecklarnas kunskaper.
Du vet inte om deras erfarenhet med kod, de vet inte om deras kunskaper i allmänhet. Då är det att föredra att skriva koden så enkel som möjligt som om man skrev för ett barn, då det är lättare för en mer oerfaren att läsa sådan kod än om den var skriven på ett strukturerat och effektiv sätt.
Vill sedan de som skall ta över koden effektivisera den så är det upp till dem.De ser lättare i sådan kod vart de kan effektivisera den, detta är tecken på att koden var eller är rätt självbeskrivande.
Så mitt sista stycke handlar om riskerna att effektivisera för mycket om man inte känner till vem det är som skall läsa koden eller ändra id den. Hoppas detta framgår bättre nu...
Några synpunkter?
Mvh JohanSv: Strukturera din kod.
Det visade sig att det inte alls var en testmiljö utan för honom var en testanvändare samma sak som något man kunde testa vad som mot utan fara. De tecken vi la in i passwordfältet dödade hela WHERE satsen i en då dynamiskt uppbygg sql-sats. Det hela ledde till att alla användare fick testanvändarens användarnamn och ett tomt lösenord.</b>
Var det en UPDATE-sats i stil med följande?sql = "UPDATE member SET username=" & username & ", password=" & password & "/* fler personuppgiftsfält */ WHERE id=" & id
Sv:Strukturera din kod.
Jepp. typ. :-)
Har justerat texten lite i artikeln för att förtydliga saker, sånt man alltid ser efteråt när fler börjar läsa och kommentera. Det är inte alltid lätt att få med allt på så få sidro då jag försöker pressa ner en hel vetanskap på några få :-)
Dels är det xmlBuildern som jag försökt förtydliga att detta är inget exempel man skall använda utan det viktriga är att förstå hur man får en användare att fatta hur man får fram reusltatet.
<code>
<data>
hej
</data>
</code>
Sedan om SetArrow... så handlar det mer om att försäka lägga det på en bra nivå så andra som tar efter ev jan justera detta på sitt sätt om man inte känner till deras kunskaper och hur de skriver sin kod. När det handlar om mer erfarna utvecklare som har god kodstruktur och design väljer jag oftast alltid att ha korta konditions som input om det inte fins fler undantag med dessa.
Mvh JohanSv: Strukturera din kod.
<code>
if(this.xmlStringBuilder != null)
return ( this.xmlStringBuilder.ToString() );
else
throw new Excpetion(“Couldn’t build string!”);
</code>
Har fått in lite tankar varför jag inte gör:
<code>
if(this.xmlStringBuilder == null)
throw new Excpetion(“Couldn’t build string!”);
else
return ( this.xmlStringBuilder.ToString() );
</code>
Jag har inget direkt svar på varför jag gjorde som jag gjorde mer än att jag i min postconditon (som detta fall handlar om) kollade det jag förväntade mig före det jag inte förväntade mig, kändes logiskt när jag snabbt skrev ihop exemplet. Jag brukar även av rutin att försöka ha med det jag förväntar mig vara rätt i if och det jag förväntar mig vara ett undantag i else, det kan vara en orsak till följande rader.
Vad har ni för synpunkter, vad är ni vana att göra? Sv:Strukturera din kod.
if(this.xmlStringBuilder == null)
throw new Exception(“Couldn’t build string!”);
return ( this.xmlStringBuilder.ToString() );
Sv:Strukturera din kod.
Då är det mindre sannolikt att göra fel även om man glömmer else-satsen (å andra sidan kan det då bli tvetydigt...).
Eller om man säger så här; jag använder i princip helst samma idé som krävs för rekursion, en return först, och det "viktiga" i funktionen sen. Men det innebär också att man tar hand om specialfallen först, och returnerar bort dem, så... tja... egentligen beror det ju på hur man förväntar sig att en kod ska fungera.Sv: Strukturera din kod.
Dels fanns den stil jag föreslog:
int may_umount(struct vfsmount *mnt)
{
if (atomic_read(&mnt->mnt_count) > 2)
return -EBUSY;
return 0;
}
static int do_umount(struct vfsmount *mnt, int flags)
{
struct super_block * sb = mnt->mnt_sb;
int retval;
retval = security_sb_umount(mnt, flags);
if (retval)
return retval;
/* flerradig kommentar bortplockad */
if (flags & MNT_EXPIRE) {
if (mnt == current->fs->rootmnt ||
flags & (MNT_FORCE | MNT_DETACH))
return -EINVAL;
if (atomic_read(&mnt->mnt_count) != 2)
return -EBUSY;
if (!xchg(&mnt->mnt_expiry_mark, 1))
return -EAGAIN;
}
...
Dels finns en annan stil:
struct vfsmount *alloc_vfsmnt(const char *name)
{
struct vfsmount *mnt = kmem_cache_alloc(mnt_cache, GFP_KERNEL);
if (mnt) {
memset(mnt, 0, sizeof(struct vfsmount));
atomic_set(&mnt->mnt_count,1);
INIT_LIST_HEAD(&mnt->mnt_hash);
INIT_LIST_HEAD(&mnt->mnt_child);
INIT_LIST_HEAD(&mnt->mnt_mounts);
INIT_LIST_HEAD(&mnt->mnt_list);
INIT_LIST_HEAD(&mnt->mnt_fslink);
if (name) {
int size = strlen(name)+1;
char *newname = kmalloc(size, GFP_KERNEL);
if (newname) {
memcpy(newname, name, size);
mnt->mnt_devname = newname;
}
}
}
return mnt;
}