You are on page 1of 30

CLEAN CODE 05

REINŽENJERING INFORMACIONIH SISTEMA


2
• Uvod
• Nazivi (Names)

• Metode/Funkcije (Functions)
• Komentari (Comments)
• Formatiranje (Formatting)

• Objekti i strukture podataka (Objects and Data Structures)


• Upravljanje greškama (Error Handling)
• Testiranje (Unit Tests)

• Klase (Classes)
• Code Smells

• Junit Internals (primer)


• Refactoring SerialData (primer)

Reinženjering informacionih sistema 2020/2021


3
Code Smells

Opšta pravila:

G24: Follow Standard Conventions


Ukoliko tim prihvati određene konvencije, npr. gde se navode varijable, kako se imenuju klase, toga
bi trebalo da se pridržavaju svi članovi tima. Ne bi trebalo da postoji poseban dokument koji
objašnjava koje konvencije se primenjuju, već bi to trebalo da bude jasno iz samog koda.

G25: Replace Magic Numbers with Named Constants


U većini slučajeva, upotreba brojeva u kodu nije poželjna. Imenovane konstante mogu dati kontekst
brojčanoj vrednosti. Broj 86400 možda nekome čini prvu asocijaciju na broj sekundi u danu, ali
nekome to možda neće biti odmah jasno tako da je NUMBER_OF_SECONDS_IN_DAY je svakako
jasnije.

Reinženjering informacionih sistema 2020/2021


4
Code Smells

Opšta pravila:

G26: Be Precise
Nije rešenje promeniti private na protected i public. Nije rešenje ne predviđati threads ukoliko se
mogu desiti. Ukoliko metoda može da vrati null vrednost, pokriti slučaj kada se vrati null vrednost…

G27: Structure over Convention


Neka dizajn bude zasnovan na strukturama ne na konvencijama. Konvencija imenovanja je dobra
polazna tačka, ali je mnogo bolje ukoliko postoji mogućnost da implementirate strukturu koja će tu
konvenciju sprovoditi. Ukoliko se koriste switch ili if izrazi, ne postoji način da se odredi kako će se
tačno koristiti, ali ukoliko osnovna klasa proširuje apstraktnu, onda je jasno određeno kako se mora
ponašati.

Reinženjering informacionih sistema 2020/2021


5
Code Smells

Opšta pravila:

G28: Encapsulate Conditionals


Bolje je kreirati metodu kao npr.
if (shouldBeDeleted(timer))

nego kombinovati više uslova


if (timer.hasExpired() && !timer.isRecurrent())

G29: Avoid Negative Conditionals


Trebalo bi izbegavati uslove sa negacijom. Takvi uslovi su često teže razumljivi.
if (buffer.shouldCompact())
if (!buffer.shouldNotCompact())

Reinženjering informacionih sistema 2020/2021


6
Code Smells

Opšta pravila:

G30: Functions Should Do One Thing


Metode bi trebalo da rade samo jednu stvar, ukoliko postoji funkcija koja radi više stvari, trebalo bi
je podeliti u više manjih funkcija od koji će svaka raditi po jednu stvar.

Reinženjering informacionih sistema 2020/2021


7
Code Smells

Opšta pravila:

G31: Hidden Temporal Couplings


Potrebno je ispoštovati redosled povezivanja objekata.

public class MoogDiver { public class MoogDiver {


Gradient gradient; Gradient gradient;
List<Spline> splines; List<Spline> splines;

public void dive(String reason) { public void dive(String reason) {


saturateGradient(); Gradient gradient = saturateGradient();
reticulateSplines(); List<Spline> splines = reticulateSplines(gradient);
diveForMoog(reason); diveForMoog(splines, reason);
} }
... …
} }
* Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship

Reinženjering informacionih sistema 2020/2021


8
Code Smells

Opšta pravila:

G32: Don’t Be Arbitrary


Struktura koda treba da bude organizovana na određen način sa razlogom i taj razlog treba da bude
jasan iz same strukture. Unutrašnja klasa ne treba da bude deo klase koja je ne koristi. Ukoliko će je
koristiti neka treća klasa, treba da bude javna i da se nalazi u odgovarajućem paketu.

Reinženjering informacionih sistema 2020/2021


9
Code Smells

Opšta pravila:

G33: Encapsulate Boundary Conditions


Granične slučajeve je ponekad teško pratiti. Potrebno je da se nalaze na jednom mestu, a ne da se
„šire“ po kodu.

if(level + 1 < tags.length) {


parts = new Parse(body, tags, level + 1, offset + endTag);
body = null;
}

int nextLevel = level + 1;


if(nextLevel < tags.length) {
parts = new Parse(body, tags, nextLevel, offset + endTag);
body = null;
}

Reinženjering informacionih sistema 2020/2021


10
Code Smells

G34: Functions Should Descend Only One Level of Abstraction


Iskazi napisani unutar metod treba da budu na istom nivou apstrakcije i jedan nivo ispod nivoa koji
je definisan nazivom metode.

