Clean Code Maciej Grabek Software Engineer Holte Software
Clean Code Maciej Grabek Software Engineer | Holte Software Poland
Bio • Maciej Grabek • Software Engineer w Holte Software • Editor in Chief Code. Guru. pl • MVP Windows Phone Development • Speaker, author of books, articles, webcasts. . . • Contact • kontakt@maciejgrabek. com • http: //maciejgrabek. com • @maciejgrabek
Agenda • Meaningful names • Read your code • Small steps • Responsibilities • Magic numbers • Exceptions • Communication between projects
Why?
Why? • Smart developer • Difficult code • Has great developing skills • r = lowercase url • Professional developer • • Readable code Maintanable code Clarity! lowercase. Url. Of. Page = lowercase url
Why? • Bad code? • • Need to be done fast Tired of project / work Works now, I will clean up later All of us does this
Why? • Bad code? • • • Requirements changed Deadline to close Managers Sales WE - DEVELOPERS
Why? • DEVELOPERS, DEVELOPERS
Explanation
Explanation
Meaningful names
Meaningful names int x int y int temp return x int elapsed. Time. In. Minutes int maximum. Possible. Value int days. Since. Last. Login return result
Meaningful names public List<int[]> get. Them() { List<int[]> list 1 = new Array. List<int[]>(); public List<Cell> get. Flagged. Cells() { List<Cell> flagged. Cells = new Array. List<Cell>(); for (int[] x : the. List) if (x[0] == 4) list 1. add(x); return list 1; for (Cell cell : game. Board) if (cell. is. Flagged()) flagged. Cells. add(cell); return flagged. Cells; } }
Meaningful names public static void copy. Chars(char a 1[], char a 2[]) { for (int i = 0; i < a 1. length; i++) { a 2[i] = a 1[i]; } } public static void copy. Chars(char source[], char destination[]) { for (int i = 0; i < source. length; i++) { destination[i] = source[i]; } }
Meaningful names XYZController. For. Efficient. Handling. Of. Strings XYZController. For. Efficient. Storage. Of. Strings Array[Item] Get. Items. Array() List<Item> Get. Items. List() IEnumerable<Item> Get. Items()
Not too much string str. Product. Title = „some product title”; double db. Product. Price = 12. 34; string product. Title = „some product title”; double product. Price = 12. 34;
Try to pronouce this class Dta. Rcrd 102 { private Date genymdhms; private Date modymdhms; private final String pszqint = "102"; /*. . . */ }; class Customer { private Date generation. Timestamp; private Date modification. Timestamp; ; private final String record. Id = "102"; /*. . . */ };
One word per concept • Get / receive / fetch • Controller / manager / driver
Read your code
Read your code • Max 150 chars per line • Max 20 lines per method • Blocks ( { } )
Read your code • Method parameters • Search(int min. Value, int max. Value, int page. Number, int page. Size) • Search(Conditions conditions) • Conditions {int min. Value, int max. Value, int page. Number, int page. Size }
Read your code if(account. Id > 0 && account. Name != null) { // do something } if(Account. Is. Valid(account)) { // do something } //where account is bussinnes class if(account. Is. Valid) { // do something }
Read your code Bad. Way() { Code. To. Call. DB Code. To. Convert. Items. To. Model Code. To. Calculate Code. To. Save. Calculations return } Better. Way() { var items = Get. Items(); var results = Process. Items(items); Save. Results(results); return results; } Get. Items() { } Process. Items(items. To. Process){ } Save. Results(results. To. Save){ }
Don’t repeat your self Get. Items(){ Account account = accounts. Service. Get. Account(); if(account. Is. Valid) { return items. Service. Get. Items(account); } } Get. Item(int item. Id){ Account account = accounts. Service. Get. Account(); if(account. Is. Valid) { return items. Service. Get. Item(item. Id); } } Get. Items(){ if(Validate. Account()) { return items. Service. Get. Items(account); } } Get. Item(int item. Id){ if(Validate. Account()) { return items. Service. Get. Item(item. Id); } } Validate. Account(){ Account account = accounts. Service. Get. Account(); return account. Is. Valid; }
Small steps
Small steps • Scout rule • Always leave it better than you found it • Check your code after some time
Conditions – leave when is not ok if(check. Condition 1) { some logic here if(check. Condition 2) { long logic here } else { return / throw } if(!check. Condition 1) { return / throw } some logic here if(!check. Condition 2) { return / throw } long logic here
Responsibilities
SOLID • S – Single responsibility principle • O – Open / closed principle • L – Liskov substitution principle • I – Interface segregation principle • D – Dependency inversion principle
Single responsibility principle class Person { string Name; string Surname; int Age; . . . int Calculate. Distance(Place); void Save. In. DB(). . . and so on. . . for next couple k lines } class Person { string Name; string Surname; int Age; } class World { Calculate. Distance(Person, Place) } class Person. Repository { Save(Person); }
Magic Numbers MNDD – Magic Numbers Driven Development
Magic number if(report. Type == 2) { if(report. Type == Report. Type. Cool) { } } // guess what is 2 enum Report. Type { Normal = 1, Cool = 2, Basic = 3 }
Magic string if(report. Category. Name == „special”) { } if(report. Category. Name == String. Resources. Special. Category. Name) { }
Exceptions
Exception hierarchy try { var result = Do. Something(); } catch(Exception ex) { if(ex. Message. Equals(„range”)) { } else if(ex. Message. Starts. With(„_”)) { } } Out. Of. Range. Exception Invalid. Operation. Exception Invalid. User. Exception Insufficient. Privileges. Exception try { var result = Do. Something(); } catch(Out. Of. Range. Exception){} catch(Invalid. User. Exception){} catch(Insufficient. Privileges. Exception){} catch(Exception) { // something went really bad // as I was not expecting that }
„Empty” object Var account = Get. Account(id); Get. Account. Returns Empty instead of null if(account == null || account. Id <= 0) { throw new Invalid. Account. Exception(); } if(account == Account. Empty) { throw new Invalid. Account. Exception(); } rest of logic class Account { public int Id { get; set; } public Account Empty { return new Account { Id = 0}; } }
Communication between projects
External / internal • IPerson. Repository • Person Get(id) • Model • Person • DBPerson. Repository : IPerson. Repository • DBPerson To Person Mapper • Easy to change repository ex. from EF to Azure Tables • Web. API • Always use DTO (ex Model. Person) • Person. Controller • Person. Dto Get(id) • Contract is resistant to internal changes of model
Bonus
- Slides: 41