Code Reviews: Pogosti viri skrajnih kršitev in kako se izogniti argumentom o njihovem popravljanju

Noži se vlečejo. Rezila so zaostrena zaradi konfliktov. Med razvijalci divja spor. Strasti kodrov se vnamejo ne nad hroščečo programsko opremo, temveč nad skrajno jedrnato ali dobesedno kodo. Te vrstice so znaki kramp. Vsak programer, ki se ne strinja, je ljubitelj. Samo neofit bi ustvaril metode in bloke, ki tako jasno kršijo dober okus. Kljub temu so različni preferenci in ne naravni zakoni izvor tega konflikta in vitriola. V tem primeru je sovraštvo med razvijalci posledica različnih nagnjenj k trgovanju s sukcetnostjo za različne namene. Ti cilji in težnja po njih so pri vsakem razvijalcu različni, kar vodi v nenehne konflikte na določenih področjih. Eden takšnih mest je besedna ali nesnažna koda. Da bi zmanjšali boj, lahko ekipa s pomočjo pregledov kode poudari najbolj zamerljive segmente, skupina pa se lahko prereka nad temi deli, namesto da bi se prepirala po vsaki vrstici in bloku osnove kode.

Nekatere konstrukcije kode ali tehnike verjetno povzročijo skrajne kršitve in vodijo argumente o popravljanju teh kršitev. Odpravljanje teh zlorab vodi do intenzivnih prepirov. Ta nesoglasja se lahko razrešijo ali vsaj opredelijo za posebne spodaj navedene jezikovne značilnosti in tehnike.

Pogojni operater vs. če izjava

Jezikovni elementi, pogojni operater in if-izjava, vodijo v argumente, z različnimi taborišči pa trdijo, da je vsaka superiorna tehnika za določene operacije. Te ukrepe je mogoče izvajati na nešteto načinov, vsaka tehnika pa prinaša prednosti in slabosti.

If Statement: Stavek if lahko prispeva k grozljivo obsežni kodi, ko je gostota pogojev visoka. Zaradi velike gostote se blok ali metoda zdi zabuhla. Kljub temu pa je koda, napisana z if-izjavami, prav tako zelo zanemarljiva, saj lahko razvijalci prestopijo skozi vsako vrstico.

če (label1IsRequired) {
 label1.Color = "rdeča";
} else {
 label1.Color = "črna";
}
če (label2IsRequired) {
 label2.Color = "rdeča";
} else {
 label2.Color = "črna";
}
če (label3IsRequired) {
 label3.Color = "rdeča";
} else {
 label3.Color = "črna";
}

Pogojni operater: Pogojni operater lahko pripelje do nekaterih nevtraliziranih črtah, ko je bil nadomeščen za več stavkov-if. Vgrajeni pogojni operaterji naredijo kodo do skrajnosti težko branje, preizkušanje ali odpravljanje napak. Vsak blok ali metoda, ki je težka za pogojne operaterje, je tudi zelo kompaktna, saj zmanjša količino kode, ki jo mora razviti razvijalec.

healthIndicatorColor = (zdravje == "Dobro")? "Zelena": (zdravje == "Pošteno")? "Rumena": (zdravje == "slabo")? "Rdeča": (zdravje == "življenjska podpora")? „Oranžna“: „vijolična“;

Potencialna ločljivost: Pogojni operaterji so koristni, kadar nadomestijo veliko gostoto vrednosti, ki je določena na podlagi pogojev, izvedenih s pomočjo if-stavkov. Pogojni operaterji so destruktivni, ko nadomestijo celo par odločitev, vgrajenih drug v drugega. Imperativ, ki se lahko čitljivo prilega v eno vrstico, je glavni cilj za pogojne operaterje, medtem ko so pogoji, ki zahtevajo več vrstic, domena stavkov-stavkov. Vsako gnusno uporabo if-izjav ali pogojnih operaterjev je treba popraviti, da se uporabi ustrezna uporaba enega od teh konstrukcij. (Opomba: Za spremembo je morda potrebno znatno ponovno nameščanje.)

