Download - Perfect Code

Transcript
Page 1: Perfect Code

Perfect Code!How to write high-quality code!

ARTEM TABALIN!

Page 2: Perfect Code

Motivation!Why should we always improve our code?!Why code that just works is not enough? !

Page 3: Perfect Code

Code Quality Control Law !

Improving code quality reduces development costs!

Why?!

Developer average productivity is!10-50 lines per day!

Writing code – 10%!Reading code, testing, debugging – 90%!

!

Page 4: Perfect Code

Productivity vs Time!

Time

Pro

du

ctiv

ity

Productivity decreases with entropy increasing!

Page 5: Perfect Code

Software Development Paradox!

1.  Low-quality code slows down development!

2.  Devs reduce code quality to meet a deadline!

Paradox: “Devs have no time to work rapidly”!

The clue: #2 is wrong!

Impossible to successfully meet a deadline messing up the code!

Continuously maintain high code quality!

Page 6: Perfect Code

The Boy Scout Rule!

It’s not enough to write code well - prevent “rotting”!

!

“Leave the campground cleaner than you found it”!!

Page 7: Perfect Code

Software Development Principles!KISS, YAGNI, DRY, SOLID!

Page 8: Perfect Code

Keep Code Simple!

KISS (Keep It Simple, Stupid)!

Simplicity is a key goal!

Components should be integrated tightly or weakly (?)!

Try to reduce influence between components!

Follow “Divide and Conquer” principle!

!

Page 9: Perfect Code

Division of Responsibilities!

•  System → packages!

•  Package → classes!

•  Class → methods!

•  Method → control statements!

Low coupling on each level!

Page 10: Perfect Code

Use Patterns!

Don’t reinvent the square wheel!

•  Reduce complexity!

•  Less mistakes!

•  Simplify communication!

!

Examples: Repository, Factory, Adapter, Strategy, Observer!

Page 11: Perfect Code

No Unnecessary Code!

YAGNI (You Aren’t Gonna Need It)!

Implement things only when you really need them!!

Page 12: Perfect Code

Avoid Duplication!

DRY (Don’t Repeat Yourself)!

!

“Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.”!

!

Page 13: Perfect Code

Object-Oriented Design!

SOLID!

1.  Single Responsibility (SRP)!

2.  Open-Closed (OCP)!

3.  Liskov Substitution (LSP)!

4.  Interface Segregation (ISP)!

5.  Dependency Inversion (DIP)!

Page 14: Perfect Code

Single Responsibility Principle!

“A class should have one and only one reason to change”!!

Page 15: Perfect Code

Open-Closed Principle!Class should be opened to extension and closed for modification!

GraphicEditor

+drawShape

Shape

+draw

Rectangle

+draw

Circle

+draw

violation +drawCircle +drawRectangle +drawTriangle

Triangle

+draw

Page 16: Perfect Code

Liskov Substitution Principle!Objects implementing an interface can be used interchangeably!

!

IResizable +bounds +resize

Shape +bounds +resize

Image +bounds +resize

violation

resize(IResizable obj) {

if(obj is TextBlock)

return; obj.resize(); }

TextBlock +bounds +resize

GraphicEditor

+resize(IResizable)

Page 17: Perfect Code

Interface Segregation Principle!Clients should not depend on interfaces they don’t use!

!

Shape +resize +move +select

IResizable +resize

ISelectable +select

violation

IGraphic +resize +move +select

IMovable +move

Page 18: Perfect Code

Dependency Inversion Principle!Abstractions should not depend on details!

GraphicEditor

+logger: ILogger

ILogger

EmailLogger SystemLogger

violation

GraphicEditor() {

logger = new FileLogger(); }

FileLogger

Page 19: Perfect Code

Meaningful Names!Naming principles. Name length. Variable names. !Class names. Method names.!

Page 20: Perfect Code

Naming Principles!

Name should show your intention!

int  d;  //  elapsed  time  

Is it good enough?!

Which name is better?!

int  elapsedTimeInDays;  

int  daysSinceCreation;  

!

!

!

Page 21: Perfect Code

Naming Principles!What does the following code do?!

function  getItems(items)  {          var  list1  =  [];          for(var  i  =  0;  i  <  items.length;  i++)  {                  var  x  =  items[i];                  if(items[i]["Field"]  ===  12)  {                          list1.push(x);                  }          }          return  list1;  }  

!

Page 22: Perfect Code

Naming Principles!What is about this one?!

function  getMarkedCells(cells)  {          var  result  =  [];          for(var  i  =  0;  i  <  cells.length;  i++)  {                  var  cell  =  cells[i];                  if(cell.Status  ===  CellStatus.Marked)  {                          result.push(cell);                  }          }          return  result;  }  

