CLEAN CODE 02
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
Metode/Funkcije (Functions) – Primer 1
public static String testableHtml( PageData pageData, boolean includeSuiteSetup) throws Exception {
WikiPage wikiPage = pageData.getWikiPage();
StringBuffer buffer = new StringBuffer();
if (pageData.hasAttribute("Test")) {
if (includeSuiteSetup) {
WikiPage suiteSetup = PageCrawlerImpl.getInheritedPage(SuiteResponder.SUITE_SETUP_NAME, wikiPage);
if (suiteSetup != null) {
WikiPagePath pagePath = suiteSetup.getPageCrawler().getFullPath(suiteSetup);
String pagePathName = PathParser.render(pagePath);
buffer.append("!include -setup .").append(pagePathName).append("\n");
}
}
WikiPage setup = PageCrawlerImpl.getInheritedPage("SetUp", wikiPage);
if (setup != null) {
WikiPagePath setupPath = wikiPage.getPageCrawler().getFullPath(setup);
String setupPathName = PathParser.render(setupPath);
buffer.append("!include -setup .").append(setupPathName).append("\n");
}
}
buffer.append(pageData.getContent()); * Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship
Reinženjering informacionih sistema 2020/2021
4
Metode/Funkcije (Functions) – Primer 1
if (pageData.hasAttribute("Test")) {
WikiPage teardown = PageCrawlerImpl.getInheritedPage("TearDown", wikiPage);
if (teardown != null) {
WikiPagePath tearDownPath = wikiPage.getPageCrawler().getFullPath(teardown);
String tearDownPathName = PathParser.render(tearDownPath);
buffer.append("\n")
.append("!include -teardown .").append(tearDownPathName).append("\n");
}
if (includeSuiteSetup) {
WikiPage suiteTeardown =
PageCrawlerImpl.getInheritedPage( SuiteResponder.SUITE_TEARDOWN_NAME,wikiPage);
if (suiteTeardown != null) {
WikiPagePath pagePath = suiteTeardown.getPageCrawler().getFullPath (suiteTeardown);
String pagePathName = PathParser.render(pagePath);
buffer.append("!include -teardown .").append(pagePathName).append("\n");
}
}
}
pageData.setContent(buffer.toString());
return pageData.getHtml();
}
* Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship
Reinženjering informacionih sistema 2020/2021
5
Metode/Funkcije (Functions) – Primer 1
public static String renderPageWithSetupsAndTeardowns(PageData pageData, boolean isSuite) throws Exception {
boolean isTestPage = pageData.hasAttribute("Test");
if (isTestPage) {
WikiPage testPage = pageData.getWikiPage();
StringBuffer newPageContent = new StringBuffer();
includeSetupPages(testPage, newPageContent, isSuite);
newPageContent.append(pageData.getContent());
includeTeardownPages(testPage, newPageContent, isSuite);
pageData.setContent(newPageContent.toString());
}
return pageData.getHtml();
}
* Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship
Reinženjering informacionih sistema 2020/2021
6
Metode/Funkcije (Functions)
Prvo pravilo za metode je da metode traba da budu kratke.
Drugo pravilo je da treba da budu još kraće.
Metode ne bi trebalo da budu duže od 20-tak linija.
Ukoliko imate selekcije ili iteracije, one ne bi trebalo da imaju više od jedne linije. Ukoliko je
potrebno da ima više linije, onda bi trebalo da koristite poziv neke druge metode.
Treba izbegavati ugnežđene strukture i ograničiti „dubinu“ na jednu ili dve strukture.
Reinženjering informacionih sistema 2020/2021
7
Metode/Funkcije (Functions)
Metode treba da rade jednu stvar. Treba da je rade dobro. То treba da bude jedina stvar koju rade.
public void unexecuteConsecutiveRemoveCommands(Command command){
while (command isInstanceof RemoveCommand) {
executedCommands.peek().unexecute();
unexecutedCommands.push(executedCommands.pop());
command = executedCommands.peek();
}
}
1. Proverava da li se radi o remove komandi
2. Radi unexecute() komande
3. Premešta komandu sa jednog steka u drugi
Reinženjering informacionih sistema 2020/2021
8
Metode/Funkcije (Functions)
Unutar jedne funkcije treba da budemo na jednom nivou apstrakcije.
The Stepdown Rule – želimo da svaku funkciju prate druge funkcije koje se nalaze na narednom
nivou apstrakcije.
Funkcije koje nisu na istom nivou apstrakcije i koje ne obavljaju samo jednu stvar, teško možete
podeliti u sekcije.
Reinženjering informacionih sistema 2020/2021
9
Metode/Funkcije (Functions) – Primer 3
public double calculatePay(Employee e) throws InvalidEmployeeCategory {
switch (e.category) {
case PROFESSOR:
return calculateProfessorPay(e);
case ASSISTANT:
return calculateAssistantPay(e);
case TEACHING_ASSOSIATE:
return calculateTeachingAssosiatePay(e);
case NON_TEACHING_STAFF:
return calculateNonTeachingStaffPay(e);
default:
throw new InvalidEmployeeCategory(e.category);
}
}
Reinženjering informacionih sistema 2020/2021
10
Metode/Funkcije (Functions)
Switch statements:
• Dugačke.
• Narušavaju Open Closed Principle.
• Pojaviće se u velikom broju drugih metoda.
Preporuka je da se mogu koristiti:
• samo jednom,
• ukoliko se koriste za kreiranje polimorfnih objekata,
• ukoliko su skrivene iza nasleđivanja.
Reinženjering informacionih sistema 2020/2021
11
Metode/Funkcije (Functions) – Primer 3
public abstract class Employee {
public abstract double calculatePay(); Iskorišćen je dizajnerski obrazac Factory
public abstract boolean isPayday(); što je stavljeno do znanja imenovanjem
public abstract void deliverPay(double pay); interfejsa i klasa.
}
public interface EmployeeFactory {
public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType;
}
public class EmployeeFactoryImpl implements EmployeeFactory {
public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType {
switch (r.type) {
case PROFESSOR:
return new ProfessorEmployee(r) ;
case ASSISTANT:
return new AssistantEmployee(r);
case TEACHING_ASSOCIATE:
return new TeachingAssociateEmploye(r);
case NON_TEACHING_STAFF:
return new NonTeachingTeachingEmploye(r);
default:
throw new InvalidEmployeeType(r.type);
}
}
Reinženjering informacionih sistema 2020/2021
12
Metode/Funkcije (Functions)
Argumenti funkcije:
• Idealan broj argumenata koje funkcija treba da ima je nula
• Jedan argument je malo lošiji izbor
• Dva argumenta još malo lošiji
• Tri argumenta su već loš izbor
• Četiri i više argumenta zahtevaju posebna opravdanja
Razlozi:
• Otežano razumevanje koda
• Otežano pisanje testova
Reinženjering informacionih sistema 2020/2021
13
Metode/Funkcije (Functions)
Ulazni i povratni argumenti:
• public boolean isAreaClosed(Shape s)
• public void trimExtraSpaces(String s)
Reinženjering informacionih sistema 2020/2021
14
Metode/Funkcije (Functions)
Ulazni i povratni argumenti:
public boolean isAreaClosed(Shape s) – povratni tip podatka je boolean
public void trimExtraSpaces(String s) - povratni tip podatka je String nad kojim je vršena operacija
Dva najčešća razloga za prosleđivanje jednog argumenta metodi:
• postavljenje pitanje o argumentu
• vršenje operacija nad argumentom
Reinženjering informacionih sistema 2020/2021
15
Metode/Funkcije (Functions)
Vršenje operacija nad argumentom
- public void trimExtraSpaces(String s)
- appendFooter(s)
Da li je s ulazni ili povratni argument?
Reinženjering informacionih sistema 2020/2021
16
Metode/Funkcije (Functions)
Vršenje operacija nad argumentom
- public void trimExtraSpaces(String s)
- appendFooter(s);
Da li je s ulazni ili povratni argument?
public void appendFooter(StringBuffer report)
Reinženjering informacionih sistema 2020/2021
17
Metode/Funkcije (Functions)
Vršenje operacija nad argumentom
- public void trimExtraSpaces(String s)
- appendFooter(s);
Da li je s ulazni ili povratni argument?
• public void appendFooter(StringBuffer report)
Generalno, bilo bi mnogo bolje kada bi se this koristilo kao povratni argument
• report.appendFooter();
Reinženjering informacionih sistema 2020/2021
18
Metode/Funkcije (Functions)
Korišćenje više argumenata je nekada sasvim opravdano:
• public Point(int x, int y)
• public Point(int x, int y, int z)
Ukoliko postoji potreba za više argumenata, postoji mogućnost da se neki od argumenata smeste u
objekat:
• public Circle(int x, int y, int radius)
• public Circle(Point p, int radius)
Nazivi argumenata
• write(s)
• write(status)
Reinženjering informacionih sistema 2020/2021
19
Metode/Funkcije (Functions) – Primer 4
public class UserValidator {
private Cryptographer cryptographer;
public boolean checkPassword(String userName, String password) {
User user = UserGateway.findByName(userName);
if (user != User.NULL) {
String codedPhrase = user.getPhraseEncodedByPassword();
String phrase = cryptographer.decrypt(codedPhrase, password);
if ("Valid Password".equals(phrase)) {
Session.initialize();
return true;
}
}
return false;
}*
* Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship
Reinženjering informacionih sistema 2020/2021
20
Metode/Funkcije (Functions) – Primer 4
public class UserValidator {
private Cryptographer cryptographer;
public boolean checkPassword(String userName, String password) {
User user = UserGateway.findByName(userName);
if (user != User.NULL) {
String codedPhrase = user.getPhraseEncodedByPassword();
String phrase = cryptographer.decrypt(codedPhrase, password);
if ("Valid Password".equals(phrase)) {
Session.initialize();
return true;
}
- Skrivene funkcionalnosti
}
- Radi više stvari od jedne
return false;
}*
* Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship
Reinženjering informacionih sistema 2020/2021
21
Metode/Funkcije (Functions)
Metode treba da rade nešto ili da odgovaraju na neko pitanje, ne treba da rade i jedno i drugo.
public boolean set(String attribute, String value);
Postavlja vrednost attribute na value i vraća true ukoliko atribut sa vrednošću attribute postoji, a false
ukoliko ne postoji.
To nam omogućava da pravimo:
if(set(“username”,“testuser”))
* Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship
Reinženjering informacionih sistema 2020/2021
22
Metode/Funkcije (Functions)
try/catch blokovi
• premestiti telo try/catch blokova u posebne metode
• ukoliko metoda treba da ima try/catch blok neka počne sa try i ne bi trebalo da ima ništa nakon
catch/final
Reinženjering informacionih sistema 2020/2021
23
Metode/Funkcije (Functions) – Primer 5
try/catch blokovi
public void delete(Page page) {
try {
deletePage(page);
registry.deleteReference(page.name);
configKeys.deleteKey(page.name.makeKey());
}
catch (Exception e) {
logger.log(e.getMessage());
}
* Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship
Reinženjering informacionih sistema 2020/2021
24
Metode/Funkcije (Functions) – Primer 5
try/catch blokovi
public void delete(Page page) {
try {
deletePageAndAllReferences(page);
}
catch (Exception e) {
logError(e);
}
}
private void deletePageAndAllReferences(Page page) throws Exception {
deletePage(page);
registry.deleteReference(page.name);
configKeys.deleteKey(page.name.makeKey());
}
private void logError(Exception e) {
logger.log(e.getMessage());
* Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship
}
Reinženjering informacionih sistema 2020/2021
25
Metode/Funkcije (Functions)
Kako poštovati pravila za metode?
• napisaćete metode sa pogrešnim nazivima,
• napisaćete metode sa velikim brojem argumenata,
• napisaćete metode sa ugnježdenim strukturama,
• imaćete mnogo dupliranog koda, ali
• pre nego što komitujete kod koji ste napisali, uradićete refaktoring/reinženjering, učinićete ga
čistim/čistijim, nastaće nove klase, nove metode, i taj proces ne bi trebalo da bude „strašan“, jer
imati testove koji će vam pomoći u ovom zadatku.
Pitanja?
Reinženjering informacionih sistema 2020/2021
26
Komentari (Comments)
Reinženjering informacionih sistema 2020/2021
27
Komentari (Comments)
package shapes;
public class Point extends Shape {
private int x; //x koordinata tacke
private int y; //y koordinata tacke
//prazan konstruktor
public Point() {
}
//konstruktor koji kreira tačku sa koordinatama koje su proleđene kao argumenti
public Point(int x, int y) {
this.x = x;
this.y = y;
}
Reinženjering informacionih sistema 2020/2021
28
Komentari (Comments)
//konstruktor koji kreira tacku sa koordinatama koje su proledjene kao argumenti
public Point(int x, int y) {
this.x = x;
this.y = y;
}
//konstruktor koji kreira tacku sa koordinatama i bojom koje su prosledjene kao argumenti
public Point(int x, int y, Color color) {
this(x, y);
setColor(color);
}
Reinženjering informacionih sistema 2020/2021
29
Komentari (Comments)
//metoda koja vraća vrednost x koordinate
public int getX() {
return x;
}
//metoda koja vraća vrednost y koordinate
public int getY() {
return y;
}
//metoda koja postavlja vrednost x koordinate na vrednost prosledjenog argumenta
public void setX(int x) {
this.x = x;
}
Reinženjering informacionih sistema 2020/2021
30
Komentari (Comments)
//metoda koja postavlja vrednost y koordinate na vrednost prosledjenog argumenta
public void setY(int y) {
this.y = y;
}
//metoda koja pomera tacku na koordinate prosledjena kao argumenti
public void moveTo(int x, int y) {
setX(x);
setY(y);
}
}
Reinženjering informacionih sistema 2020/2021
31
Komentari (Comments)
• Mogu da pomognu
• Mogu da zaguše kod
• Mogu da budu netačni/zbunjujući
• Sa aspekta CleanCode-a predstavljaju neophodno zlo
Reinženjering informacionih sistema 2020/2021
32
Komentari (Comments)
• Mogu da pomognu
public void testCompareTo() throws Exception {
WikiPagePath a = PathParser.parse("PageA");
WikiPagePath ab = PathParser.parse("PageA.PageB");
WikiPagePath b = PathParser.parse("PageB");
WikiPagePath aa = PathParser.parse("PageA.PageA");
WikiPagePath bb = PathParser.parse("PageB.PageB");
WikiPagePath ba = PathParser.parse("PageB.PageA");
assertTrue(a.compareTo(a) == 0); // a == a
assertTrue(a.compareTo(b) != 0); // a != b
assertTrue(ab.compareTo(ab) == 0); // ab == ab
assertTrue(a.compareTo(b) == -1); // a < b
assertTrue(aa.compareTo(ab) == -1); // aa < ab
assertTrue(ba.compareTo(bb) == -1); // ba < bb
assertTrue(b.compareTo(a) == 1); // b > a
assertTrue(ab.compareTo(aa) == 1); // ab > aa
assertTrue(bb.compareTo(ba) == 1); // bb > ba
}*
* Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship
Reinženjering informacionih sistema 2020/2021
33
Komentari (Comments)
• Mogu da pomognu
//checks is student has required average grade to enroll into phd studies
if(student.getAverageGrade()>AVERAGE_GRADE_REQUIREMENT)
Reinženjering informacionih sistema 2020/2021
34
Komentari (Comments)
• Mogu da budu netačni/zbunjujući
o Komentare je potrebno održavati
▪ Kod je promenjen, a komentar je ostao kao pre promene
▪ Komentar ne odgovara onome što metoda radi
Reinženjering informacionih sistema 2020/2021
35
Komentari (Comments)
Sa aspekta Clean Code-a predstavljaju neophodno zlo
• Kada god je to moguće, šta kod radi treba da bude jasno iz naziva metoda i varijabli
Šta ne bi trebalo da radite:
- da koristite komentare kako bi pratili verzije datoteke (VCS – Version Control System)
- da koristite komentare da vodite evidenciju o tome koje poslednji menjao datoteku (VCS)
- da pišete komentare samo zato što vam je neko rekao da to treba da radite
- da komentarišete delove koda
- iako je sasvim normalno da tokom rada zakomentarišete neku liniju ili metodu,
zakomentarisan kod ne bi trebalo da se nađe u vašem komitu
//Copyright (C) 2002 by ITGuys, All rights reserved
Sa stranice ISP početka 2000.-tih
//Do not copy this code without permission or I’ll cut your little fingers off
Reinženjering informacionih sistema 2020/2021
36
Formatiranje (Formatting)
Vertikalno formatiranje
• Koliko linija koda treba da bude u jednoj klasi?
o zavisi od toga šta klasa rad
▪ najčešće ipak zavisi od toga kako je kod pisan
▪ poželjno je da klase imaju što manji broj linija
* Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship
Reinženjering informacionih sistema 2020/2021
37
Formatiranje (Formatting)
public class Point extends Shape { public class Point extends Shape {
private int x; private int x;
private int y; private int y;
public Point(int x, y, Color color) {
public Point(int x, int y, Color color) { this.x = x;
this.x = x; this.y = y;
this.y = y; setColor(color);
setColor(color); }
} public void moveTo(int x, int y) {
this.x = x;
public void moveTo(int x, int y) { this.y = y;
this.x = x; }
this.y = y;
} }
Reinženjering informacionih sistema 2020/2021
38
Formatiranje (Formatting)
public class Point extends Shape { public class Point extends Shape {
private int x; private int x;
private int y; private int y;
public Point(int x, int y, Color color) {
this.x = x; public Point(int x, int y, Color color) {
this.y = y; this.x = x;
setColor(color);
} this.y = y;
setColor(color);
public void moveTo(int x, int y) { }
this.x = x;
this.y = y; public void moveTo(int x, int y) {
} this.x = x;
this.y = y;
}
Reinženjering informacionih sistema 2020/2021 }
39
Formatiranje (Formatting)
Deklarisanje varijabli
• Varijable treba da budu deklarisane što je moguće bliže kodu u kojem će se koristiti
• Varijable koje se koriste u iteracijama, treba da budu deklarisane unutar iteracije
• Varijable instance treba da budu deklarisane na početku klase
Reinženjering informacionih sistema 2020/2021
40
Formatiranje (Formatting)
Point druga = new Point();
public boolean equals(Object obj) {
…
if (obj instanceof Point) {
public boolean equals(Object obj) {
Point druga = (Point)obj;
if (obj instanceof Point) {
if (getColor().equals(druga.getColor()) &&
druga = (Point)obj;
x==druga.getX() &&
if (getColor().equals(druga.getColor()) &&
y==druga.getY())
x==druga.getX() &&
return true;
y==druga.getY())
else
return true;
return false;
else
}
return false;
else
}
return false;
else
}
return false;
}
Reinženjering informacionih sistema 2020/2021
41
Formatiranje (Formatting)
Vertikalno formatiranje
• Metode između kojih postoji zavisnost, treba da budu blizu jedna druge u vertikalnom
formatiranju, naravno, onoliko koliko je to moguće.
• Metode koje pripadaju istim logičkim segmentima, treba da budu vertikalno bliske.
Reinženjering informacionih sistema 2020/2021
42
Formatiranje (Formatting)
public moveTo(int x, int y,) { public moveTo(int x, int y,) {
this.x = x; this.x = x;
this.y = y; this.y = y;
} }
public void moveBy(int x, int y) { public boolean contains(int x, int y) {
moveTo(this.x+x, this.y+y); Point kliknuta = new Point(x, y);
} if (distance(kliknuta)<=3)
return true;
public boolean contains(int x, int y) { return false;
Point kliknuta = new Point(x, y); }
if (distance(kliknuta)<=3)
return true; public void moveBy(int x, int y) {
return false; moveTo(this.x+x, this.y+y);
} }
Reinženjering informacionih sistema 2020/2021
43
Formatiranje (Formatting)
public int getX() { public int getX() {
return x; return x;
} }
public int getY() { public boolean contains(int x, int y) {
return y; Point kliknuta = new Point(x, y);
} if (distance(kliknuta)<=3)
return true;
public void setX(int x) { return false;
this.x = x; }
}
public int getY() {
public void setY(int y) { return y;
this.y = y; }
}
Reinženjering informacionih sistema 2020/2021
44
Formatiranje (Formatting) – Primer 6
@Override
public void draw(Graphics g) {
g.setColor(getColor());
g.drawOval(this.getCenter().getX() - this.radius, getCenter().getY() - getRadius(),
this.getRadius() * 2, this.getRadius() * 2);
fill(g);
if (isSelected()) {
g.setColor(Color.BLUE);
g.drawRect(getCenter().getX() - 3, getCenter().getY() - 3, 6, 6);
g.drawRect(getCenter().getX() + getRadius() - 3, getCenter().getY() - 3, 6, 6);
g.drawRect(getCenter().getX() - getRadius() - 3, getCenter().getY() - 3, 6, 6);
g.drawRect(getCenter().getX() - 3, getCenter().getY() + getRadius() - 3, 6, 6);
g.drawRect(getCenter().getX() - 3, getCenter().getY() - getRadius() - 3, 6, 6);
g.setColor(Color.BLACK);
}
}
Reinženjering informacionih sistema 2020/2021
45
Formatiranje (Formatting) – Primer 6
public boolean contains(Point p) {
return center.distance(p.getX(), p.getY()) <= radius;
}
public Point getCenter() {
return center;
}
public void setCenter(Point center) {
this.center = center;
}
public int getRadius() {
return radius;
}
Reinženjering informacionih sistema 2020/2021
46
Formatiranje (Formatting) – Primer 6
public void setRadius(int radius) throws Exception {
if (radius >= 0)
this.radius = radius;
else
throw new Exception();
}
public String toString() {
return "Circle: " + "Center= (" + center.getX() + "," + center.getY() + "), " + "Radius=" +
radius + ", " + "OuterColor=" + Integer.toString(getColor().getRGB()) + ", " +
"InnerColor=“ + Integer.toString(getInsideColor().getRGB());
@Override
public void moveBy(int byX, int byY) {
center.moveBy(byX, byY);
}
Reinženjering informacionih sistema 2020/2021
47
Formatiranje (Formatting) – Primer 6
@Override
public int compareTo(Object o) {
if (o instanceof Circle) {
return (this.radius - ((Circle) o).radius);
}
return 0;
}
@Override
public void fill(Graphics g) {
g.setColor(getInsideColor());
g.fillOval(this.getCenter().getX() + 1 - this.radius, getCenter().getY() + 1 - getRadius(),
(this.getRadius() - 1) * 2, (this.getRadius() - 1) * 2);
}
Reinženjering informacionih sistema 2020/2021
48
Formatiranje (Formatting) – Primer 6
@Override public void setRadius(int radius) throws Exception {…}
public void draw(Graphics g) {
… public String toString() {…}
fill(g);
if (isSelected()) { @Override
… public void moveBy(int byX, int byY) {…}
}
} @Override
public int compareTo(Object o) {…}
public boolean contains(Point p) {…}
@Override
public Point getCenter() {…} public void fill(Graphics g) {…}
public void setCenter(Point center) {…}
public int getRadius() {…}
Reinženjering informacionih sistema 2020/2021
49
Formatiranje (Formatting)
…
@Override
public void draw(Graphics g) {
…
fill(g);
if (isSelected()) {
drawSelection(g);
}
}
public void fill(Graphics g) {…}
public void drawSelection(Graphics g) {…}
…
Reinženjering informacionih sistema 2020/2021
50
Formatiranje (Formatting)
Horizontalno formatiranje
* Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship
Reinženjering informacionih sistema 2020/2021
51
Formatiranje (Formatting)
Horizontalno formatiranje
• razmak (space) oko operatora dodele =, =+…
• „nazubljivanje“ koda…
• dogovor oko pravila kada se radi u timu
Izbegavati
• pisanje „kratkih“ metoda u jednoj liniji
public void setX(int x){ this.x =x;}
public void setX(int x){
this.x = x;
}
Reinženjering informacionih sistema 2020/2021
52
Formatiranje (Formatting)
public class CodeAnalyzer implements JavaFileAnalysis {
private int lineCount;
private int maxLineWidth;
private int widestLineNumber;
private LineWidthHistogram lineWidthHistogram;
private int totalChars;
public CodeAnalyzer() {
lineWidthHistogram = new LineWidthHistogram();
}
public static List<File> findJavaFiles(File parentDirectory) {
List<File> files = new ArrayList<File>();
findJavaFiles(parentDirectory, files);
return files;
}
* Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship
Reinženjering informacionih sistema 2020/2021
53
Formatiranje (Formatting)
private static void findJavaFiles(File parentDirectory, List<File> files) {
for (File file : parentDirectory.listFiles()) {
if (file.getName().endsWith(".java"))
files.add(file);
else if (file.isDirectory())
findJavaFiles(file, files);
}
}
public void analyzeFile(File javaFile) throws Exception {
BufferedReader br = new BufferedReader(new FileReader(javaFile));
String line;
while ((line = br.readLine()) != null)
measureLine(line);
}
* Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship
Reinženjering informacionih sistema 2020/2021
54
Formatiranje (Formatting)
private void measureLine(String line) {
lineCount++;
int lineSize = line.length();
totalChars += lineSize;
lineWidthHistogram.addLine(lineSize, lineCount);
recordWidestLine(lineSize);
}
private void recordWidestLine(int lineSize) {
if (lineSize > maxLineWidth) {
maxLineWidth = lineSize;
widestLineNumber = lineCount;
}
}
public int getLineCount() {
return lineCount; * Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship
}
Reinženjering informacionih sistema 2020/2021
55
Formatiranje (Formatting)
public int getMaxLineWidth() {
return maxLineWidth;
}
public int getWidestLineNumber() {
return widestLineNumber;
}
public LineWidthHistogram getLineWidthHistogram() {
return lineWidthHistogram;
}
public double getMeanLineWidth() {
return (double)totalChars/lineCount;
}
* Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship
Reinženjering informacionih sistema 2020/2021
56
Formatiranje (Formatting)
public int getMedianLineWidth() {
Integer[] sortedWidths = getSortedWidths();
int cumulativeLineCount = 0;
for (int width : sortedWidths) {
cumulativeLineCount += lineCountForWidth(width);
if (cumulativeLineCount > lineCount/2)
return width;
}
throw new Error("Cannot get here");
}
private int lineCountForWidth(int width) {
return lineWidthHistogram.getLinesforWidth(width).size();
}
* Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship
Reinženjering informacionih sistema 2020/2021
57
Formatiranje (Formatting)
private Integer[] getSortedWidths() {
Set<Integer> widths = lineWidthHistogram.getWidths();
Integer[] sortedWidths = (widths.toArray(new Integer[0]));
Arrays.sort(sortedWidths);
return sortedWidths;
}
}
* Robert C. Martin - Clean Code: A Handbook of Agile Software Craftsmanship
Reinženjering informacionih sistema 2020/2021
58
Formatiranje (Formatting)
Pitanja?
Reinženjering informacionih sistema 2020/2021