perfect code

66
Perfect Code How to write high-quality code ARTEM TABALIN

Upload: artem-tabalin

Post on 14-Jun-2015

2.990 views

Category:

Software


0 download

DESCRIPTION

Learn how to write better code. Follow key software development principles like KISS, DRY, YAGNI, and SOLID. Know how to choose better names, structure your code, write methods, and design classes.

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!