če (zdravje == "dobro") {
 healthIndicatorColor = "zelena";
} else if (zdravje == "Pošteno") {
 healthIndicatorColor = “rumena”;
} else if (zdravje == "slabo") {
 healthIndicatorColor = "rdeča";
} else if (zdravje == "life_support") {
 healthIndicatorColor = "oranžna";
} else {
 healthIndicatorColor = "vijolična";
}
label1.Color = (label1IsRequired)? „Rdeča“: „črna“;
label2.Color = (label2IsRequired)? „Rdeča“: „črna“;
label3.Color = (label3IsRequired)? „Rdeča“: „črna“;

Več izjav o vračilu v primerjavi z eno izjavo o vračilu

Dva posebna sloga, ki vodijo do argumentov, sta več vrnitev in enojna vrnitev. Pojavijo se nesoglasja glede tega, ali bi morale biti metode ena povratna izjava ali je sprejemljivo več izjav. Vsak pristop ima pozitivne in negativne učinke.

Več izjav o vračanju: Izjave z več povratnimi podatki lahko prispevajo k kodi, ki jo je težko razumeti, slediti in preizkusiti. Vendar so metode z več povratki lahko krajše od funkcij z enim povratkom.

SomeDataType nekiMethod (param1, param2, param3) {
 RetVal SomeDataType;
 če (param1 == null) {
 retVal = ničelna
 }
 če (retVal == null) {
 povratni retVal;
 }
 
 če (param2! = null) {
 retVal = param2;
 }
 če (retVal.Equals (param2)) {
 povratni retVal;
 }
 
 retVal = param3;
 povratni retVal;
}

Ena izjava o vrnitvi: Ena sama izjava o vrnitvi lahko vodi do dolgih metod. Vendar imajo ti postopki en izhod, kar poenostavlja testiranje in odpravljanje napak.

SomeDataType someMethod () {
 RetVal SomeDataType;
 // Koda sto ali tisoč vrstic
 povratni retVal;
}

Potencialna ločljivost: Večkratna vrnitev otežuje razumevanje, sledenje in preizkušanje kode, kadar se uporabljajo nedosledno. Posamezni povratni stavki vodijo do dolgih metod, ko jih nadaljujejo dolgi raztezki kode. Te izvlečene razmike lahko skrajšate ali vsaj naredite berljive z uporabo več povratnih stavkov namesto enega. Ko sledijo kratkim oznakam kode, so enotne povratke povsem sprejemljive. Vsako očitno zlorabo posamezne izjave o vračanju ali več vrnitev je treba odpraviti, če želite uporabiti primere uporabe enega od teh slogov. (Opomba: za popravek bo morda potrebna pomembna ponovna faktoringa.)

