21. high-quality programming code ii

91
High-Quality High-Quality Programming Code Programming Code Construction – Part Construction – Part II II Revealing the Secrets of Self- Revealing the Secrets of Self- Documenting Code Documenting Code Svetlin Nakov Svetlin Nakov Telerik Telerik Corporation Corporation www.telerik. com For C# Developers For C# Developers

Upload: intro-c-book

Post on 20-May-2015

30.187 views

Category:

Technology


0 download

DESCRIPTION

What is High-Quality Programming Code? Code Conventions Naming Identifiers in the Source Code: Classes, Interfaces, Structures, Namespaces, Methods, Fields, Constants, etc. Formatting the Code: Formatting Methods, Formatting Classes, Formatting Loops and Conditional Statements, Using Empty Lines, Breaking Long Statements High-Quality Methods: Method Intension, Method Behavior, Strong Cohesion and Loose Coupling, Method Length, Method Parameters Efficiently Using Variables: Declaration, Initialization, Scope, Span and Lifetime Efficiently Using Constants Efficiently Using Conditional Statements Defensive Programming Documentation and Self-Documenting Code Refactoring: Improving the Existing Code Exercises: Refactoring Existing Low-Quality Code

TRANSCRIPT

Page 1: 21. High-Quality Programming Code II

High-Quality High-Quality Programming Code Programming Code Construction – Part Construction – Part

IIIIRevealing the Secrets of Self-Revealing the Secrets of Self-

Documenting CodeDocumenting Code

Svetlin NakovSvetlin NakovTelerik Telerik

CorporationCorporationwww.telerik.com

For C# DevelopersFor C# Developers

Page 2: 21. High-Quality Programming Code II

Table of ContentsTable of Contents High-Quality MethodsHigh-Quality Methods

Cohesion and CouplingCohesion and Coupling Using Variables CorrectlyUsing Variables Correctly

Scope, Span, LifetimeScope, Span, Lifetime Using Expressions CorrectlyUsing Expressions Correctly Using ConstantsUsing Constants Using Control-Flow Logic CorrectlyUsing Control-Flow Logic Correctly

Conditional StatementsConditional Statements LoopsLoops

2

Page 3: 21. High-Quality Programming Code II

Table of Contents (2)Table of Contents (2)

Defensive ProgrammingDefensive Programming Assertions and ExceptionsAssertions and Exceptions

Comments and DocumentationComments and Documentation Self-Documenting CodeSelf-Documenting Code

Code RefactoringCode Refactoring Improving the Quality ofImproving the Quality of

Existing CodeExisting Code

3

Page 4: 21. High-Quality Programming Code II

High-Quality MethodsHigh-Quality MethodsHow to Design and Implement High-How to Design and Implement High-

Quality Methods? Understanding Quality Methods? Understanding Cohesion and CouplingCohesion and Coupling

Page 5: 21. High-Quality Programming Code II

Why We Need Why We Need Methods?Methods?

Methods are important inMethods are important in software developmentsoftware development Reduce complexityReduce complexity

Divide and conquer: complex problems Divide and conquer: complex problems can be split into composition of several can be split into composition of several simple onessimple ones

Improve code readabilityImprove code readability

Small methods with good method names Small methods with good method names make the code self-documentingmake the code self-documenting

Avoid duplicating codeAvoid duplicating code

Duplicating code is hard to maintainDuplicating code is hard to maintain5

Page 6: 21. High-Quality Programming Code II

Why We Need Why We Need Methods? (2)Methods? (2)

Methods simplify software Methods simplify software developmentdevelopment Hide implementation detailsHide implementation details

Complex logic is encapsulated and Complex logic is encapsulated and hidden behind a simple interfacehidden behind a simple interface

Algorithms and data structures are Algorithms and data structures are hidden and can be transparently hidden and can be transparently replaced laterreplaced later

Increase the level of abstractionIncrease the level of abstraction

Methods address the business problem, Methods address the business problem, not the technical implementation:not the technical implementation:

6

Bank.accounts[customer].deposit(500);Bank.accounts[customer].deposit(500);

Page 7: 21. High-Quality Programming Code II

Using Methods: Using Methods: FundamentalsFundamentals

Fundamental principle of correct method Fundamental principle of correct method usage:usage:

Methods should do exactly what their names Methods should do exactly what their names saysay

Nothing lessNothing less

Nothing moreNothing more

In case of incorrect input or incorrect In case of incorrect input or incorrect preconditions, an error should be indicatedpreconditions, an error should be indicated

7

A method should do what its A method should do what its name says or should indicate an name says or should indicate an error. Any other behaviour is error. Any other behaviour is incorrect! incorrect!

Page 8: 21. High-Quality Programming Code II

Good Methods – Good Methods – ExamplesExamples

8

long Sum(int[] elements)long Sum(int[] elements){{ long sum = 0;long sum = 0; foreach (int element in elements)foreach (int element in elements) {{ sum = sum + element;sum = sum + element; }} return sum;return sum;}}

double CalcTriangleArea(double a, double b, double c)double CalcTriangleArea(double a, double b, double c){{ if (a <= 0 || b <= 0 || c <= 0)if (a <= 0 || b <= 0 || c <= 0) {{ throw new ArgumentException("Sides should be throw new ArgumentException("Sides should be positive.");positive."); }} double s = (a + b + c) / 2;double s = (a + b + c) / 2; double area = Math.Sqrt(s * (s - a) * (s - b) * (s - double area = Math.Sqrt(s * (s - a) * (s - b) * (s - c));c)); return area;return area;}}

Page 9: 21. High-Quality Programming Code II

Symptoms of Wrong Symptoms of Wrong MethodsMethods

Method that does something different than Method that does something different than its name, is wrong for at least one of these its name, is wrong for at least one of these reasons:reasons:

The method sometimes returns incorrect result The method sometimes returns incorrect result bugbug

The method returns incorrect output when its The method returns incorrect output when its input is incorrect or unusual input is incorrect or unusual low quality low quality

Acceptable for private methods onlyAcceptable for private methods only

The method does too many things The method does too many things bad cohesion bad cohesion

The method has side effects The method has side effects spaghetti code spaghetti code

Method returns strange value when an error Method returns strange value when an error condition happens condition happens it should indicate the error it should indicate the error

9

Page 10: 21. High-Quality Programming Code II

Wrong Methods – Wrong Methods – ExamplesExamples

10

long Sum(int[] elements)long Sum(int[] elements){{ long sum = 0;long sum = 0; for (int i = 0; i < elements.Length; i++)for (int i = 0; i < elements.Length; i++) {{ sum = sum + elements[i];sum = sum + elements[i]; elements[i] = 0;elements[i] = 0; }} return sum;return sum;}}

double CalcTriangleArea(double a, double b, double c)double CalcTriangleArea(double a, double b, double c){{ if (a <= 0 || b <= 0 || c <= 0)if (a <= 0 || b <= 0 || c <= 0) {{ return 0;return 0; }} double s = (a + b + c) / 2;double s = (a + b + c) / 2; double area = Math.Sqrt(s * (s - a) * (s - b) * (s - c));double area = Math.Sqrt(s * (s - a) * (s - b) * (s - c)); return area;return area;}}

Hidden side Hidden side effecteffect

Incorrect result. Incorrect result. Throw an Throw an exception exception instead.instead.

Page 11: 21. High-Quality Programming Code II

Strong CohesionStrong Cohesion Methods should have Methods should have strong cohesionstrong cohesion

Should address single task and address Should address single task and address it wellit well

Should have clear intentShould have clear intent Methods that address several tasks in Methods that address several tasks in

the same time are hard to be namedthe same time are hard to be named String cohesion is used in engineeringString cohesion is used in engineering