Page 23: Perfect Code

Naming Principles!

No implementation details!

HashSet<Account>  accountHashSet;  

Is it good enough? Why?!

What if we decide to use List?!Which name is better?!

HashSet<Account>  accounts;  

!

Page 24: Perfect Code

Naming Principles!

Choose easy-to-pronounce name!

class  Cstmr  {          private  int  prsnid;          private  DateTime  genTstmp;          private  DateTime  modTstmp;  }  

class  Customer  {          private  int  personId;          private  DateTime  generationTimestamp;          private  DateTime  modificationTimestamp;  

}  

!

Page 25: Perfect Code

Naming Principles!

•  Single word for concept (avoid synonyms)! fetch / retrieve / get controller / manager / driver!

•  Names from patterns and algos! RenderStrategy, JobQueue!

•  Names from user stories! Credit, Debit, Asset!

•  Antonyms! begin / end first / last min / max next / previous! old / new opened / closed source / target up / down!!

Page 26: Perfect Code

Naming Convention!

The most important is to follow to the convention!

Example:!•  CONSTANT  

•  ClassName  

•  localVariable  

•  _privateMember  

Page 27: Perfect Code

Name Length!What is the optimal length for a name?!

x → maximumNumberOfPointsInEachLine  

short / long name pros & cons!

short names – lacks of information!long names – harder to read and write!!10-16 characters is the optimal length!if < 10 ask: is meaningful enough?!if > 16 ask: isn’t verbose?!

Page 28: Perfect Code

Loop Variable Names!

•  Simple loop!for(int  i  =  0;  i  <  data.length;  i++)  {          data[i]  =  0;  }  

•  Complex loop!for(int  teamIndex  =  0;  teamIndex  <  teamCount;  teamIndex++)  {          for(int  playerIndex  =  0;  playerIndex  <  count;  playerIndex++)  {                  playerStore[teamIndex][playerIndex]  =  0;          }  }!

Page 29: Perfect Code

Loop Variable Names!

•  Variable used outside of the loop  

int  recordCount  =  0;  

while(moreRecords())  {          data[recordCount]  =  getNextRecord();          recordCount++;  }  

//  …  recordCount  is  accessed  here  

!

Page 30: Perfect Code

Temporary Variable Names!

Avoid pointless names!

temp  =  sqrt(b^2  -­‐  4*a*c);  root[0]  =  (-­‐b  +  temp)  /  (2*a);  root[1]  =  (-­‐b  -­‐  temp)  /  (2*a);  

How to improve?!

discriminant  =  sqrt(b^2  -­‐  4*a*c);  root[0]  =  (-­‐b  +  discriminant)  /  (2*a);  root[1]  =  (-­‐b  -­‐  discriminant)  /  (2*a);  

!

Page 31: Perfect Code

Boolean Variables and Methods!

Use verbs is, has, can for booleans!

•  isSupported!

•  hasNext!

•  canExecute!

Page 32: Perfect Code

Class Names!

Use nouns and noun combinations for classes!

•  Client!

•  Window!

•  UserAccount!

•  FileLoader!

Page 33: Perfect Code

Method Names!

Use verbs and verb phrases for methods!

•  Save!

•  Close!

•  GetAccount!

•  LoadFile!

Page 34: Perfect Code

Variables!Declaration. Initialization. Lifetime and scope.!

Page 35: Perfect Code

Declaration!

•  Declare all variables!

•  Turn off implicit variable declaration!

JavaScript:  “use  strict”  

VB:  Option  Explicit  On  

php:  error_reporting(E_STRICT);  

!

Page 36: Perfect Code

Initialization!

Initialize variables at declaration!

var  total  =  0;  

or at first occurrence in code!

Dim  total  As  Double  '  another  code  total  =  0.0  '  code  using  total  

!

Page 37: Perfect Code

Lifetime and Scope!

Variables lifetime and scope should be minimal!

Why?!

Does code follow the principle?!

function  summarizeData()  {          var  oldData  =  getOldData();          var  totalOldData  =  summarize(oldData);          printData(totalOldData);          saveData(totalOldData);            var  newData  =  getNewData();          var  totalNewData  =  summarize(newData);          printData(totalNewData);          saveData(totalNewData);  }    

Page 38: Perfect Code

Lifetime and Scope!Code might look like!

function  summarizeData()  {          var  oldData  =  getOldData();          var  newData  =  getNewData();                    var  totalOldData  =  summarize(oldData);          var  totalNewData  =  summarize(newData);                    printData(totalOldData);          printData(totalNewData);                    saveData(totalOldData);          saveData(totalNewData);  }    

!

!

Page 39: Perfect Code

Lifetime and Scope!