public String render() throws Exception {


StringBuffer html = new StringBuffer("<hr");

if (size > 0)
html.append(" size=\"").append(size + 1).append("\"");
html.append(">");
return html.toString();
}

* Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship

Reinženjering informacionih sistema 2020/2021


11
Code Smells

public String render() throws Exception {


HtmlTag hr = new HtmlTag("hr");

if (extraDashes > 0)
hr.addAttribute("size", hrSize(extraDashes));
return hr.html();
}

private String hrSize(int height) {


int hrSize = height + 1;
return String.format("%d", hrSize);
}

* Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship

Reinženjering informacionih sistema 2020/2021


12
Code Smells

Opšta pravila:

G35: Keep Configurable Data at High Levels


Ukoliko u kodu postoje podrazumevane ili konfiguracione konstante koje se nalaze na visokom
nivou apstrakcije, nije poželjno sakrivati ih duboko u kodu.

public static void main(String[] args) throws Exception {


Arguments arguments = parseCommandLine(args);
...
}

public class Arguments


{
public static final String DEFAULT_PATH = ".";
public static final String DEFAULT_ROOT = "FitNesseRoot";
public static final int DEFAULT_PORT = 80;
public static final int DEFAULT_VERSION_DAYS = 14;
...
* Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship
Reinženjering informacionih sistema 2020/2021
13
Code Smells

Opšta pravila:

G36: Avoid Transitive Navigation


Ukoliko A zna za B, a B zna za C, A ne bi trebalo da zna za C. (Law of Demeter)

a.getB().getC().doSomething();

Reinženjering informacionih sistema 2020/2021


14
Code Smells

Java:

J1: Avoid Long Import Lists by Using Wildcards


Potrebno je izbegavati dugačku listu importa tako što će se koristiti wildcard (*).

J2: Don’t Inherit Constants


Nije poželjno konstante definisati u interfejsima i dobijati pristup konstantama nasleđivajući
interfejs.

J3: Constants versus Enums


Enums su uključeni u Javu sa razlogom, pružaju više mogućnosti od konstanti.

Reinženjering informacionih sistema 2020/2021


15
Code Smells

Java:

J3: Constants versus Enums


Enums su uključeni u Javu sa razlogom, pružaju više mogućnosti od konstanti.

public class HourlyEmployee extends Employee {


private int tenthsWorked;
HourlyPayGrade grade;

public Money calculatePay() {


int straightTime = Math.min(tenthsWorked, TENTHS_PER_WEEK);
int overTime = tenthsWorked - straightTime;
return new Money(
grade.rate() * (tenthsWorked + OVERTIME_RATE * overTime)
);
}
...
}
Reinženjering informacionih sistema 2020/2021
16
Code Smells

Java:

J3: Constants versus Enums


Enums su uključeni u Javu sa razlogom, pružaju više mogućnosti od konstanti.

public enum HourlyPayGrade {


APPRENTICE {
public double rate() {
return 1.0;
}
},

LEUTENANT_JOURNEYMAN {
public double rate() {
return 1.2;
}
},

Reinženjering informacionih sistema 2020/2021


17
Code Smells

Java:

J3: Constants versus Enums


Enums su uključeni u Javu sa razlogom, pružaju više mogućnosti od konstanti.

public enum HourlyPayGrade {



JOURNEYMAN {
public double rate() {
return 1.5;
}
},

MASTER {
public double rate() {
return 2.0;
}
};
Reinženjeringpublic abstract
informacionih sistemadouble
2020/2021 rate();
18
Code Smells

Java:

J3: Constants versus Enums


Enums su uključeni u Javu sa razlogom, pružaju više mogućnosti od konstanti.

public enum HourlyPayGrade {



public abstract double rate();
}

Reinženjering informacionih sistema 2020/2021


19
Code Smells

Nazivi:

N1: Choose Descriptive Names


Potrebno je birati nazive koji imaju smisla. Čitljivost koda u 90% slučajeva zavisi od pravila
imenovanja koja su primenjivana.

N2: Choose Names at the Appropriate Level of Abstraction


Nazivi ne bi trebalo da objašnjavaju kako nešto radi, već šta nešto radi. Objašnjavajući kako nešto
radi dolazi do mešanja različitih nivoa apstrakcije.

Reinženjering informacionih sistema 2020/2021


20
Code Smells

Nazivi:

N2: Choose Names at the Appropriate Level of Abstraction


Nazivi ne bi trebalo da objašnjavaju kako nešto radi, već šta nešto radi. Objašnjavajući kako nešto
radi dolazi do mešanja različitih nivoa apstrakcije.

public interface Modem {


boolean dial(String phoneNumber);
boolean disconnect();
boolean send(char c);
char recv();
String getConnectedPhoneNumber();
}

* Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship

Reinženjering informacionih sistema 2020/2021


21
Code Smells

Nazivi:

N2: Choose Names at the Appropriate Level of Abstraction


Nazivi ne bi trebalo da objašnjavaju kako nešto radi, već šta nešto radi. Objašnjavajući kako nešto
radi dolazi do mešanja različitih nivoa apstrakcije.

public interface Modem {


boolean connect(String connectionLocator);
boolean disconnect();
boolean send(char c);
char recv();
String getConnectedLocator();
}

* Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship

Reinženjering informacionih sistema 2020/2021


22
Code Smells

Nazivi:

N3: Use Standard Nomenclature Where Possible


Ukoliko se primenjuje neki dizajnerski obrazac, uobičajeno je da se nazivu klase doda i naziv
obrazca koji se primenjuje. Npr. AutoHangupModemDecorator može biti naziv klase koje primenjuje
dekorator nad klasom Modem kako bi se automatski prekinula veza na modemu.

Reinženjering informacionih sistema 2020/2021


23
Code Smells

Nazivi:

N4: Unambiguous Names


Nazivi treba da odrede jednoznačno šta metode rade i čemu varijable služe.

private String doRename() throws Exception {

if(refactorReferences)
renameReferences();
renamePage();

pathToRename.removeNameFromEnd();
pathToRename.addNameToEnd(newName);
return PathParser.render(pathToRename);
}
* Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship

Reinženjering informacionih sistema 2020/2021


24
Code Smells

Nazivi:

N4: Unambiguous Names


Nazivi treba da odrede jednoznačno šta metode rade i čemu varijable služe.

private String RenamePageAndOptionallyAllReferences () throws Exception {

if(refactorReferences)
renameReferences();
renamePage();

pathToRename.removeNameFromEnd();
pathToRename.addNameToEnd(newName);
return PathParser.render(pathToRename);
}
* Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship

Reinženjering informacionih sistema 2020/2021


25
Code Smells

Nazivi:

N5: Use Long Names for Long Scopes


Što je veći opseg, naziv bi trebao da bude duži.

N6: Avoid Encodings


Nazivi ne bi trebalo da sadrže suvišne informacije. Npr. Hungarian notation.

Reinženjering informacionih sistema 2020/2021


26
Code Smells

Nazivi:

N7: Names Should Describe Side-Effects


Nazivi treba da opišu sve što klasa, metoda ili varijabla radi. Ne bi trebalo izostaviti „sporedne“
funkcionalnosti koje mogu imati.

public ObjectOutputStream getOos() throws IOException {


if (m_oos == null) {
m_oos = new ObjectOutputStream(m_socket.getOutputStream());
}
return m_oos;
}

Reinženjering informacionih sistema 2020/2021


27
Code Smells

Nazivi:

N7: Names Should Describe Side-Effects


Nazivi treba da opišu sve što klasa, metoda ili varijabla radi. Ne bi trebalo izostaviti „sporedne“
funkcionalnosti koje mogu imati.

public ObjectOutputStream createOrReturnOos() throws IOException {


if (m_oos == null) {
m_oos = new ObjectOutputStream(m_socket.getOutputStream());
}
return m_oos;
}

Reinženjering informacionih sistema 2020/2021


28
Code Smells

Testovi:

T1: Insufficient Tests


Ne postoji metrika koja će odrediti potreban broj testova. Testovi treba da pokriju sve što može da
ne radi. Broj testova nije dovoljan ukoliko postoje uslovi ili proračuni koji nisu testirani.

T2: Use a Coverage Tool!


Potrebno je koristiti alate koji će proveravati pokrivenost koda testovima. Ovi alati olakšavaju
pronalaženje koda koji nije pokriven testovima.

T3: Don’t Skip Trivial Tests


Trivijalne testove je lako napisati i rad koji je potrebno uložiti u to obično je mnogo manji nego
njihova vrednost.

Reinženjering informacionih sistema 2020/2021


29
Code Smells

Testovi:

T4: An Ignored Test Is a Question about an Ambiguity


Ukoliko postoji test koji je oznaćen sa @Ignore, to može izazvati zabunu i nejasnoće u smislu
njegovog postojanja i namene.

T5: Test Boundary Conditions


Posebnu požnju treba posvetiti testovima koji testiraju granične slučajeve.

T6: Exhaustively Test Near Bugs


Ukoliko test pokaže da u metodi postoji problem, nakon ispravljanja problema poželjno je detaljno
testirati izmenjenu metodu, jer je veoma moguće sa greška koja je pronađena nije bila jedina.

Reinženjering informacionih sistema 2020/2021


30
Code Smells

Testovi:

T7: Patterns of Failure Are Revealing


Ponekad je moguće primetiti da se testovi koji uvek ne prolaze u istim grupama ili sekvencama.
Ovakvo ponašanje se najlakše otkriva kada je pokrivenost testovima najveća moguća.

T8: Test Coverage Patterns Can Be Revealing


Ukoliko pogledate deo koda koji se izvršava ili ne izvršava od strane testa koji prolazi, može biti od
pomoći za pronalaženje razloga zašto neki drugi test ne prolazi.

T9: Tests Should Be Fast


Testovi se moraju izvršavati brzo, ukoliko testiranje oduzima mnogo vremena, testovi se neće
pokretati redovno i prednosti koje donose će biti smanjene.

Pitanja?

Reinženjering informacionih sistema 2020/2021

You might also like