In computer hardware any PC In computer hardware any PC component solves a single taskcomponent solves a single task

E.g. hard disk performs a single task – E.g. hard disk performs a single task – storagestorage

11

Page 12: 21. High-Quality Programming Code II

Acceptable Types of Acceptable Types of CohesionCohesion

Functional cohesionFunctional cohesion (independent (independent function)function) Method performs certain well-Method performs certain well-

defined calculation and returns a defined calculation and returns a single resultsingle result

The entire input is passed through The entire input is passed through parameters and the entire output is parameters and the entire output is returned as resultreturned as result

No external dependencies or side No external dependencies or side effectseffects

Examples:Examples:12

Math.Sqrt(value) Math.Sqrt(value) square root square root

String.Substring(str, startIndex, length)String.Substring(str, startIndex, length)

Char.IsLetterOrDigit(ch)Char.IsLetterOrDigit(ch)

Page 13: 21. High-Quality Programming Code II

Acceptable Types of Acceptable Types of Cohesion (2)Cohesion (2)

Sequential cohesionSequential cohesion (algorithm)(algorithm) Method performs certain sequence of Method performs certain sequence of

operations to perform a single task and operations to perform a single task and achieve certain resultachieve certain result

It encapsulates an algorithmIt encapsulates an algorithm

Example:Example:

1.1.Connect to mail serverConnect to mail server

2.2.Send message headersSend message headers

3.3.Send message bodySend message body

4.4.Disconnect from the serverDisconnect from the server 13

SendEmail(recipient, subject, body)SendEmail(recipient, subject, body)

Page 14: 21. High-Quality Programming Code II

Acceptable Types of Acceptable Types of Cohesion (3)Cohesion (3)

Communicational cohesionCommunicational cohesion (common data)(common data) A set of operations used to process certain A set of operations used to process certain

data and produce a resultdata and produce a result Example:Example:

1.1.Retrieve input data from databaseRetrieve input data from database

2.2.Perform internal calculations over retrieved Perform internal calculations over retrieved datadata

3.3.Build the reportBuild the report

4.4.Format the report as Excel worksheetFormat the report as Excel worksheet

5.5.Display the Excel worksheet on the screenDisplay the Excel worksheet on the screen14

DisplayAnnualExpensesReport(int employeeId)DisplayAnnualExpensesReport(int employeeId)

Page 15: 21. High-Quality Programming Code II

Acceptable Types of Acceptable Types of Cohesion (4)Cohesion (4)

Temporal cohesion Temporal cohesion (time related (time related activities)activities) Operations that are generally not related Operations that are generally not related

but need to happen in a certain momentbut need to happen in a certain moment Examples:Examples:

1.1. Load user settingsLoad user settings

2.2. Check for updatesCheck for updates

3.3. Load all invoices from the databaseLoad all invoices from the database

Sequence of actions to handle the eventSequence of actions to handle the event15

InitializeApplication()InitializeApplication()

ButtonConfirmClick()ButtonConfirmClick()

Page 16: 21. High-Quality Programming Code II

Unacceptable CohesionUnacceptable Cohesion Logical cohesionLogical cohesion

Performs a different operation Performs a different operation depending on an input parameterdepending on an input parameter

Incorrect example:Incorrect example:

Can be acceptable in event handlers (e.g. Can be acceptable in event handlers (e.g. the the KeyDownKeyDown event in Windows Forms) event in Windows Forms)

16