•  Single purpose principle!int  value  =  getValue();  int  result  =  calcResult(value);  //  some  code  value  =  val1;      val1  =  val2;        val2  =  value;  

•  Avoid global variables!

•  Prefer the most restrictive access level! private → public!

var  swap  =  val1;  val1  =  val2;  val2  =  swap;    

Page 40: Perfect Code

Methods (Functions)!Purposes. Principles. Order. Parameters.!

Page 41: Perfect Code

Purposes!

•  Simplify code !

•  Improve readability !

•  Documentation defines abstraction!

•  Eliminating duplication most popular!

•  Inheritance support method overriding!

Page 42: Perfect Code

Principles!

Method should be small!

How many lines?!

not more than 20 lines and better even less!

Example:!

public  ReportContainer  BuildReport(IList<Order>  orders)  {          var  report  =  new  ReportContainer();          report.Lines  =  BuildReportLines(orders);          report.Total  =  BuildReportTotal(report.Lines);          return  report;  }  

!

Page 43: Perfect Code

Principles!

Method should have!

•  blocks (if, else, for, while) 1-3 lines long!•  indent level not more than 2!

private  IList<ReportLine>  BuildReportLines(IList<Order>  orders)  {          IList<ReportLine>  result  =  new  List<ReportLine>();          foreach  (Order  order  in  orders)  {                  ReportLine  reportLine  =  BuildReportLine(order);                  if  (reportLine.IsVisible)                          result.Add(reportLine);          }          return  result;  }  

!

Page 44: Perfect Code

Principles!

Single Thing Rule!

Function should do one thing, do it only, and do it well!

Examples:!

•  BuildReport – makes report!

•  BuildReportLines – prepares report lines!

•  BuildReportTotal – summarizes report!

Criteria: function cannot be divided into sections!

Page 45: Perfect Code

Principles!

Single Abstraction Level!

Mixing up abstraction levels increases complexity!

Does code follow the principle? Why?!

private  Report  BuildReport(Order  order)  {          var  result  =  new  Report();            result.Header  =  BuildReportHeader(order.Title);                    result.Body  =  ReportHelper.TextToHtml(order.Description);            result.Footer  =  "<b>"  +  APP_NAME  +  "</b>";          result.Footer  +=  "  CopyRight  ©  "  +  DateTime.Now.Year;            return  result;  }  

!

Page 46: Perfect Code

Principles!Better!

private  Report  BuildReport(Order  order)  {          var  result  =  new  Report();          result.Header  =  BuildReportHeader(order.Title);          result.Body  =  ReportHelper.TextToHtml(order.Description);          result.Footer  =  BuildReportFooter();          return  result;  }  

Much Better!

private  Report  BuildReport(Order  order)  {          var  result  =  new  Report();          result.Header  =  BuildReportHeader(order.Title);          result.Body  =  BuildReportBody(order.Description);          result.Footer  =  BuildReportFooter();          return  result;  }  

!

Page 47: Perfect Code

Principles!

Command-Query Separation (CQS)!

Method performs an action OR returns data!

Does code follow the principle?!