SomeDataType nekiMethod (param1, param2, param3) {
 če (param1 == null || param3 == null) {
 vrniti ničelno;
 }
 
 SomeDataType retVal = null;
 če (param2! = null {
 retVal = param2;
 } else if (param1! = null) {
 retVal = param1;
 } ele if (param3! = null) {
 retVal = param3;
 }
 povratni retVal;
}
SomeDataType nekiMethod (param1, param2) {
 SomeDataType retVal = null;
 za (int i = 0; i  if (param1 [i] .equals (param2)) {
 retVal = param1 [i];
 odmor;
 }
 }
 povratni retVal;
} Prekinitev in nadaljevanje uporabe v zankah

Konstrukti o prekinitvi in ​​nadaljevanju so predmet intenzivnih razprav. Na eni strani argumentacije razvijalci trdijo, da lahko prekinitev in nadaljevanje poenostavijo nadzorni tok. Drugi programerji trdijo, da te funkcije zapletajo logiko programa. Odmor in nadaljevanje se zagotovo lahko uporabi za poenostavitev ali zapleteno kodo. Te vrstice je mogoče opaziti.

Prekinitev in nadaljevanje uporabe: Elementi lahko poenostavijo kodo, vendar jih lahko tudi nepotrebno zapletejo.

SomeDataType nekiMethod (param1, param2) {
 SomeDataType retVal = null;
 za (int i = 0; i  če (param1 [i] == null) {
 nadaljujte;
 }
 if (param1 [i] .equals (param2)) {
 retVal = param1 [i];
 odmor;
 }
 }
 povratni retVal;
}
SomeDataType someMethod (podatki, param1) {
 SomeDataType retVal = null;
 naredi kaj:
 za (int i = 0; i  če (i> = data.length) {
 odmor;
 }
 if (podatki [i] .equals (param1)) {
 retVal = podatki [i];
 } else {
 nadaljujte;
 }
 }
če (retVal == null) {
 podatki - refreshData ();
 goto dosomething;
 }
povratni retVal;
}

Potencialna ločljivost: Večina razvijalcev trdi, da bi koda morala uporabljati preproste mehanizme za nadzor pretoka. Kateri konkretni mehanizmi so preprosti, je vir razprave. Ta argument postane veliko manj vroči, ko se vsak instrument uporablja na splošno sprejetih načinih. Sprejeti pristopi obstajajo za prekinitev in nadaljevanje. Držite se teh konvencij, da preprečite nesoglasja in poenostavite nadzor pretoka. Vsako sredstvo nadzora, ki hudo krši te standarde, je treba brez razprave popraviti.

SomeDataType someMethod (podatki, param1) {
 SomeDataType retVal = null;
 za (int i = 0; i  če (podatki [i] == null) {
 nadaljujte; // preskoči preostanek zanke
 }
 if (podatki [i] .equals (param2)) {
 retVal = podatki [i];
 odmor; // ne več zanke, ki sem ga naredil
 }
 }
 povratni retVal;
}

Obrambne izjeme

Izjeme so sredstvo za prikaz težave ali preprečitev prihodnje težave. Katere glavobole je treba opozoriti ali jih odpraviti, kateri deli kode so tema ostre razprave. Na enem koncu nesoglasja šifranti trdijo, da prodorne obrambne izjeme preprečujejo napake in jih olajšajo. Kljub temu pa nekateri obrambni seznami obrambe lahko postanejo šibkejši in težko razumljivi, kot trdijo nekateri programerji. Razvijalci na obeh straneh razprave imajo poanto. Obrambne izjeme imajo koristi in škodo.

Koristi in škode obrambnih izjem: Zaščita pred napakami in drugimi težavami se lahko zaščiti z minimalnimi pomanjkljivostmi z uporabo izjemnih izjem. Te pomanjkljivosti se povečajo, ko je tehnika nerazločljiva.

void someMethod (param1, param2) {
 če (param1 == null || param2 == null) {
 vrgel novo ArgumentNullException ("manjka eden ali več parametrov");
 }
 // delati stvari
}
void someMethod (param1, param2) {
 // na desetine vrstic obrambnih pregledov… ..
 // narediti ostalo metodo
}

Potencialna ločljivost: Pomanjkljivosti obrambnih izjem so najmanjše, če se uporabijo v sprejetih navadah. Vsako uporabo tehnike, ki odstopa od teh konvencij, je treba popraviti, razen če ni naveden prepričljiv razlog.

javna void someMethod (param1, param2) {
 // preveri vsak parameter v javni metodi
 če (param1 == null || param2 == null) {
 vrgel novo ArgumentNullException ("manjka eden ali več parametrov");
 }
 
 // odpraviti težave, ki jih povzročajo neveljavni podatki
 if (! isValid (param1) ||! isValid (param2)) {
 vrzi novo InvalidParameterException ("Eden ali več parametrov ni veljaven");
 }
 
 // narediti nekaj s parametri
}

Zaviti

Te konstrukcije kode in tehnike uporabljajo tako dobri kot slabi razvijalci. Programerji so ljudje. Človeška bitja so nagnjena. Ti nagibi se kažejo v kodi. Občasno ga spodbudi razvijalec, da napiše kodo, ki jo drugi kodirniki upravičeno kritizirajo. Razvijalec, ki je steber, ni nujno slab programer. Koder, ki ga kritizira, ni nujno dober razvijalec. Obe osebi sta verjetno v nekem trenutku zmedeni po svojih željah. Te želje ne bi smele voditi k razvoju, da bi se stopil v neskončen tok žalitev. Namesto tega bi morali programerji medsebojno pregledati kodo, omejiti svoje bitke na najslabše odseke in se strinjati, da določene argumente poravnajo s pomočjo zgoraj določenih pravil.