object ReadAll(int operationCode)object ReadAll(int operationCode){{ if (operationCode == 1) … // Read person if (operationCode == 1) … // Read person namename else if (operationCode == 2) … // Read else if (operationCode == 2) … // Read addressaddress else if (operationCode == 3) … // Read dateelse if (operationCode == 3) … // Read date … …}}

Page 17: 21. High-Quality Programming Code II

Unacceptable CohesionUnacceptable Cohesion Coincidental cohesion Coincidental cohesion (spaghetti)(spaghetti)

Not related (random) operations are Not related (random) operations are grouped in a method for unclear reasongrouped in a method for unclear reason

Incorrect example:Incorrect example:

1.1.Prepares annual incomes report for given Prepares annual incomes report for given customercustomer

2.2.Sorts an array of integers in increasing orderSorts an array of integers in increasing order

3.3.Calculates the square root of given numberCalculates the square root of given number

4.4.Converts given MP3 file into WMA formatConverts given MP3 file into WMA format

5.5.Sends email to given customerSends email to given customer

17

HandleStuff(customerId, int[], ref sqrtValue, HandleStuff(customerId, int[], ref sqrtValue, mp3FileName, emailAddress)mp3FileName, emailAddress)

Page 18: 21. High-Quality Programming Code II

Loose CouplingLoose Coupling What is What is loose couplingloose coupling??

Minimal dependences of the method on Minimal dependences of the method on the other parts of the source codethe other parts of the source code

Minimal dependences on the class Minimal dependences on the class members or external classes and their members or external classes and their membersmembers

No side effectsNo side effects

If the coupling is loose, we can easily If the coupling is loose, we can easily reuse a method or group of methods in reuse a method or group of methods in a new projecta new project

Tight coupling Tight coupling spaghetti code spaghetti code18

Page 19: 21. High-Quality Programming Code II

Loose Coupling (2)Loose Coupling (2) The ideal couplingThe ideal coupling

A methods depends only on its A methods depends only on its parametersparameters

Does not have any other input or outputDoes not have any other input or output

Example: Example: Math.SqrtMath.Sqrt Real worldReal world

Complex software cannot avoid coupling Complex software cannot avoid coupling but could make it as loose as possiblebut could make it as loose as possible

Example: complex encryption algorithm Example: complex encryption algorithm performs initialization, encryption, performs initialization, encryption, finalizationfinalization

19

Page 20: 21. High-Quality Programming Code II

Coupling – ExampleCoupling – Example Intentionally increased coupling for Intentionally increased coupling for

more flexibility (.NET cryptography more flexibility (.NET cryptography API):API):

20

byte[] EncryptAES(byte[] inputData, byte[] byte[] EncryptAES(byte[] inputData, byte[] secretKey)secretKey){{ Rijndael cryptoAlg = new RijndaelManaged();Rijndael cryptoAlg = new RijndaelManaged(); cryptoAlg.Key = secretKey;cryptoAlg.Key = secretKey; cryptoAlg.GenerateIV();cryptoAlg.GenerateIV(); MemoryStream destStream = new MemoryStream();MemoryStream destStream = new MemoryStream(); CryptoStream csEncryptor = new CryptoStream(CryptoStream csEncryptor = new CryptoStream( destStream, cryptoAlg.CreateEncryptor(),destStream, cryptoAlg.CreateEncryptor(), CryptoStreamMode.Write);CryptoStreamMode.Write); csEncryptor.Write(inputData, 0, csEncryptor.Write(inputData, 0, inputData.Length);inputData.Length); csEncryptor.FlushFinalBlock();csEncryptor.FlushFinalBlock(); byte[] encryptedData = destStream.ToArray();byte[] encryptedData = destStream.ToArray(); return encryptedData;return encryptedData;}}

Page 21: 21. High-Quality Programming Code II

Loose Coupling – Loose Coupling – ExampleExample

To reduce coupling we can make To reduce coupling we can make utility classes that hide the complex utility classes that hide the complex logic and provide simple logic and provide simple straightforward interface (a.k.a. straightforward interface (a.k.a. façade):façade):

21

byte[] EncryptAES(byte[] inputData, byte[] byte[] EncryptAES(byte[] inputData, byte[] secretKey)secretKey){{ MemoryStream inputStream =MemoryStream inputStream = new MemoryStream(inputData);new MemoryStream(inputData); MemoryStream outputStream = new MemoryStream();MemoryStream outputStream = new MemoryStream(); EncryptionUtils.EncryptAES(EncryptionUtils.EncryptAES( inputStream, outputStream, secretKey);inputStream, outputStream, secretKey); byte[] encryptedData = outputStream.ToArray();byte[] encryptedData = outputStream.ToArray(); return encryptedData;return encryptedData;}}

Page 22: 21. High-Quality Programming Code II

Tight Coupling – Tight Coupling – ExampleExample

Passing parameters through class Passing parameters through class fieldsfields Typical example of tight couplingTypical example of tight coupling Don't do this unless you have a good Don't do this unless you have a good

reason!reason!

22

class Sumatorclass Sumator{{ public int a, b;public int a, b;

int Sum()int Sum() {{ return a + b;return a + b; }}

static void Main()static void Main() {{ Sumator sumator = new Sumator() { a = 3, b = 5 };Sumator sumator = new Sumator() { a = 3, b = 5 }; Console.WriteLine(sumator.Sum());Console.WriteLine(sumator.Sum()); }}}}

Why don't pass Why don't pass the numbers as the numbers as

parameters?parameters?

Page 23: 21. High-Quality Programming Code II

Loose Coupling and Loose Coupling and OOPOOP

Reducing coupling with OOP Reducing coupling with OOP techniquestechniques AbstractionAbstraction

Define a public interface and hide the Define a public interface and hide the implementation detailsimplementation details

EncapsulationEncapsulation

Make methods and fields private unless Make methods and fields private unless they are definitely neededthey are definitely needed

Define new members as privateDefine new members as private

Increase visibility as soon as this is Increase visibility as soon as this is neededneeded 23

Page 24: 21. High-Quality Programming Code II

Acceptable CouplingAcceptable Coupling Method is coupled to its parametersMethod is coupled to its parameters

This is the best type of couplingThis is the best type of coupling

Method in a class is coupled to some class Method in a class is coupled to some class fieldsfields

This coupling is usual, do not worry too muchThis coupling is usual, do not worry too much

Method in a class is coupled to static Method in a class is coupled to static methods, properties or constants in external methods, properties or constants in external classclass

This is normal, usually is not a problemThis is normal, usually is not a problem

Method is coupled to external static fieldsMethod is coupled to external static fields

Avoid this, classes should keep their fields Avoid this, classes should keep their fields privateprivate

24

Page 25: 21. High-Quality Programming Code II

Non-Acceptable Non-Acceptable CouplingCoupling

Method in a class is coupled to static Method in a class is coupled to static fields in external classfields in external class Avoid it Avoid it consider refactoring consider refactoring

Methods take as input data some fields Methods take as input data some fields that could be passed as parametersthat could be passed as parameters Check the intent of the methodCheck the intent of the method

Is it designed to process internal class Is it designed to process internal class data or is utility methoddata or is utility method

Method is defined public without being Method is defined public without being part of the public class's interface part of the public class's interface possible couplingpossible coupling

25

Page 26: 21. High-Quality Programming Code II

Methods ParametersMethods Parameters Put most important parameters Put most important parameters

firstfirst First put the main input parametersFirst put the main input parameters Put non-important optional Put non-important optional

parameters lastparameters last Example:Example:

Incorrect example:Incorrect example:

26

void RegisterUser(string username, string void RegisterUser(string username, string password, Date accountExpirationDate, Role[] password, Date accountExpirationDate, Role[] roles)roles)

void RegisterUser(Role[] roles, string password, void RegisterUser(Role[] roles, string password, string username, Date accountExpirationDate,)string username, Date accountExpirationDate,)

void RegisterUser(string password, Date void RegisterUser(string password, Date accountExpirationDate, Role[] roles, string accountExpirationDate, Role[] roles, string username)username)

Page 27: 21. High-Quality Programming Code II

Methods Parameters Methods Parameters (2)(2)

Do not modify the input Do not modify the input parametersparameters Use new variable insteadUse new variable instead Incorrect example:Incorrect example:

Correct example:Correct example:

27

bool CheckLogin(string username, string password)bool CheckLogin(string username, string password){{ username = username.ToLower();username = username.ToLower(); … … // Check the username / password here// Check the username / password here}}

bool CheckLogin(string username, string password)bool CheckLogin(string username, string password){{ string usernameLowercase = username.ToLower();string usernameLowercase = username.ToLower(); … … // Check the username / password here// Check the username / password here}}

Page 28: 21. High-Quality Programming Code II

Methods Parameters Methods Parameters (3)(3)

Use parameters consistentlyUse parameters consistently Use the same names and the same Use the same names and the same

order in all methodsorder in all methods

Incorrect example:Incorrect example:

Output parameters should be put Output parameters should be put lastlast

28

void EncryptFile(Stream input, Stream output, string void EncryptFile(Stream input, Stream output, string key);key);

void DecryptFile(string key, Stream output, Stream void DecryptFile(string key, Stream output, Stream input);input);

FindCustomersAndIncomes(Region region, out FindCustomersAndIncomes(Region region, out Customer[] customers, out decimal[] incomes)Customer[] customers, out decimal[] incomes)

Page 29: 21. High-Quality Programming Code II

Pass Entire Object or Pass Entire Object or Its Fields?Its Fields?

When should we pass an object When should we pass an object containing few values and when these containing few values and when these values separately?values separately? Sometime we pass an object and use only Sometime we pass an object and use only

a single field of ita single field of it – – it is a good practice?it is a good practice? Examples:Examples:

Look at the method's level of abstractionLook at the method's level of abstraction

Is it intended to operate with employees of Is it intended to operate with employees of with rates and months? with rates and months? the first is the first is incorrectincorrect 29

CalculateSalary(Employee employee, int months);CalculateSalary(Employee employee, int months);

CalculateSalary(double rate, int months);CalculateSalary(double rate, int months);

Page 30: 21. High-Quality Programming Code II

How Much Parameters How Much Parameters Methods Should Have?Methods Should Have?

Limit the number of method Limit the number of method parameters to 7 (+/-2)parameters to 7 (+/-2) 7 is a magic number in psychology7 is a magic number in psychology

Human brain cannot process more Human brain cannot process more than 7 (+/-2) things in the same timethan 7 (+/-2) things in the same time

If the parameters need to be too If the parameters need to be too much reconsider the method intent much reconsider the method intent does it have clear intent? does it have clear intent?

Consider putting few parameters in a Consider putting few parameters in a new classnew class

30

Page 31: 21. High-Quality Programming Code II

Methods LengthMethods Length How long should a method be?How long should a method be?

There is no specific restrictionThere is no specific restriction Avoid methods longer than one screen (30 Avoid methods longer than one screen (30

lines)lines) Long methods are not always badLong methods are not always bad

Be sure you have a good reason for their Be sure you have a good reason for their lengthlength

Cohesion and coupling are more important Cohesion and coupling are more important than the method length!than the method length!

Long methods often contain portions that Long methods often contain portions that could be extracted as separate methods could be extracted as separate methods with good name and clear intent with good name and clear intent check check this!this! 31

Page 32: 21. High-Quality Programming Code II

Using VariablesUsing VariablesBest PracticesBest Practices

Page 33: 21. High-Quality Programming Code II

Retuning Result from a Retuning Result from a MethodMethod

Always assign the result of a Always assign the result of a method in some variable before method in some variable before returning it. Benefits:returning it. Benefits: Improved code readabilityImproved code readability

The returned value has self-The returned value has self-documenting namedocumenting name

Simplified debuggingSimplified debugging

Example:Example:

Incorrect example:Incorrect example: 33

return days * hoursPerDay * ratePerHour;return days * hoursPerDay * ratePerHour;

int salary = days * hoursPerDay * ratePerHour;int salary = days * hoursPerDay * ratePerHour;return salary;return salary;

The intent of The intent of the formula is the formula is

obvious.obvious.

We can put a breakpoint We can put a breakpoint at this line and check if at this line and check if

the result is correct.the result is correct.

Page 34: 21. High-Quality Programming Code II

Variable InitializationVariable Initialization Initialize all variables before their first Initialize all variables before their first

usageusage Class variables (fields) are automatically Class variables (fields) are automatically

initialized with initialized with 00 / / nullnull by the C# compiler by the C# compiler You still get a warning messageYou still get a warning message

Local variables should be manually Local variables should be manually initializedinitialized This C# code will result in compilation error:This C# code will result in compilation error:

We can initialize variables at their We can initialize variables at their declaration:declaration:

34

int value;int value;Console.WriteLine(value);Console.WriteLine(value);

int value = 0;int value = 0;Console.WriteLine(value);Console.WriteLine(value);

Page 35: 21. High-Quality Programming Code II

Partially Initialized Partially Initialized ObjectsObjects

Ensure objects cannot get into Ensure objects cannot get into partially initialized statepartially initialized state Make all fields private and require Make all fields private and require

valid values for all mandatory fields valid values for all mandatory fields in all constructorsin all constructors

Example: Example: StudentStudent object is invalid object is invalid unless it has unless it has NameName and and FacultyNumberFacultyNumber

35

class Studentclass Student{{ private string name, facultyNumber;private string name, facultyNumber;

public Student(string name, string public Student(string name, string facultyNumber)facultyNumber) { … }{ … }}}

Page 36: 21. High-Quality Programming Code II

Variable ScopeVariable Scope Variable scope defines how "famous" is a Variable scope defines how "famous" is a

variable in the programvariable in the program StaticStatic variables are more "famous" than variables are more "famous" than

instanceinstance variables, and they are more "famous" variables, and they are more "famous" than than locallocal

Variables' visibility is directly related to their Variables' visibility is directly related to their scopescope publicpublic, , protectedprotected, , internalinternal, , privateprivate

Always try to reduce the variable's scopeAlways try to reduce the variable's scope This reduces potential couplingThis reduces potential coupling Avoid public fields (exception: Avoid public fields (exception: readonlyreadonly / / constconst))

Access all fields through properties / methodsAccess all fields through properties / methods36

Page 37: 21. High-Quality Programming Code II

Exceeded Scope – Exceeded Scope – ExampleExample

37

public class Globalspublic class Globals{{ public static int state = 0;public static int state = 0;}}

public class Genious public class Genious {{ public static void PrintSomething()public static void PrintSomething() {{ if (Globals.state == 0)if (Globals.state == 0) {{ Console.WriteLine("Hello.");Console.WriteLine("Hello."); }} elseelse {{ Console.WriteLine("Good bye.");Console.WriteLine("Good bye."); }} }}}}

Page 38: 21. High-Quality Programming Code II

Variable Span and Variable Span and LifetimeLifetime

Variable Variable spanspan

The average number of lines of code The average number of lines of code (LOC) between variable usages(LOC) between variable usages

Variable Variable lifetimelifetime

The number of lines of code (LOC) The number of lines of code (LOC)

between the first and the last variable between the first and the last variable

usage in a blockusage in a block Keep variable span and lifetime as Keep variable span and lifetime as

low as possiblelow as possible

38

Always define and initialize Always define and initialize variables just before their first variables just before their first use and never before it!use and never before it!

Page 39: 21. High-Quality Programming Code II

Unneeded Large Unneeded Large Variable Span and Variable Span and

LifetimeLifetime

39

int count;int count;int[] numbers = new int[100];int[] numbers = new int[100];for (int i = 0; i < numbers.Length; i++)for (int i = 0; i < numbers.Length; i++){{ numbers[i] = i;numbers[i] = i;}}count = 0;count = 0;for (int i = 0; i < numbers.Length / 2; i++)for (int i = 0; i < numbers.Length / 2; i++){{ numbers[i] = numbers[i] * numbers[i];numbers[i] = numbers[i] * numbers[i];}}for (int i = 0; i < numbers.Length; i++)for (int i = 0; i < numbers.Length; i++){{ if (numbers[i] % 3 == 0)if (numbers[i] % 3 == 0) {{ count++;count++; }}}}Console.WriteLine(count);Console.WriteLine(count);

span =19 / 4

= 4.75

lifetime

("count") = 19

Page 40: 21. High-Quality Programming Code II

Reduced Reduced Variable Span Variable Span

and Lifetimeand Lifetime

40

int[] numbers = new int[100];int[] numbers = new int[100];for (int i = 0; i < numbers.Length; i++)for (int i = 0; i < numbers.Length; i++){{ numbers[i] = i;numbers[i] = i;}}for (int i = 0; i < numbers.Length / 2; i++)for (int i = 0; i < numbers.Length / 2; i++){{ numbers[i] = numbers[i] * numbers[i];numbers[i] = numbers[i] * numbers[i];}}int count = 0;int count = 0;for (int i = 0; i < numbers.Length; i++)for (int i = 0; i < numbers.Length; i++){{ if (numbers[i] % 3 == 0)if (numbers[i] % 3 == 0) {{ count++;count++; }}}}Console.WriteLine(count);Console.WriteLine(count);

span=9 / 3 = 3

lifetime = 9

Page 41: 21. High-Quality Programming Code II

Single PurposeSingle Purpose Variables should have single purposeVariables should have single purpose

Never use a single variable for multiple Never use a single variable for multiple purposes!purposes!

Economizing memory is not an excuseEconomizing memory is not an excuse Can you choose a good name for variable Can you choose a good name for variable

that is used for several purposes?that is used for several purposes? Example: variable used to count students Example: variable used to count students

of to keep the average of their gradesof to keep the average of their grades

Proposed name: Proposed name: studentsCountOrAvgGradestudentsCountOrAvgGrade

41

Page 42: 21. High-Quality Programming Code II

Variables – Other Variables – Other SuggestionsSuggestions

Don't define variables that are not Don't define variables that are not usedused Compilers usually issues warningsCompilers usually issues warnings

Don't use variables with hidden Don't use variables with hidden purposepurpose Incorrect example:Incorrect example:

Instead use enumeration:Instead use enumeration: 42

int mode = 1;int mode = 1;……if (mode == 1) …; // Readif (mode == 1) …; // Readif (mode == 2) …; // Writeif (mode == 2) …; // Writeif (mode == 3) …; // Read and writeif (mode == 3) …; // Read and write

enum ResourceAccessMode { Read, Write, enum ResourceAccessMode { Read, Write, ReadWrite }ReadWrite }

Page 43: 21. High-Quality Programming Code II

Using Using ExpressionsExpressions

Best PracticesBest Practices

Page 44: 21. High-Quality Programming Code II

Avoid Complex Avoid Complex ExpressionsExpressions

Never use complex expressions in the Never use complex expressions in the code!code! Incorrect example:Incorrect example:

Complex expressions are evil because:Complex expressions are evil because: Make code hard to read and understand, Make code hard to read and understand,

hard to debug, hard to modify and hard to hard to debug, hard to modify and hard to maintainmaintain 44

for (int i=0; i<xCoords.length; i++) {for (int i=0; i<xCoords.length; i++) { for (int j=0; j<yCoords.length; j++) {for (int j=0; j<yCoords.length; j++) { matrix[i][j] = matrix[i][j] = matrix[xCoords[findMax(i)+1]][yCoords[findMin(j)-matrix[xCoords[findMax(i)+1]][yCoords[findMin(j)-1]] *1]] * matrix[yCoords[findMax(j)+1]][xCoords[findMin(i)-matrix[yCoords[findMax(j)+1]][xCoords[findMin(i)-1]];1]]; }}}}

What shall we do if we get What shall we do if we get at this line at this line

IndexOutOfRangeExceptionIndexOutOfRangeException??

There are 10 potential sources of There are 10 potential sources of IndexOutOfRangeExceptionIndexOutOfRangeException in this in this

expression!expression!

Page 45: 21. High-Quality Programming Code II

Simplifying Complex Simplifying Complex ExpressionsExpressions

45

for (int i = 0; i < xCoords.length; i++)for (int i = 0; i < xCoords.length; i++){{ for (int j = 0; j < yCoords.length; j++)for (int j = 0; j < yCoords.length; j++) {{ int maxStartIndex = findMax(i) + 1;int maxStartIndex = findMax(i) + 1; int minStartIndex = findMin(i) - 1;int minStartIndex = findMin(i) - 1; int minXcoord = xCoords[minStartIndex];int minXcoord = xCoords[minStartIndex]; int maxXcoord = xCoords[maxStartIndex];int maxXcoord = xCoords[maxStartIndex]; int minYcoord = yCoords[minStartIndex];int minYcoord = yCoords[minStartIndex]; int maxYcoord = yCoords[maxStartIndex];int maxYcoord = yCoords[maxStartIndex]; int newValue = int newValue = matrix[maxXcoord][minYcoord] *matrix[maxXcoord][minYcoord] * matrix[maxYcoord][minXcoord];matrix[maxYcoord][minXcoord]; matrix[i][j] = newValue;matrix[i][j] = newValue; }}}}

Page 46: 21. High-Quality Programming Code II

Using ConstantsUsing ConstantsWhen and How to Use Constants?When and How to Use Constants?

Page 47: 21. High-Quality Programming Code II

Avoid Magic Numbers and Avoid Magic Numbers and StringsStrings

What is What is magic numbermagic number or or valuevalue?? Magic numbers / values are all literals Magic numbers / values are all literals

different than different than 00, , 11, , -1-1, , nullnull and and """" (empty (empty string)string)

Avoid using magic numbers / valuesAvoid using magic numbers / values They are hard to maintainThey are hard to maintain

When change occurs, you need to modify all When change occurs, you need to modify all occurrences of the magic number / constantoccurrences of the magic number / constant

Their meaning is not obviousTheir meaning is not obvious

Example: what does the number Example: what does the number 10241024 mean?mean?

47

Page 48: 21. High-Quality Programming Code II

The Evil Magic NumbersThe Evil Magic Numbers

48

public class GeometryUtilspublic class GeometryUtils{{ public static double CalcCircleArea(double radius)public static double CalcCircleArea(double radius) {{ double area = 3.14159206 * radius * radius;double area = 3.14159206 * radius * radius; return area;return area; }} public static double CalcCirclePerimeter(double radius)public static double CalcCirclePerimeter(double radius) {{ double perimeter = 6.28318412 * radius;double perimeter = 6.28318412 * radius; return perimeter;return perimeter; }} public static double CalcElipseArea(double axis1, double public static double CalcElipseArea(double axis1, double axis2)axis2) {{ double area = 3.14159206 * axis1 * axis2;double area = 3.14159206 * axis1 * axis2; return area;return area; }}}}

Page 49: 21. High-Quality Programming Code II

Turning MagicTurning MagicNumbers into Numbers into

ConstantsConstants

49

public class GeometryUtilspublic class GeometryUtils{{ public const double PI = 3.14159206;public const double PI = 3.14159206; public static double CalcCircleArea(double radius)public static double CalcCircleArea(double radius) {{ double area = PI * radius * radius;double area = PI * radius * radius; return area;return area; }} public static double CalcCirclePerimeter(double radius)public static double CalcCirclePerimeter(double radius) {{ double perimeter = 2 * PI * radius;double perimeter = 2 * PI * radius; return perimeter;return perimeter; }} public static double CalcElipseArea(double axis1, double public static double CalcElipseArea(double axis1, double axis2)axis2) {{ double area = PI * axis1 * axis2;double area = PI * axis1 * axis2; return area;return area; }}}}

Page 50: 21. High-Quality Programming Code II

When to Use When to Use Constants?Constants?

Constants should be used in the Constants should be used in the following cases:following cases:

When we need to use numbers or When we need to use numbers or other values and their logical meaning other values and their logical meaning and value are not obviousand value are not obvious

File namesFile names

Mathematical constantsMathematical constants

Bounds and rangesBounds and ranges50

public const string SettingsFileName =public const string SettingsFileName = "ApplicationSettings.xml";"ApplicationSettings.xml";

public const double E = 2.7182818284;public const double E = 2.7182818284;

public const int READ_BUFFER_SIZE = 5 * 1024 public const int READ_BUFFER_SIZE = 5 * 1024 *1024;*1024;

Page 51: 21. High-Quality Programming Code II

When to Avoid When to Avoid Constants?Constants?

Sometime it is better to keep the Sometime it is better to keep the magic values instead of using a magic values instead of using a constantconstant Error messages and exception Error messages and exception

descriptionsdescriptions

SQL commands for database SQL commands for database operationsoperations

Titles of GUI elements (labels, Titles of GUI elements (labels, buttons, menus, dialogs, etc.)buttons, menus, dialogs, etc.)

For internationalization purposes For internationalization purposes use use resourcesresources, not constants, not constants 51

Page 52: 21. High-Quality Programming Code II

Using Using Control Control

ConstructsConstructsUsing Conditional Using Conditional

Statements and Loops Statements and Loops CorrectlyCorrectly

Page 53: 21. High-Quality Programming Code II

Using Conditional Using Conditional StatementsStatements

Always use Always use {{ and and }} for the conditional for the conditional statements body, even when it is a single statements body, even when it is a single line:line:

Why omitting the brackets could be harmful?Why omitting the brackets could be harmful?

This is misleading code + misleading This is misleading code + misleading formattingformatting

53

if (condition)if (condition){{ DoSometing();DoSometing();}}

if (condition)if (condition) DoSomething();DoSomething(); DoAnotherThing();DoAnotherThing();DoDifferentThing();DoDifferentThing();

Page 54: 21. High-Quality Programming Code II

Use Simple ConditionsUse Simple Conditions Do not use complex Do not use complex ifif conditions conditions

You can always simplify them by You can always simplify them by introducing boolean variables or boolean introducing boolean variables or boolean methodsmethods

Incorrect example:Incorrect example:

Complex boolean expressions are harmfulComplex boolean expressions are harmful

How you will find the problem if you get How you will find the problem if you get IndexOutOfRangeExceptionIndexOutOfRangeException??

54

if (x > 0 && y > 0 && x < Width-1 && y < if (x > 0 && y > 0 && x < Width-1 && y < Height-1 &&Height-1 && matrix[x, y] == 0 && matrix[x-1, y] == 0 &&matrix[x, y] == 0 && matrix[x-1, y] == 0 && matrix[x+1, y] == 0 && matrix[x, y-1] == 0 &&matrix[x+1, y] == 0 && matrix[x, y-1] == 0 && matrix[x, y+1] == 0 && !visited[x, y])matrix[x, y+1] == 0 && !visited[x, y])

Page 55: 21. High-Quality Programming Code II

Simplifying Boolean Simplifying Boolean ConditionsConditions

The last example can be easily refactored The last example can be easily refactored into self-documenting code:into self-documenting code:

Now the code is:Now the code is: Easy to read – the logic of the condition is Easy to read – the logic of the condition is

clearclear

Easy to debug – breakpoint can be put at Easy to debug – breakpoint can be put at the the ifif 55

bool inRange = bool inRange = x > 0 && y > 0 && x < Width-1 && y < Height-1;x > 0 && y > 0 && x < Width-1 && y < Height-1;bool emptyCellAndNeighbours =bool emptyCellAndNeighbours = matrix[x, y] == 0 && matrix[x-1, y] == 0 &&matrix[x, y] == 0 && matrix[x-1, y] == 0 && matrix[x+1, y] == 0 && matrix[x, y-1] == 0 &&matrix[x+1, y] == 0 && matrix[x, y-1] == 0 && matrix[x, y+1] == 0;matrix[x, y+1] == 0;if (inRange && emptyCellAndNeighbours && !if (inRange && emptyCellAndNeighbours && !visited[x, y])visited[x, y])

Page 56: 21. High-Quality Programming Code II

Avoid Deep Nesting of Avoid Deep Nesting of BlocksBlocks

Deep nesting of conditional Deep nesting of conditional statements and loops makes the statements and loops makes the code unclearcode unclear Deeply nested code is complex and Deeply nested code is complex and

hard to read and understandhard to read and understand

Usually you can extract portions of Usually you can extract portions of the code in separate methodsthe code in separate methods

This simplifies the logic of the codeThis simplifies the logic of the code

Using good method name makes the Using good method name makes the code self-documentingcode self-documenting

56

Page 57: 21. High-Quality Programming Code II

Deep Nesting – ExampleDeep Nesting – Example

57

if (maxElem != Int32.MaxValue)if (maxElem != Int32.MaxValue){{ if (arr[i] < arr[i + 1])if (arr[i] < arr[i + 1]) {{ if (arr[i + 1] < arr[i + 2])if (arr[i + 1] < arr[i + 2]) {{ if (arr[i + 2] < arr[i + 3])if (arr[i + 2] < arr[i + 3]) {{ maxElem = arr[i + 3];maxElem = arr[i + 3]; }} elseelse {{ maxElem = arr[i + 2];maxElem = arr[i + 2]; }} }} elseelse {{ if (arr[i + 1] < arr[i + 3])if (arr[i + 1] < arr[i + 3]) {{ maxElem = arr[i + 3];maxElem = arr[i + 3]; }} elseelse {{ maxElem = arr[i + 1];maxElem = arr[i + 1]; }} }} }} (continues on the next slide)

Page 58: 21. High-Quality Programming Code II

Deep Nesting – Example Deep Nesting – Example (2)(2)

58

elseelse {{ if (arr[i] < arr[i + 2])if (arr[i] < arr[i + 2]) {{ if (arr[i + 2] < arr[i + 3])if (arr[i + 2] < arr[i + 3]) {{ maxElem = arr[i + 3];maxElem = arr[i + 3]; }} elseelse {{ maxElem = arr[i + 2];maxElem = arr[i + 2]; }} }} elseelse {{ if (arr[i] < arr[i + 3])if (arr[i] < arr[i + 3]) {{ maxElem = arr[i + 3];maxElem = arr[i + 3]; }} elseelse {{ maxElem = arr[i];maxElem = arr[i]; }} }} }}}}

Page 59: 21. High-Quality Programming Code II

Avoiding Deep Nesting – Avoiding Deep Nesting – ExampleExample

59

private static int Max(int i, int j)private static int Max(int i, int j){{ if (i < j)if (i < j) {{ return j;return j; }} elseelse {{ return i;return i; }}}}

private static int Max(int i, int j, int k)private static int Max(int i, int j, int k){{ if (i < j)if (i < j) {{ int maxElem = Max(j, k);int maxElem = Max(j, k); return maxElem;return maxElem; }} elseelse {{ int maxElem = Max(i, k);int maxElem = Max(i, k); return maxElem;return maxElem; }}}} (continues on the next slide)

Page 60: 21. High-Quality Programming Code II

Avoiding Deep Nesting – Avoiding Deep Nesting – ExampleExample

60

private static int FindMax(int[] arr, int i)private static int FindMax(int[] arr, int i){{ if (arr[i] < arr[i + 1])if (arr[i] < arr[i + 1]) {{ int maxElem = Max(arr[i + 1], arr[i + 2], arr[i + int maxElem = Max(arr[i + 1], arr[i + 2], arr[i + 3]);3]); return maxElem;return maxElem; }} elseelse {{ int maxElem = Max(arr[i], arr[i + 2], arr[i + 3]);int maxElem = Max(arr[i], arr[i + 2], arr[i + 3]); return maxElem;return maxElem; }}}}

if (maxElem != Int32.MaxValue) {if (maxElem != Int32.MaxValue) { maxElem = FindMax(arr, i);maxElem = FindMax(arr, i);}}

Page 61: 21. High-Quality Programming Code II

Using Case StatementUsing Case Statement Choose the most effective ordering of cases

Put the normal (usual) case first

Order cases by frequency

Put the most unusual (exceptional) case last

Order cases alphabetically or numerically

Keep the actions of each case simple

Extract complex logic in separate methods

Use the default clause in a case statement or the last else in a chain of if-else to trap errors

61

Page 62: 21. High-Quality Programming Code II

Bad Case StatementBad Case Statement

62

void ProcessNextChar(char ch)void ProcessNextChar(char ch){{ switch (parseState)switch (parseState) {{ InTag:InTag: if (ch == ">")if (ch == ">") {{ Console.WriteLine("Found tag: {0}", tag);Console.WriteLine("Found tag: {0}", tag); text = "";text = ""; parseState = ParseState.OutOfTag;parseState = ParseState.OutOfTag; }} elseelse {{ tag = tag + ch;tag = tag + ch; }} break;break; OutOfTag:OutOfTag: … … }}}}

Page 63: 21. High-Quality Programming Code II

Improved Case Improved Case StatementStatement

63

void ProcessNextChar(char ch)void ProcessNextChar(char ch){{ switch (parseState)switch (parseState) {{ InTag:InTag: ProcessCharacterInTag(ch);ProcessCharacterInTag(ch); break;break; OutOfTag:OutOfTag: ProcessCharacterOutOfTag(ch);ProcessCharacterOutOfTag(ch); break;break; default:default: throw new Exception("Invalid parse state: " +throw new Exception("Invalid parse state: " + parseState);parseState); }}}}

Page 64: 21. High-Quality Programming Code II

Using LoopsUsing Loops Choosing the correct type of loop:Choosing the correct type of loop:

Use Use forfor loop to repeat some block of code loop to repeat some block of code a certain number of timesa certain number of times

Use Use foreachforeach loop to process each element loop to process each element of array or collectionof array or collection

Use Use whilewhile / / dodo--whilewhile loop when you don't loop when you don't know how many times a block should be know how many times a block should be repeatedrepeated

Avoid deep nesting of loopsAvoid deep nesting of loops You can extract the loop body in a new You can extract the loop body in a new

methodmethod 64

Page 65: 21. High-Quality Programming Code II

Loops: Best PracticesLoops: Best Practices Keep loops simpleKeep loops simple

This helps readers of your codeThis helps readers of your code Treat the inside of the loop as it Treat the inside of the loop as it

were a routinewere a routine Don’t make the reader look inside Don’t make the reader look inside

the loop to understand the loop the loop to understand the loop controlcontrol

Think of a loop as a black box:Think of a loop as a black box:

65

while (!inputFile.EndOfFile() && !hasErrors)while (!inputFile.EndOfFile() && !hasErrors){{

}}

(black box code)(black box code)

Page 66: 21. High-Quality Programming Code II

Defensive Defensive ProgrammingProgrammingUsing Assertions and Exceptions Using Assertions and Exceptions

CorrectlyCorrectly

Page 67: 21. High-Quality Programming Code II

Principles of Defensive Principles of Defensive ProgrammingProgramming

Fundamental principle of defensive Fundamental principle of defensive programmingprogramming

Defensive programming means:Defensive programming means:

To expect incorrect input and to handle it To expect incorrect input and to handle it correctlycorrectly

To think not only about the usual execution To think not only about the usual execution flow, but to consider also unusual situationsflow, but to consider also unusual situations

To ensure that incorrect input results to To ensure that incorrect input results to exception, not to incorrect outputexception, not to incorrect output

67

Any public method should check Any public method should check its input data, preconditions its input data, preconditions and postconditionsand postconditions

Page 68: 21. High-Quality Programming Code II

Defensive Programming Defensive Programming – Example– Example

68

string Substring(string str, int startIndex, int length)string Substring(string str, int startIndex, int length){{ if (str == null)if (str == null) {{ throw new NullReferenceException("Str is null.");throw new NullReferenceException("Str is null."); }} if (startIndex >= str.Length)if (startIndex >= str.Length) {{ throw new ArgumentException(throw new ArgumentException( "Invalid startIndex:" + startIndex);"Invalid startIndex:" + startIndex); }} if (startIndex + count > str.Length)if (startIndex + count > str.Length) {{ throw new ArgumentException("Invalid length:" + throw new ArgumentException("Invalid length:" + length);length); }} … … Debug.Assert(result.Length == length);Debug.Assert(result.Length == length);}}

Check the Check the input and input and

preconditions.preconditions.

Perform the method Perform the method main logic.main logic.

Check the Check the postconditipostconditi

ons.ons.

Page 69: 21. High-Quality Programming Code II

Exceptions – Best Exceptions – Best PracticesPractices

Choose a good name for your Choose a good name for your exception classexception class Incorrect example:Incorrect example:

Example:Example:

Use descriptive error messagesUse descriptive error messages Incorrect example:Incorrect example: Example:Example:

69

throw new Exception("File error!");throw new Exception("File error!");

throw new FileNotFoundException("Cannot find file " + throw new FileNotFoundException("Cannot find file " +

fileName);fileName);

throw new Exception("Error!");throw new Exception("Error!");

throw new ArgumentException("The speed should be a number " throw new ArgumentException("The speed should be a number "

++

"between " + MIN_SPEED + " and " + MAX_SPEED + ".");"between " + MIN_SPEED + " and " + MAX_SPEED + ".");

Page 70: 21. High-Quality Programming Code II

Exceptions Handling Exceptions Handling Best Practices (2)Best Practices (2)

Catch only exceptions that you are Catch only exceptions that you are capable to process correctlycapable to process correctly Do not catch all exceptions!Do not catch all exceptions! Incorrect example:Incorrect example:

What about What about OutOfMemoryExceptionOutOfMemoryException??70

trytry

{{

ReadSomeFile();ReadSomeFile();

}}

catchcatch

{{

Console.WriteLine("File not found!");Console.WriteLine("File not found!");

}}

Page 71: 21. High-Quality Programming Code II

Exceptions Handling Exceptions Handling Best Practices (3)Best Practices (3)

Always include the exception cause Always include the exception cause when throwing a new exceptionwhen throwing a new exception

71

trytry{{ WithdrawMoney(account, amount);WithdrawMoney(account, amount);}}catch (DatabaseException dbex)catch (DatabaseException dbex){{ throw new WithdrawException(String.Format(throw new WithdrawException(String.Format( "Can not withdraw the amount {0} from acoount "Can not withdraw the amount {0} from acoount {1}",{1}", amount, account), dbex);amount, account), dbex);}} We include in the We include in the

exceptions chain the exceptions chain the original source of the original source of the

problem.problem.

Page 72: 21. High-Quality Programming Code II

Exceptions Handling Exceptions Handling Best Practices (4)Best Practices (4)

Throw exceptions at the Throw exceptions at the corresponding level of abstractioncorresponding level of abstraction Example: Bank account withdrawal Example: Bank account withdrawal

operation could throw operation could throw InsufficientFundsExceptionInsufficientFundsException but cannot but cannot throw throw FileAccessDeniedExceptionFileAccessDeniedException

Display to the end users only Display to the end users only messages that they could messages that they could understandunderstand

72

or

Page 73: 21. High-Quality Programming Code II

Disposable ResourcesDisposable Resources Handle disposable resources with Handle disposable resources with

carecare All classes implementing All classes implementing IDisposableIDisposable should follow the should follow the try-try-finallyfinally / / usingusing pattern: pattern:

73

StreamReader reader = StreamReader reader =

new StreamReader("file.txt");new StreamReader("file.txt");

trytry

{ {

String line = String line =

reader.ReadLine(); reader.ReadLine();

}}

finallyfinally

{{

reader.Close();reader.Close();

}}

StreamReader reader = StreamReader reader =

new StreamReader(new StreamReader(

"file.txt");"file.txt");

using (reader)using (reader)

{ {

String line =String line =

reader.ReadLine(); reader.ReadLine();

}}

==

Page 74: 21. High-Quality Programming Code II

Comments and Code Comments and Code DocumentationDocumentation

The Concept of Self-Documenting CodeThe Concept of Self-Documenting Code

Page 75: 21. High-Quality Programming Code II

Effective CommentsEffective Comments Effective comments do not repeat the Effective comments do not repeat the

codecode They explain it at higher level and reveal They explain it at higher level and reveal

non-obvious detailsnon-obvious details The best software documentation is the The best software documentation is the

source code itself – keep it clean and source code itself – keep it clean and readablereadable

Self-documenting code is code that is self-Self-documenting code is code that is self-explainable and does not need commentsexplainable and does not need comments Simple design, small well named methods, Simple design, small well named methods,

strong cohesion and loose coupling, simple strong cohesion and loose coupling, simple logic, good variable names, good logic, good variable names, good formatting, … formatting, … 75

Page 76: 21. High-Quality Programming Code II

Self-Documenting CodeSelf-Documenting Code Self-documenting code Self-documenting code

fundamental principlesfundamental principles

76

The best documentation is the The best documentation is the code itself. code itself.

Do not document bad code, Do not document bad code, rewrite it!rewrite it!

Make the code self-explainable Make the code self-explainable and self-documenting, easy to and self-documenting, easy to read and understand. read and understand.

Page 77: 21. High-Quality Programming Code II

Bad Comments – Bad Comments – ExampleExample

77

public static List<int> FindPrimes(int start, int end)public static List<int> FindPrimes(int start, int end){{ // Create new list of integers// Create new list of integers List<int> primesList = new List<int>();List<int> primesList = new List<int>();

// Perform a loop from start to end// Perform a loop from start to end for (int num = start; num <= end; num++)for (int num = start; num <= end; num++) {{ // Declare boolean variable, initially true// Declare boolean variable, initially true bool prime = true;bool prime = true;

// Perform loop from 2 to sqrt(num)// Perform loop from 2 to sqrt(num) for (int div = 2; div <= Math.Sqrt(num); div++)for (int div = 2; div <= Math.Sqrt(num); div++) {{ // Check if div divides num with no remainder // Check if div divides num with no remainder if (num % div == 0)if (num % div == 0) {{ // We found a divider -> the number is not // We found a divider -> the number is not primeprime prime = false;prime = false;

// Exit from the loop// Exit from the loop break;break; }}

(continues on the next slide)

Page 78: 21. High-Quality Programming Code II

Bad Comments – Bad Comments – Example (2)Example (2)

78

// Continue with the next loop value// Continue with the next loop value }}

// Check if the number is prime// Check if the number is prime if (prime)if (prime) {{ // Add the number to the list of primes// Add the number to the list of primes primesList.Add(num);primesList.Add(num); }} }}

// Return the list of primes// Return the list of primes return primesList;return primesList;}}

Page 79: 21. High-Quality Programming Code II

Self-Documenting Code – Self-Documenting Code – ExampleExample

79

public static List<int> FindPrimes(int start, int public static List<int> FindPrimes(int start, int end)end){{ List<int> primesList = new List<int>();List<int> primesList = new List<int>(); for (int num = start; num <= end; num++)for (int num = start; num <= end; num++) {{ bool isPrime = IsPrime(num);bool isPrime = IsPrime(num); if (isPrime)if (isPrime) {{ primesList.Add(num);primesList.Add(num); }} }} return primesList;return primesList;}}

(continues on the next slide)

Good code does not Good code does not need comments. It is need comments. It is

self-explaining.self-explaining.

Page 80: 21. High-Quality Programming Code II

Self-Documenting Code –Self-Documenting Code –Example (2)Example (2)

80

private static bool IsPrime(int num)private static bool IsPrime(int num)

{{

bool isPrime = true;bool isPrime = true;

int maxDivider = Math.Sqrt(num);int maxDivider = Math.Sqrt(num);

for (int div = 2; div <= maxDivider; div++)for (int div = 2; div <= maxDivider; div++)

{{

if (num % div == 0)if (num % div == 0)

{{

// We found a divider -> the number is not prime// We found a divider -> the number is not prime

isPrime = false;isPrime = false;

break;break;

}}

}}

return isPrime;return isPrime;

}}

Good methods have good Good methods have good name and are easy to name and are easy to read and understand.read and understand.

This comment explain This comment explain non-obvious details. It non-obvious details. It

does not repeat the code.does not repeat the code.

Page 81: 21. High-Quality Programming Code II

Code RefactoringCode RefactoringImproving the Quality of the Existing Improving the Quality of the Existing

CodeCode

Page 82: 21. High-Quality Programming Code II

Code RefactoringCode Refactoring What is What is refactoringrefactoring of the source of the source

code?code? Improving the design and quality of Improving the design and quality of

existing source code without changing existing source code without changing its behaviorits behavior

Step by step process that turns the bad Step by step process that turns the bad code into good code (if possible)code into good code (if possible)

Why we need refactoring?Why we need refactoring? Code constantly changes and its quality Code constantly changes and its quality

constantly degrades (unless refactored)constantly degrades (unless refactored) Requirements often change and code Requirements often change and code

needs to be changed to follow themneeds to be changed to follow them 82

Page 83: 21. High-Quality Programming Code II

Rafactoring PatternsRafactoring Patterns When should we perform refactoring of the When should we perform refactoring of the

code?code?

Bad smells in the codeBad smells in the code indicate need of indicate need of refactoringrefactoring

Unit tests guarantee that refactoring Unit tests guarantee that refactoring does not change the behaviordoes not change the behavior

Rafactoring patternsRafactoring patterns Large repeating code fragments Large repeating code fragments e extract xtract

repeating code in separate methodrepeating code in separate method

Large methods Large methods split them logically split them logically

Large loop body or deep nesting Large loop body or deep nesting extract extract methodmethod 83

Page 84: 21. High-Quality Programming Code II

Rafactoring Patterns Rafactoring Patterns (2)(2)

Refactoring patternsRefactoring patterns Class or method has weak cohesion Class or method has weak cohesion split split

into several classes / methodsinto several classes / methods

Single change carry out changes in several Single change carry out changes in several classes classes classes have tight coupling classes have tight coupling consider redesignconsider redesign

Related data are always used together but Related data are always used together but are not part of a single class are not part of a single class group them group them in a classin a class

A method has too many parameters A method has too many parameters create create a class to groups parameters togethera class to groups parameters together

A method calls more methods from another A method calls more methods from another class than from its own class class than from its own class move it move it

84

Page 85: 21. High-Quality Programming Code II

Rafactoring Patterns Rafactoring Patterns (3)(3)

Refactoring patternsRefactoring patterns

Two classes are tightly coupled Two classes are tightly coupled merge merge them or redesign them to separate their them or redesign them to separate their responsibilitiesresponsibilities

Public non-constant fields Public non-constant fields make them make them private and define accessing propertiesprivate and define accessing properties

Magic numbers in the code Magic numbers in the code consider consider extracting constantsextracting constants

Bad named class / method / variable Bad named class / method / variable rename itrename it

Complex boolean condition Complex boolean condition split it to split it to several expressions or method callsseveral expressions or method calls 85

Page 86: 21. High-Quality Programming Code II

Rafactoring Patterns Rafactoring Patterns (4)(4)

Refactoring patternsRefactoring patterns Complex expression Complex expression split it into few split it into few

simple partssimple parts A set of constants is used as enumeration A set of constants is used as enumeration

convert it to enumeration convert it to enumeration Method logic is too complex and is hard to Method logic is too complex and is hard to

understand understand extract several more simple extract several more simple methods or even create a new classmethods or even create a new class

Unused classes, methods, parameters, Unused classes, methods, parameters, variables variables remove them remove them

Large data is passed by value without a Large data is passed by value without a good reason good reason pass it by reference pass it by reference

86

Page 87: 21. High-Quality Programming Code II

Rafactoring Patterns Rafactoring Patterns (5)(5)

Refactoring patternsRefactoring patterns Few classes share repeating functionality Few classes share repeating functionality

extract base class and reuse the common extract base class and reuse the common codecode

Different classes need to be instantiated Different classes need to be instantiated depending on configuration setting depending on configuration setting use use factoryfactory

Code is not well formatted Code is not well formatted reformat it reformat it Too many classes in a single namespace Too many classes in a single namespace

split classes logically into more namespacessplit classes logically into more namespaces Unused Unused usingusing definitions definitions remove them remove them Non-descriptive error messages Non-descriptive error messages improve improve

themthem Absence of defensive programming Absence of defensive programming add it add it 87

Page 88: 21. High-Quality Programming Code II

Code RefactoringCode RefactoringLive DemoLive Demo

Page 89: 21. High-Quality Programming Code II

ResourcesResources

The bible of high-quality software construction:The bible of high-quality software construction:

89

Code Complete, 2Code Complete, 2ndnd edition, Steve McConnell, edition, Steve McConnell, Microsoft Press, 2004, Microsoft Press, 2004, ISBN ISBN 07356196700735619670, , http://www.cc2e.comhttp://www.cc2e.com

The "High-Quality Programming The "High-Quality Programming Code" course at Telerik Academy:Code" course at Telerik Academy: http://codecourse.telerik.com

Page 90: 21. High-Quality Programming Code II

QuestionsQuestions??

QuestionsQuestions??

High-Quality High-Quality Programming Code Programming Code

Construction – Part IIConstruction – Part II

Page 91: 21. High-Quality Programming Code II

ExercisesExercises1.1. You are given a source code trying to solve the You are given a source code trying to solve the

"Game 15" puzzle. Refactor the code quality "Game 15" puzzle. Refactor the code quality without changing its functionality (bug fixes are without changing its functionality (bug fixes are allowed):allowed):a)a) Reformat the code.Reformat the code.

b)b) Give good names to all identifiers.Give good names to all identifiers.

c)c) Split the functionality into appropriate classes.Split the functionality into appropriate classes.

d)d) Refactor methods to achieve strong cohesion and Refactor methods to achieve strong cohesion and loose coupling.loose coupling.

e)e) Minimize the variables scope, span and lifetime.Minimize the variables scope, span and lifetime.

f)f) Improve the control-flow logic.Improve the control-flow logic.

g)g) Introduce constants where appropriate.Introduce constants where appropriate.

h)h) Add defensive programming where appropriate.Add defensive programming where appropriate.

91