if  (SetAttribute("username",  "Admin"))  {          //  code  }  

How to fix?  

if  (HasAttribute("username"))  {          SetAttribute("username",  "Admin");          //  code  }    

Page 48: Perfect Code

Order!The Stepdown Rule!

Read code from top to bottom (by abstraction levels)!

public  Report  BuildReport(IList<Order>  orders)  {          //  uses  BuildReportLines  and  BuildReportTotal  }    private  Report  BuildReportLines(IList<Order>  orders)  {          //  uses  BuildReportLine  }    private  Report  BuildReportLine(IList<Order>  orders)  {          //  code  }    private  Report  BuildReportTotal(IList<Order>  orders)  {          //  code  }  

Page 49: Perfect Code

Arguments!How many parameters should a method have?!

•  Ideally 0!

•  Avoid methods with more than 2 arguments!

Why?!

•  Harder to read (remember passing values)!

•  Increase coupling!

•  Harder to test (combinatorial growth of variants)!

Page 50: Perfect Code

Arguments!Avoid boolean arguments!

Why?!

•  Usually can be divided into two sections!•  Hard to understand a purpose of an argument!BuildReportLine(order,  true);  

private  Report  BuildReportLine(Order  order,  bool  isMarked)  {          if  (isMarked)  {                  //  build  marked  report  line          }            else  {                  //  build  simple  report  line          }  }  

Page 51: Perfect Code

Classes!Purposes. Principles. Interface. Encapsulation. Inheritance.!

Page 52: Perfect Code

Purposes!•  Simplify code

•  Improve readability!

•  Limit the scope of changes!

•  Hide implementation details (encapsulation)!

•  Allow to prepare generic solution (abstraction)!

•  Eliminate duplication (delegation & inheritance)!

•  Provide extensibility (inheritance)!

•  Allow to work with real domain entities!

Page 53: Perfect Code

Principles!

•  Encapsulation! Hide as much as possible!

•  Compactness! Reduce class responsibilities (SRP)!

•  Abstraction! Program to an interface, not an implementation!

•  High Cohesion! Fields and methods should belong together!

Page 54: Perfect Code

Interface!

Methods should be on the same abstraction level!

Does code follow the principle? Why?!

class  Program  {          public  void  InitializeCommandStack();          public  void  PushCommand(Command  command);          public  Command  PopCommand();          public  void  ShutdownCommandStack();          public  void  InitializeReportFormatting();          public  void  FormatReport(Report  report);          public  void  PrintReport(Report  report);          public  void  InitializeGlobalData();          public  void  ShutdownGlobalData();  }  

Page 55: Perfect Code

Interface!

Programming over semantic!

•  Programming – can be checked by compiler! Amount of arguments! Argument types!

•  Semantic – cannot be checked by compiler! Method A should be called after method B! Method A throws exception when argument is not initialized!!

Page 56: Perfect Code

Encapsulation!

•  Not public should be private ! private → public!

•  No direct access to fields!private  decimal  _x  =  0;  public  decimal  X  {          get  {  return  _x;  }          set  {  _x  =  value;  }  }  

•  No assumptions about class clients!//  param2  should  be  >  0,  in  other  case  method  fails  public  int  Method(int  param1,  int  param2)  

!

Page 57: Perfect Code

Inheritance!

Should be able to say that child ‘is’ parent!Circle is Shape HtmlParser is Parser!

Does code follow the principle?!  class  Customer  {          public  int  ID  {  get;  set;  }          public  string  Name  {  get;  set;  }  }    class  Bank:  Customer  {          public  string  CorrespondentAccount  {  get;  set;  }  }  

Depends on whether a bank can be a customer or not!

!

Page 58: Perfect Code

Inheritance!

Move common methods to base class!

abstract  class  Stream  {          public  void  Write(byte[]  bytes);          public  byte[]  Read();  }      class  SecureStream:  Stream  {          public  void  Init(StreamConfig  config);  }  

!

Page 59: Perfect Code

Inheritance!

Avoid following situations:!

•  Parent class has only one child!

•  Child overrides method leaving it empty!

•  Too many hierarchy levels! better not more than 3 levels!

Page 60: Perfect Code

Comments!Commenting principles. Bad comments. Good comments.!

Page 61: Perfect Code

Commenting Principles!

•  Comments do not redress bad code! clean code much better than bad code with comments!

•  Do not comment tricky code – rewrite it! tricky code = bad code!

•  Try to explain with code!//  is  employee  eligible  for  bonus  if  ((employee.Schedule  ==  HOURLY_SCHEDULE)  &&          employee.Age  >  65)  {  …  }  !Better!

if  (employee.IsEligibleForBonus())  {  …  }  

Page 62: Perfect Code

Commenting Principles!

Comment says “why” not “how”!

•  How!//  if  flag  equals  to  zero  if  (accountFlag  ==  0)  

•  Why!//  if  new  account  created  if  (accountFlag  ==  0)  

•  Code instead of comment!if  (accountType  ==  AccountType.NewAccount)  

Page 63: Perfect Code

Bad Comments!•  Redundant comments! obvious and repeating code!

//  closing  connection  Connection.Close();    

•  Commented code! remove unnecessary code, VCS is for the rescue  

InputStream  response  =  new  InputStream();  response.SetBody(formatter.ResultStream,  formatter.BytesCount);  //InputStream  resultStream  =  formatter.ResultStream;  //StreamReader  reader  =  new  StreamReader(resultStream);  //response.SetContent(reader.Read(formatter.BytesCount));  

Page 64: Perfect Code

Good Comments!•  Legal comments! license, copyright, author!

•  Explanations! provide info about inevitable tricks  

//  NOTE:  postpone  execution  to  refresh  UI  setTimeout(function()  {          //  code  });  

•  TODOs! notes for future to avoid “broken windows”  

//  TODO:  get  rid  of  tricky  workaround  function  badFunction()  {          //  tricky  workaround  here  });  

Page 65: Perfect Code

Thank you!!

Your questions, please!!ARTEM TABALIN!

Page 66: Perfect Code

References!

•  Steve McConnell Code Complete!

•  Robert C. Martin Clean Code!

•  Hunt A., Thomas D. The Pragmatic Programmer !

•  Craig Larman Applying UML and Patterns!

•  Kent Beck Implementation Patterns!

•  Eric Evans Domain-Driven Design!


Top Related