Presentation is loading. Please wait.

Presentation is loading. Please wait.

Revealing the Secrets of Self-Documenting Code Svetlin Nakov Telerik Corporation www.telerik.com For C# Developers.

Similar presentations


Presentation on theme: "Revealing the Secrets of Self-Documenting Code Svetlin Nakov Telerik Corporation www.telerik.com For C# Developers."— Presentation transcript:

1 Revealing the Secrets of Self-Documenting Code Svetlin Nakov Telerik Corporation www.telerik.com For C# Developers

2 What is High-Quality Programming Code? What is High-Quality Programming Code? Naming Identifiers Naming Identifiers Naming classes, methods, variables, etc. Naming classes, methods, variables, etc. Code Formatting Code Formatting Designing High-Quality Classes Designing High-Quality Classes High-Quality Methods High-Quality Methods Cohesion and Coupling Cohesion and Coupling Using Variables Correctly Using Variables Correctly Using Expressions Correctly Using Expressions Correctly 2

3 Using Constants Using Constants Using Control-Flow Constructs Correctly Using Control-Flow Constructs Correctly Conditional Statements Conditional Statements Loops Loops Defensive Programming Defensive Programming Assertions and Exceptions Assertions and Exceptions Comments and Documentation Comments and Documentation Code Refactoring Code Refactoring 3

4

5 5 static void Main() { int value=010, i=5, w; int value=010, i=5, w; switch(value){case 10:w=5;Console.WriteLine(w);break;case 9:i=0;break; switch(value){case 10:w=5;Console.WriteLine(w);break;case 9:i=0;break; case 8:Console.WriteLine("8 ");break; case 8:Console.WriteLine("8 ");break; default:Console.WriteLine("def ");{ default:Console.WriteLine("def ");{ Console.WriteLine("hoho ");} Console.WriteLine("hoho ");} for (int k = 0; k < i; k++, Console.WriteLine(k - 'f'));break;} { Console.WriteLine("loop!"); } for (int k = 0; k < i; k++, Console.WriteLine(k - 'f'));break;} { Console.WriteLine("loop!"); }} What does this code do? Is it correct?

6 6 static void Main() { int value = 010, i = 5, w; int value = 010, i = 5, w; switch (value) switch (value) { case 10: w = 5; Console.WriteLine(w); break; case 10: w = 5; Console.WriteLine(w); break; case 9: i = 0; break; case 9: i = 0; break; case 8: Console.WriteLine("8 "); break; case 8: Console.WriteLine("8 "); break; default: default: Console.WriteLine("def "); Console.WriteLine("def "); Console.WriteLine("hoho "); Console.WriteLine("hoho "); for (int k = 0; k < i; k++, Console.WriteLine(k - 'f')) ; for (int k = 0; k < i; k++, Console.WriteLine(k - 'f')) ; break; break; } Console.WriteLine("loop!"); Console.WriteLine("loop!");} Now the code is formatted, but is still unclear.

7 External quality External quality Does the software behave correctly? Does the software behave correctly? Are the produced results correct? Are the produced results correct? Does the software run fast? Does the software run fast? Is the software UI easy-to-use? Is the software UI easy-to-use? Internal quality Internal quality It the code easy to read and understand? It the code easy to read and understand? It the code well structured? It the code well structured? Is the code easy to modify? Is the code easy to modify? 7

8 High-quality programming code: High-quality programming code: Easy to read and understand Easy to read and understand Easy to modify and maintain Easy to modify and maintain Correct behavior in all cases Correct behavior in all cases Well tested Well tested Well architectured and designed Well architectured and designed Well documented Well documented Self-documenting code Self-documenting code Well formatted Well formatted 8

9 Code conventions are formal guidelines about the style of the source code: Code conventions are formal guidelines about the style of the source code: Code formatting conventions Code formatting conventions Indentation, whitespace, etc. Indentation, whitespace, etc. Naming conventions Naming conventions PascalCase or camelCase, prefixes, suffixes, etc. PascalCase or camelCase, prefixes, suffixes, etc. Best practices Best practices Classes, interfaces, enumerations, structures, inheritance, exceptions, properties, events, constructors, fields, operators, etc. Classes, interfaces, enumerations, structures, inheritance, exceptions, properties, events, constructors, fields, operators, etc. 9

10 Microsoft has official code conventions called Microsoft has official code conventions called Design Guidelines for Developing Class Libraries: http://msdn.microsoft.com/en-us/library/ms229042.aspx Design Guidelines for Developing Class Libraries: http://msdn.microsoft.com/en-us/library/ms229042.aspx http://msdn.microsoft.com/en-us/library/ms229042.aspx Large organizations follow strict conventions Large organizations follow strict conventions Code conventions can vary in different teams Code conventions can vary in different teams Most conventions developers follow the official Microsoft's recommendations but extend them Most conventions developers follow the official Microsoft's recommendations but extend them High-quality code goes beyond code conventions High-quality code goes beyond code conventions Software quality is not just a set of conventions – its is a way of thinking Software quality is not just a set of conventions – its is a way of thinking 10

11 Naming Classes, Interfaces, Enumerations, Methods, Variables and Constants

12 Always use English Always use English How you will feel if you read Vietnamese code with variables named in Vietnamese? How you will feel if you read Vietnamese code with variables named in Vietnamese? English is the only language that all software developers speak English is the only language that all software developers speak Avoid abbreviations Avoid abbreviations Example: scrpCnt vs. scriptsCount Example: scrpCnt vs. scriptsCount Avoid hard-to-pronounce names Avoid hard-to-pronounce names Example: dtbgRegExPtrn vs. dateTimeBulgarianRegExPattern Example: dtbgRegExPtrn vs. dateTimeBulgarianRegExPattern 12

13 Always prefer using meaningful names Always prefer using meaningful names Names should answer these questions: Names should answer these questions: What does this class do? What is the intent of this variable? What is this variable / class used for? What does this class do? What is the intent of this variable? What is this variable / class used for? Examples: Examples: FactorialCalculator, studentsCount, Math.PI, configFileName, CreateReport FactorialCalculator, studentsCount, Math.PI, configFileName, CreateReport Incorrect examples: Incorrect examples: k, k2, k3, junk, f33, KJJ, button1, variable, temp, tmp, temp_var, something, someValue k, k2, k3, junk, f33, KJJ, button1, variable, temp, tmp, temp_var, something, someValue 13

14 Junior developers often use meaningful names that are in fact meaningless Junior developers often use meaningful names that are in fact meaningless Bad naming examples: Bad naming examples: Topic6Exercise12, LoopsExercise12, Problem7, OOPLecture_LastExercise Topic6Exercise12, LoopsExercise12, Problem7, OOPLecture_LastExercise Yes, Topic6Exercise12 indicates that this is solution to exercise 12, but what is it about? Yes, Topic6Exercise12 indicates that this is solution to exercise 12, but what is it about? Better naming: Better naming: MaximalNumbersSubsequence MaximalNumbersSubsequence 14

15 Naming types (classes, structures, etc.) Naming types (classes, structures, etc.) Use PascalCase character casing Use PascalCase character casing Examples: Examples: RecursiveFactorialCalculator, TreeSet, XmlDocument, IEnumerable, Color, TreeNode, InvalidTransactionException, MainForm RecursiveFactorialCalculator, TreeSet, XmlDocument, IEnumerable, Color, TreeNode, InvalidTransactionException, MainForm Incorrect examples: Incorrect examples: recursiveFactorialCalculator, recursive_factorial_calculator, RECURSIVE_FACTORIAL_CALCULATOR recursiveFactorialCalculator, recursive_factorial_calculator, RECURSIVE_FACTORIAL_CALCULATOR 15

16 Use the following formats: Use the following formats: [Noun] [Noun] [Adjective] + [Noun] [Adjective] + [Noun] Examples: Examples: Student, FileSystem, BinaryTreeNode, Constants, MathUtils, TextBox, Calendar Student, FileSystem, BinaryTreeNode, Constants, MathUtils, TextBox, Calendar Incorrect examples: Incorrect examples: Move, FindUsers, Fast, Optimize, Extremly, FastFindInDatabase, Check Move, FindUsers, Fast, Optimize, Extremly, FastFindInDatabase, Check 16

17 Following formats are acceptable: Following formats are acceptable: ' I ' + [Verb] + ' able ' ' I ' + [Verb] + ' able ' ' I ' + [Noun], ' I ' + [Adjective] + [Noun] ' I ' + [Noun], ' I ' + [Adjective] + [Noun] Examples: Examples: IEnumerable, IFormattable, IDataReader, IList, IHttpModule, ICommandExecutor IEnumerable, IFormattable, IDataReader, IList, IHttpModule, ICommandExecutor Incorrect examples: Incorrect examples: List, FindUsers, IFast, IMemoryOptimize, Optimizer, FastFindInDatabase, CheckBox List, FindUsers, IFast, IMemoryOptimize, Optimizer, FastFindInDatabase, CheckBox 17

18 Several formats are acceptable: Several formats are acceptable: [Noun] or [Verb] or [Adjective] [Noun] or [Verb] or [Adjective] Use the same style for all members Use the same style for all members Examples: Examples: enum Days {Monday, Tuesday, Wednesday, …}, enum AppState {Running, Finished, …} enum Days {Monday, Tuesday, Wednesday, …}, enum AppState {Running, Finished, …} Incorrect examples: Incorrect examples: enum Color {red, green, blue, white}, enum PAGE_FORMAT {A4, A5, A3, LEGAL, …} enum Color {red, green, blue, white}, enum PAGE_FORMAT {A4, A5, A3, LEGAL, …} 18

19 Exceptions Exceptions Add 'Exception ' as suffix Add 'Exception ' as suffix Use informative name Use informative name Example: FileNotFoundException Example: FileNotFoundException Incorrect example: FileNotFoundError Incorrect example: FileNotFoundError Delegate Classes Delegate Classes Add 'Delegate ' or ' EventHandler ' as suffix Add 'Delegate ' or ' EventHandler ' as suffix Example: DownloadFinishedDelegate Example: DownloadFinishedDelegate Incorrect example: WakeUpNotification Incorrect example: WakeUpNotification 19

20 How long could be the name of a class / struct / interface / enum? How long could be the name of a class / struct / interface / enum? The name should be as long as required The name should be as long as required Don't abbreviate the names if this could make them unclear Don't abbreviate the names if this could make them unclear Your IDE has autocomplete, right? Your IDE has autocomplete, right? Examples: FileNotFoundException, CustomerSupportNotificationService Examples: FileNotFoundException, CustomerSupportNotificationService Incorrect examples: FNFException, CustSuppNotifSrvc Incorrect examples: FNFException, CustSuppNotifSrvc 20

21 Namespaces naming guidelines Namespaces naming guidelines Use PascalCase Use PascalCase Following formats are acceptable: Following formats are acceptable: Company. Product. Component. … Company. Product. Component. … Product. Component. … Product. Component. … Example: Example: Telerik.WinControls.GridView Telerik.WinControls.GridView Incorrect example: Incorrect example: Telerik_WinControlsGridView, Classes Telerik_WinControlsGridView, Classes 21

22 Assembly names should follow the root namespace in its class hierarchy Assembly names should follow the root namespace in its class hierarchy Examples: Examples: Telerik.WinControls.GridView.dll Telerik.WinControls.GridView.dll Oracle.DataAccess.dll Oracle.DataAccess.dll Interop.CAPICOM.dll Interop.CAPICOM.dll Incorrect examples: Incorrect examples: Telerik_WinControlsGridView.dll Telerik_WinControlsGridView.dll OracleDataAccess.dll OracleDataAccess.dll 22

23 Methods naming guidelines Methods naming guidelines Method names should be meaningful Method names should be meaningful Should answer the question: Should answer the question: What does this method do? What does this method do? If you cannot find a good name for a method, think about does it have clear intent If you cannot find a good name for a method, think about does it have clear intent Examples: FindStudent, LoadReport, Sinus Examples: FindStudent, LoadReport, Sinus Incorrect examples: Method1, DoSomething, HandleStuff, SampleMethod, DirtyHack Incorrect examples: Method1, DoSomething, HandleStuff, SampleMethod, DirtyHack 23

24 Use PascalCase character casing Use PascalCase character casing Example: LoadSettings, not loadSettings Example: LoadSettings, not loadSettings Prefer the following formats: Prefer the following formats: [Verb] [Verb] [Verb] + [Noun], [Verb] + [Adjective] + [Noun] [Verb] + [Noun], [Verb] + [Adjective] + [Noun] Examples: Show, LoadSettingsFile, FindNodeByPattern, ToString, PrintList Examples: Show, LoadSettingsFile, FindNodeByPattern, ToString, PrintList Incorrect examples: Student, Counter, White, Generator, Approximation, MathUtils Incorrect examples: Student, Counter, White, Generator, Approximation, MathUtils 24

25 Methods returning values should describe the returned value Methods returning values should describe the returned value Examples: Examples: ConvertMetersToInches, not MetersInches or Convert or ConvertUnit ConvertMetersToInches, not MetersInches or Convert or ConvertUnit Meters2Inches is still acceptable Meters2Inches is still acceptable CalculateSinus is good CalculateSinus is good Sinus is still acceptable Sinus is still acceptable Ensure that the unit of measure of obvious Ensure that the unit of measure of obvious Prefer MeasureFontInPixels to MeasureFont Prefer MeasureFontInPixels to MeasureFont 25

26 Methods should have a single purpose! Methods should have a single purpose! Otherwise they cannot be named well Otherwise they cannot be named well How to name a method that creates annual incomes report, downloads updates from internet and scans the system for viruses? How to name a method that creates annual incomes report, downloads updates from internet and scans the system for viruses? CreateAnnualIncomesReportDownloadUpda tesAndScanForViruses is a nice name, right? CreateAnnualIncomesReportDownloadUpda tesAndScanForViruses is a nice name, right? Methods that have multiple purposes (weak cohesion) are hard to be named Methods that have multiple purposes (weak cohesion) are hard to be named Need to be refactored instead of named Need to be refactored instead of named 26

27 Use consistent naming in the entire project Use consistent naming in the entire project LoadFile, LoadImageFromFile, LoadSettings, LoadFont, LoadLibrary, but not ReadTextFile LoadFile, LoadImageFromFile, LoadSettings, LoadFont, LoadLibrary, but not ReadTextFile Use consistently the opposites at the same level of abstraction: Use consistently the opposites at the same level of abstraction: LoadLibrary vs. UnloadLibrary, but not FreeHandle LoadLibrary vs. UnloadLibrary, but not FreeHandle OpenFile vs. CloseFile, but not DeallocateResource OpenFile vs. CloseFile, but not DeallocateResource GetName vs. SetName, but not AssignName GetName vs. SetName, but not AssignName 27

28 How long could be the name of a method? How long could be the name of a method? The name should be as long as required The name should be as long as required Don't abbreviate Don't abbreviate Your IDE has autocomplete Your IDE has autocomplete Examples: Examples: LoadCustomerSupportNotificationService, CreateMonthlyAndAnnualIncomesReport LoadCustomerSupportNotificationService, CreateMonthlyAndAnnualIncomesReport Incorrect examples: Incorrect examples: LoadCustSuppSrvc, CreateMonthIncReport LoadCustSuppSrvc, CreateMonthIncReport 28

29 Method parameters names Method parameters names Preferred form: [Noun] or [Adjective] + [Noun] Preferred form: [Noun] or [Adjective] + [Noun] Should be in camelCase Should be in camelCase Should be meaningful Should be meaningful Unit of measure should be obvious Unit of measure should be obvious Examples: firstName, report, usersList, fontSizeInPixels, speedKmH, font Examples: firstName, report, usersList, fontSizeInPixels, speedKmH, font Incorrect examples: p, p1, p2, populate, LastName, last_name, convertImage Incorrect examples: p, p1, p2, populate, LastName, last_name, convertImage 29

30 Variable names Variable names Should be in camelCase Should be in camelCase Preferred form: [Noun] or [Adjective] + [Noun] Preferred form: [Noun] or [Adjective] + [Noun] Should explain the purpose of the variable Should explain the purpose of the variable If you can't find good name for a variable check if it has a single purpose If you can't find good name for a variable check if it has a single purpose Exception: variables with very small scope, e.g. the index variable in a 3-lines long for-loop Exception: variables with very small scope, e.g. the index variable in a 3-lines long for-loop Names should be consistent in the project Names should be consistent in the project 30

31 Examples: Examples: firstName, report, usersList, fontSize, maxSpeed, font, startIndex, endIndex, charsCount, configSettingsXml, config, dbConnection, createUserSqlCommand firstName, report, usersList, fontSize, maxSpeed, font, startIndex, endIndex, charsCount, configSettingsXml, config, dbConnection, createUserSqlCommand Incorrect examples: Incorrect examples: foo, bar, p, p1, p2, populate, LastName, last_name, LAST_NAME, convertImage, moveMargin, MAXSpeed, _firstName, __temp, firstNameMiddleNameAndLastName foo, bar, p, p1, p2, populate, LastName, last_name, LAST_NAME, convertImage, moveMargin, MAXSpeed, _firstName, __temp, firstNameMiddleNameAndLastName 31

32 The name should be addressed to the problem we solve, not to the means we use to solve it The name should be addressed to the problem we solve, not to the means we use to solve it Prefer nouns from the business domain to computer terms Prefer nouns from the business domain to computer terms Examples: Examples: accounts, customers, customerAddress, accountHolder, paymentPlan, vipPlayer accounts, customers, customerAddress, accountHolder, paymentPlan, vipPlayer Incorrect examples: Incorrect examples: accountsLinkedList, customersHashtable, paymentsPriorityQueue, playersArray accountsLinkedList, customersHashtable, paymentsPriorityQueue, playersArray 32

33 Boolean variables should imply true or false Boolean variables should imply true or false Prefixes like is, has and can are useful Prefixes like is, has and can are useful Use positive boolean variable names Use positive boolean variable names Incorrect example: Incorrect example: Examples: Examples: hasPendingPayment, customerFound, validAddress, positiveBalance, isPrime hasPendingPayment, customerFound, validAddress, positiveBalance, isPrime Incorrect examples: Incorrect examples: notFound, run, programStop, player, list, findCustomerById, isUnsuccessfull notFound, run, programStop, player, list, findCustomerById, isUnsuccessfull 33 if (! notFound) { … }

34 Naming Counters Naming Counters Establish a convention, e.g. [Noun] + ' Count ' Establish a convention, e.g. [Noun] + ' Count ' Examples: ticketsCount, customersCount Examples: ticketsCount, customersCount State State Establish a convention, e.g. [Noun] + ' State ' Establish a convention, e.g. [Noun] + ' State ' Examples: blogParseState, threadState Examples: blogParseState, threadState Variables with small scope and span Variables with small scope and span Short names can be used, e.g. index, i, u Short names can be used, e.g. index, i, u 34

35 Do really temporary variables exist? Do really temporary variables exist? All variables in a program are temporary because they are used temporarily only during the program execution, right? All variables in a program are temporary because they are used temporarily only during the program execution, right? Temporary variables can always be named better than temp or tmp : Temporary variables can always be named better than temp or tmp : 35 // Swap a[i] and a[j] int temp = a[i]; a[i] = a[j]; a[j] = temp; // Swap a[i] and a[j] int oldValue = a[i]; a[i] = a[j]; a[j] = oldValue;

36 How long could be the name of a variable? How long could be the name of a variable? Depends on the variable scope and lifetime Depends on the variable scope and lifetime More "famous" variables should have longer and more self-explaining name More "famous" variables should have longer and more self-explaining name Acceptable naming examples: Acceptable naming examples: Unacceptable naming examples: Unacceptable naming examples: 36 for (int i=0; i<users.Length; i++) if (i % 2 == 0) if (i % 2 == 0) sum += users[i].Weight; sum += users[i].Weight; class Student { public string lastName; public string lastName;} class Student { private int i; private int i;} class PairOfLists { public int Count { get; set; } public int Count { get; set; }}

37 In C# prefix / suffix notations are not popular In C# prefix / suffix notations are not popular Hungarian notation Hungarian notation Using prefixes to denote the variable types, e.g. lpcstrText, lpdwFlags, cbMultiByte, hWnd Using prefixes to denote the variable types, e.g. lpcstrText, lpdwFlags, cbMultiByte, hWnd The Hungarian notation works well in unmanaged languages like C++ The Hungarian notation works well in unmanaged languages like C++ Do not use Hungarian notation in C# and.NET Do not use Hungarian notation in C# and.NET Don't use prefixes / suffixes to denote the variable data type Don't use prefixes / suffixes to denote the variable data type 37

38 Name properties in C# using a noun, noun phrase, or an adjective Name properties in C# using a noun, noun phrase, or an adjective Use Pascal Case Use Pascal Case Examples: Examples: Incorrect examples: Incorrect examples: 38 public int Length { … } public Color BackgroundColor { … } public CacheMode CacheMode { … } public bool Loaded { … } public int Load { … } public Color BackgroundColor { … } public bool Font { … }

39 Use CAPITAL_LETTERS for const fields and PascalCase for readonly fields Use CAPITAL_LETTERS for const fields and PascalCase for readonly fields Use meaningful names that describe their value Use meaningful names that describe their value Examples: Examples: Incorrect examples: Incorrect examples: 39 private const int READ_BUFFER_SIZE = 8192; public static readonly PageSize DefaultPageSize = PageSize.A4; private const int FONT_SIZE_IN_POINTS = 16; public const int MAX = 512; // Max what? Apples or Oranges? public const int BUF256 = 256; // What about BUF256 = 1024? public const string GREATER = ">"; // GREATER_HTML_ENTITY public const int FONT_SIZE = 16; // 16pt or 16px? public const PageSize PAGE = PageSize.A4; // Maybe PAGE_SIZE?

40 Don't use numbers in the identifiers names Don't use numbers in the identifiers names Example: Example: PrintReport and PrintReport2 PrintReport and PrintReport2 What is the difference? What is the difference? Exceptions: Exceptions: When the number is part of the name itself, e.g. RS232Port, COM3, Win32APIFunctions When the number is part of the name itself, e.g. RS232Port, COM3, Win32APIFunctions Don't use Cyrillic or letters from other alphabets Don't use Cyrillic or letters from other alphabets E.g. FindСтудентByName, CalcΩ2Protein E.g. FindСтудентByName, CalcΩ2Protein 40

41 Giving a misleading name is worse than giving a totally unclear name Giving a misleading name is worse than giving a totally unclear name Example: Example: Consider a method that calculates the sum of all elements in an array Consider a method that calculates the sum of all elements in an array Its should be named Sum or CalculateSum Its should be named Sum or CalculateSum What about naming it CalculateAverage or Max or CheckForNegativeNumber ? What about naming it CalculateAverage or Max or CheckForNegativeNumber ? It's crazy, but be careful with "copy-paste" It's crazy, but be careful with "copy-paste" 41

42 Microsoft sometimes use really bad naming in their API libraries (especially in Win32 API) Microsoft sometimes use really bad naming in their API libraries (especially in Win32 API) Examples: Examples: Navigate and Navigate2 methods in Internet Explorer ActiveX control ( MSHTML.DLL ) Navigate and Navigate2 methods in Internet Explorer ActiveX control ( MSHTML.DLL ) WNetAddConnection3 method in Multiple Provider Router Networking API ( MPR.DLL ) WNetAddConnection3 method in Multiple Provider Router Networking API ( MPR.DLL ) LPWKSTA_USER_INFO_1 structure in Win32 LPWKSTA_USER_INFO_1 structure in Win32 Don't follow them blindly, just think a bit! Don't follow them blindly, just think a bit! 42

43 43 FileStream fs = new FileStream(FILE_NAME, FileMode.CreateNew); // Create the writer for data. BinaryWriter w = new BinaryWriter(fs); // Write data to Test.data. for (int i = 0; i < 11; i++) { w.Write( (int) i); w.Write( (int) i);}w.Close();fs.Close(); // Create the reader for data. fs = new FileStream(FILE_NAME, FileMode.Open, FileAccess.Read); BinaryReader r = new BinaryReader(fs); // Read data from Test.data. for (int i = 0; i < 11; i++) { Console.WriteLine(r.ReadInt32()); Console.WriteLine(r.ReadInt32());}r.Close();fs.Close(); Source: http://msdn.microsoft.com/en-us/library/36b93480.aspxhttp://msdn.microsoft.com/en-us/library/36b93480.aspx

44

45 45 public const string FILE_NAME ="example.bin" ; static void Main ( ){ FileStream fs= new FileStream(FILE_NAME,FileMode. CreateNew) // Create the writer for data. ;BinaryWriter w=new BinaryWriter ( fs );// Write data to Test.data. for( int i=0;i<11;i++){w.Write((int)i);}w.Close(); fs. Close ( ) // Create the reader for data. ;fs=new FileStream(FILE_NAME,FileMode. Open, FileAccess.Read) ;BinaryReader r = new BinaryReader(fs); // Read data from Test.data. for (int i = 0; i < 11; i++){ Console.WriteLine for (int i = 0; i < 11; i++){ Console.WriteLine (r.ReadInt32 ()) ;}r. Close ( ); fs. Close ( ) ; }

46 Good formatting goals Good formatting goals To improve code readability To improve code readability To improve code maintainability To improve code maintainability Fundamental principle of code formatting: Fundamental principle of code formatting: Any formatting style that follows the above principle is good Any formatting style that follows the above principle is good Any other formatting is not good Any other formatting is not good 46 The formating of the source code should disclose its logical structure.

47 Put { and } alone on a line under the corresponding parent block Put { and } alone on a line under the corresponding parent block Indent the block contents by a single [Tab] Indent the block contents by a single [Tab] Don't indent with spaces Don't indent with spaces Example: Example: 47 if ( some condition ) { // Block contents indented by a single [Tab] // Block contents indented by a single [Tab] // Don't use spaces for indentation // Don't use spaces for indentation}

48 Methods should be indented with a single [Tab] from the class body Methods should be indented with a single [Tab] from the class body Methods body should be indented with a single [Tab] as well Methods body should be indented with a single [Tab] as well 48 public class IndentationExample { private int Zero() private int Zero() { return 0; return 0; }} The entire method is indented with a single [Tab] Method body is also indented

49 Brackets in the method declaration should be formatted as follows: Brackets in the method declaration should be formatted as follows: Don't use spaces between the brackets: Don't use spaces between the brackets: The same applies for if -conditions and for - loops: The same applies for if -conditions and for - loops: 49 private static ulong CalcFactorial(uint num) if (condition) …

50 Separate method parameters by comma followed by a space Separate method parameters by comma followed by a space Don't put comma before the space Don't put comma before the space Examples: Examples: Incorrect examples: Incorrect examples: 50 private void RegisterUser(string username, string password) RegisterUser("nakov", "s3cr3t!p@ssw0rd");

51 Use empty line for separation between methods: Use empty line for separation between methods: 51 public class Factorial { private static ulong CalcFactorial(uint num) private static ulong CalcFactorial(uint num) { if (num == 0) if (num == 0) return 1; return 1; else else return num * CalcFactorial(num - 1); return num * CalcFactorial(num - 1); } static void Main() static void Main() { ulong factorial = CalcFactorial(5); ulong factorial = CalcFactorial(5); Console.WriteLine(factorial); Console.WriteLine(factorial); }} Empty line Always use { and } after if (there is no space to do it here)

52 Use an empty line to separate logically related sequences of lines: Use an empty line to separate logically related sequences of lines: 52 private List PrepareReports() { List reports = new List (); List reports = new List (); // Create incomes reports // Create incomes reports Report incomesSalesReport = PrepareIncomesSalesReport(); Report incomesSalesReport = PrepareIncomesSalesReport(); reports.Add(incomesSalesReport); reports.Add(incomesSalesReport); Report incomesSupportReport = PrepareIncomesSupportReport(); Report incomesSupportReport = PrepareIncomesSupportReport(); reports.Add(incomesSupportReport); reports.Add(incomesSupportReport); // Create expenses reports // Create expenses reports Report expensesPayrollReport = PrepareExpensesPayrollReport(); Report expensesPayrollReport = PrepareExpensesPayrollReport(); reports.Add(expensesPayrollReport); reports.Add(expensesPayrollReport); Report expensesMarketingReport = PrepareExpensesMarketingReport(); Report expensesMarketingReport = PrepareExpensesMarketingReport(); reports.Add(expensesMarketingReport); reports.Add(expensesMarketingReport); return reports; return reports;} Empty line

53 53 public static void PrintList(List ints) { Console.Write("{ "); Console.Write("{ "); foreach (int item in ints) foreach (int item in ints) { Console.Write(item); Console.Write(item); Console.Write(" "); Console.Write(" "); } Console.WriteLine("}"); Console.WriteLine("}");} static void Main() { //... //...}

54 Formatting classes / structures / interfaces / enumerations Formatting classes / structures / interfaces / enumerations Indent the class body with a single [Tab] Indent the class body with a single [Tab] Use the following order of definitions: Use the following order of definitions: Constants, delegates, inner types, fields, constructors, properties, methods Constants, delegates, inner types, fields, constructors, properties, methods Static members, public members, protected members, internal members, private members Static members, public members, protected members, internal members, private members The above order of definitions is not the only possible correct one The above order of definitions is not the only possible correct one 54

55 55 public class Dog { // Static variables // Static variables public const string SPECIES = public const string SPECIES = "Canis Lupus Familiaris"; "Canis Lupus Familiaris"; // Instance variables // Instance variables private int age; private int age; // Constructors // Constructors public Dog(string name, int age) public Dog(string name, int age) { this.Name = name; this.Name = name; this.age = age; this.age = age; } (continues on the next slide)

56 56 // Properties // Properties public string Name { get; set; } public string Name { get; set; } // Methods // Methods public void Breath() public void Breath() { // TODO: breathing process // TODO: breathing process } public void Bark() public void Bark() { Console.WriteLine("wow-wow"); Console.WriteLine("wow-wow"); }}

57 Formatting conditional statements and loops Formatting conditional statements and loops Always use { } block after if / for / while, even when a single operator follows Always use { } block after if / for / while, even when a single operator follows Indent the block body after if / for / while Indent the block body after if / for / while Never put the block after if / for / while on the same line! Never put the block after if / for / while on the same line! Always put the { on the next line Always put the { on the next line Never indent with more than one [Tab] Never indent with more than one [Tab] 57

58 Example: Example: Incorrect examples: Incorrect examples: 58 for (int i=0; i<10; i++) { Console.WriteLine("i={0}", i); Console.WriteLine("i={0}", i);} for (int i=0; i<10; i++) Console.WriteLine("i={0}", i); Console.WriteLine("i={0}", i); for (int i=0; i<10; i++) Console.WriteLine("i={0}", i); for (int i=0; i<10; i++) { Console.WriteLine("i={0}", i); Console.WriteLine("i={0}", i);}

59 Break long lines after punctuation Break long lines after punctuation Indent the second line by single [Tab] Indent the second line by single [Tab] Do not additionally indent the third line Do not additionally indent the third line Examples: Examples: 59 DictionaryEntry newEntry = new DictionaryEntry ( new DictionaryEntry ( oldEntry.Key, oldEntry.Value); oldEntry.Key, oldEntry.Value); if (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) { …

60 60 if (matrix[x, y] == 0 || matrix[x-1, y] == 0 || matrix[x+1, y] == 0 || matrix[x, 0 || matrix[x+1, y] == 0 || matrix[x, y-1] == 0 || matrix[x, y+1] == 0) y-1] == 0 || matrix[x, y+1] == 0) { … if (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) { … DictionaryEntry newEntry = new DictionaryEntry (oldEntry = new DictionaryEntry (oldEntry.Key, oldEntry.Value);.Key, oldEntry.Value);

61 All types of alignments are considered harmful All types of alignments are considered harmful Alignments are hard-to-maintain! Alignments are hard-to-maintain! Incorrect examples: Incorrect examples: 61 DateTime date = DateTime.Now.Date; int count = 0; Student student = new Strudent(); List students = new List (); matrix[x, y] == 0; matrix[x + 1, y + 1] == 0; matrix[2 * x + y, 2 * y + x] == 0; matrix[x * y, x * y] == 0;

62 How to Design High-Quality Classes? Abstraction, Cohesion and Coupling

63 Present a consistent level of abstraction in the class contract (publicly visible members) Present a consistent level of abstraction in the class contract (publicly visible members) What abstraction the class is implementing? What abstraction the class is implementing? Does it represent only one thing? Does it represent only one thing? Does the class name well describe its purpose? Does the class name well describe its purpose? Does the class define clear and easy to understand public interface? Does the class define clear and easy to understand public interface? Does the class hide all its implementation details? Does the class hide all its implementation details? 63

64 64 public class Font { public string Name { get; set; } public string Name { get; set; } public float SizeInPoints { get; set; } public float SizeInPoints { get; set; } public FontStyle Style { get; set; } public FontStyle Style { get; set; } public Font(string name, float sizeInPoints, FontStyle style) public Font(string name, float sizeInPoints, FontStyle style) { this.Name = name; this.Name = name; this.SizeInPoints = sizeInPoints; this.SizeInPoints = sizeInPoints; this.Style = style; this.Style = style; } public void DrawString(DrawingSurface surface, public void DrawString(DrawingSurface surface, string str, int x, int y) {... } string str, int x, int y) {... } public Size MeasureString(string str) {... } public Size MeasureString(string str) {... }}

65 65 public class Program { public string title; public string title; public int size; public int size; public Color color; public Color color; public void InitializeCommandStack(); public void InitializeCommandStack(); public void PushCommand(Command command); public void PushCommand(Command command); public Command PopCommand(); public Command PopCommand(); public void ShutdownCommandStack(); public void ShutdownCommandStack(); public void InitializeReportFormatting(); public void InitializeReportFormatting(); public void FormatReport(Report report); public void FormatReport(Report report); public void PrintReport(Report report); public void PrintReport(Report report); public void InitializeGlobalData(); public void InitializeGlobalData(); public void ShutdownGlobalData(); public void ShutdownGlobalData();} Does this class really represent a "program"? Is this name good? Does this class really have a single purpose?

66 Define operations along with their opposites Define operations along with their opposites Example: Example: Open() and Close() Open() and Close() Move unrelated methods in another class Move unrelated methods in another class Example: Example: In class Employee if you need to calculate Age by given DateOfBirth In class Employee if you need to calculate Age by given DateOfBirth Create static method CalcAge in a separate class DateUtils Create static method CalcAge in a separate class DateUtils 66

67 Beware of breaking the interface abstraction due to evolution Beware of breaking the interface abstraction due to evolution Don't add public members inconsistent with class abstraction Don't add public members inconsistent with class abstraction Example: in class called Employee at some time we add method for accessing the DB with SQL Example: in class called Employee at some time we add method for accessing the DB with SQL 67 class Employee { public string firstName; public string firstName; public string lastName; public string lastName; … public SqlCommand FindByPrimaryKeySqlCommand(int id); public SqlCommand FindByPrimaryKeySqlCommand(int id);}

68 Minimize the visibility of classes and members Minimize the visibility of classes and members Start from private and move to internal, protected and public if required Start from private and move to internal, protected and public if required Classes should hide their implementation details Classes should hide their implementation details Anything which is not part of the class interface should be declared private Anything which is not part of the class interface should be declared private Classes with good encapsulated classes are: less complex, easier to maintain, more loosely coupled Classes with good encapsulated classes are: less complex, easier to maintain, more loosely coupled Never declare fields public (except constants) Never declare fields public (except constants) Use methods or properties to access fields Use methods or properties to access fields 68

69 Don't violate encapsulation semantically! Don't violate encapsulation semantically! Don't rely on non-documented internal behavior or side effects Don't rely on non-documented internal behavior or side effects Wrong example: Wrong example: Skip calling ConnectToDB() because you just called FindEmployeeById() which should open connection Skip calling ConnectToDB() because you just called FindEmployeeById() which should open connection Another wrong example: Another wrong example: Use String.Empty instead of Titles.NoTitle because you know both values are the same Use String.Empty instead of Titles.NoTitle because you know both values are the same 69

70 Don't hide methods in a subclass Don't hide methods in a subclass Example: if the class Timer has private method Start(), don't define Start() in AtomTimer Example: if the class Timer has private method Start(), don't define Start() in AtomTimer Move common interfaces, data, and behavior as high as possible in the inheritance tree Move common interfaces, data, and behavior as high as possible in the inheritance tree This maximizes the code reuse This maximizes the code reuse Be suspicious of base classes of which there is only one derived class Be suspicious of base classes of which there is only one derived class Do you really need this additional level of inheritance? Do you really need this additional level of inheritance? 70

71 Be suspicious of classes that override a routine and do nothing inside Be suspicious of classes that override a routine and do nothing inside Is the overridden routine used correctly? Is the overridden routine used correctly? Avoid deep inheritance trees Avoid deep inheritance trees Don't create more than 6 levels of inheritance Don't create more than 6 levels of inheritance Avoid using a base classs protected data fields in a derived class Avoid using a base classs protected data fields in a derived class Provide protected accessor methods or properties instead Provide protected accessor methods or properties instead 71

72 Prefer inheritance to extensive type checking: Prefer inheritance to extensive type checking: Consider inheriting Circle and Square from Shape and override the abstract action Draw() Consider inheriting Circle and Square from Shape and override the abstract action Draw() 72 switch (shape.Type) { case Shape.Circle: case Shape.Circle: shape.DrawCircle(); shape.DrawCircle(); break; break; case Shape.Square: case Shape.Square: shape.DrawSquare(); shape.DrawSquare(); break; break;......}

73 Keep the number of methods in a class as small as possible reduce complexity Keep the number of methods in a class as small as possible reduce complexity Minimize direct method calls to other classes Minimize direct method calls to other classes Minimize indirect method calls to other classes Minimize indirect method calls to other classes Less external method calls == less coupling Less external method calls == less coupling Minimize the extent to which a class collaborates with other classes Minimize the extent to which a class collaborates with other classes Reduce coupling between classes Reduce coupling between classes 73

74 Initialize all member data in all constructors, if possible Initialize all member data in all constructors, if possible Uninitialized data is error prone Uninitialized data is error prone Partially initialized data is even more evil Partially initialized data is even more evil Incorrect example: assign FirstName in class Person but leave LastName empty Incorrect example: assign FirstName in class Person but leave LastName empty Initialize data members in the same order in which they are declared Initialize data members in the same order in which they are declared Prefer deep copies to shallow copies ( ICloneable should make deep copy) Prefer deep copies to shallow copies ( ICloneable should make deep copy) 74

75 Use private constructor to prohibit direct class instantiation Use private constructor to prohibit direct class instantiation Use deign patterns for common design situations Use deign patterns for common design situations Creational patterns like singleton, factory method, abstract factory Creational patterns like singleton, factory method, abstract factory Structural patterns like adapter, bridge, composite, decorator, façade Structural patterns like adapter, bridge, composite, decorator, façade Behavioral patterns like command, iterator, observer, strategy, template method Behavioral patterns like command, iterator, observer, strategy, template method 75

76 Model real-world objects with OOP classes Model real-world objects with OOP classes Model abstract objects, processes, etc. Model abstract objects, processes, etc. Reduce complexity Reduce complexity Work at higher level Work at higher level Isolate complexity Isolate complexity Hide it in a class Hide it in a class Hide implementation details encapsulation Hide implementation details encapsulation Limit effects of changes Limit effects of changes Changes affect only their class Changes affect only their class 76

77 Hide global data Hide global data Work through methods Work through methods Group variables that are used together Group variables that are used together Make central points of control Make central points of control Single task should be done at single place Single task should be done at single place Avoid duplicating code Avoid duplicating code Facilitate code reuse Facilitate code reuse Use class hierarchies and virtual methods Use class hierarchies and virtual methods Package related operations together Package related operations together 77

78 Group related classes together in namespaces Group related classes together in namespaces Follow consistent naming convention Follow consistent naming convention 78 namespace Utils { class MathUtils { … } class MathUtils { … } class StringUtils { … } class StringUtils { … }} namespace DataAccessLayer { class GenericDAO { … } class GenericDAO { … } class EmployeeDAO { … } class EmployeeDAO { … } class AddressDAO { … } class AddressDAO { … }}

79 How to Design and Implement High-Quality Methods? Understanding Cohesion and Coupling

80 Methods are important in software development Methods are important in software development Reduce complexity Reduce complexity Divide and conquer: complex problems can be split into composition of several simple ones Divide and conquer: complex problems can be split into composition of several simple ones Improve code readability Improve code readability Small methods with good method names make the code self-documenting Small methods with good method names make the code self-documenting Avoid duplicating code Avoid duplicating code Duplicating code is hard to maintain Duplicating code is hard to maintain 80

81 Methods simplify software development Methods simplify software development Hide implementation details Hide implementation details Complex logic is encapsulated and hidden behind a simple interface Complex logic is encapsulated and hidden behind a simple interface Algorithms and data structures are hidden and can be transparently replaced later Algorithms and data structures are hidden and can be transparently replaced later Increase the level of abstraction Increase the level of abstraction Methods address the business problem, not the technical implementation: Methods address the business problem, not the technical implementation: 81 Bank.accounts[customer].deposit(500);

82 Fundamental principle of correct method usage: Fundamental principle of correct method usage: Methods should do exactly what their names say Methods should do exactly what their names say Nothing less Nothing less Nothing more Nothing more In case of incorrect input or incorrect preconditions, an error should be indicated In case of incorrect input or incorrect preconditions, an error should be indicated 82 A method should do what its name says or should indicate an error. Any other behaviour is incorrect!

83 83 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) { if (a <= 0 || b <= 0 || c <= 0) if (a <= 0 || b <= 0 || c <= 0) { throw new ArgumentException("Sides should be positive."); throw new ArgumentException("Sides should be positive."); } 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;}

84 Method that does something different than its name, is wrong for at least one of these reasons: Method that does something different than its name, is wrong for at least one of these reasons: The method sometimes returns incorrect result bug The method sometimes returns incorrect result bug The method returns incorrect output when its input is incorrect or unusual low quality The method returns incorrect output when its input is incorrect or unusual low quality Acceptable for private methods only Acceptable for private methods only The method does too many things bad cohesion The method does too many things bad cohesion The method has side effects spaghetti code The method has side effects spaghetti code Method returns strange value when an error condition happens it should indicate the error Method returns strange value when an error condition happens it should indicate the error 84

85 85 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) { 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 effect Incorrect result. Throw an exception instead.

86 Methods should have strong cohesion Methods should have strong cohesion Should address single task and address it well Should address single task and address it well Should have clear intent Should have clear intent Methods that address several tasks in the same time are hard to be named Methods that address several tasks in the same time are hard to be named String cohesion is used in engineering String cohesion is used in engineering In computer hardware any PC component solves a single task In computer hardware any PC component solves a single task E.g. hard disk performs a single task – storage E.g. hard disk performs a single task – storage 86

87 Functional cohesion (independent function) Functional cohesion (independent function) Method performs certain well-defined calculation and returns a single result Method performs certain well-defined calculation and returns a single result The entire input is passed through parameters and the entire output is returned as result The entire input is passed through parameters and the entire output is returned as result No external dependencies or side effects No external dependencies or side effects Examples: Examples: 87 Math.Sqrt(value) square root String.Substring(str, startIndex, length) Char.IsLetterOrDigit(ch)

88 Sequential cohesion (algorithm) Sequential cohesion (algorithm) Method performs certain sequence of operations to perform a single task and achieve certain result Method performs certain sequence of operations to perform a single task and achieve certain result It encapsulates an algorithm It encapsulates an algorithm Example: Example: 1.Connect to mail server 2.Send message headers 3.Send message body 4.Disconnect from the server 88 SendEmail(recipient, subject, body)

89 Communicational cohesion (common data) Communicational cohesion (common data) A set of operations used to process certain data and produce a result A set of operations used to process certain data and produce a result Example: Example: 1.Retrieve input data from database 2.Perform internal calculations over retrieved data 3.Build the report 4.Format the report as Excel worksheet 5.Display the Excel worksheet on the screen 89 DisplayAnnualExpensesReport(int employeeId)

90 Temporal cohesion (time related activities) Temporal cohesion (time related activities) Operations that are generally not related but need to happen in a certain moment Operations that are generally not related but need to happen in a certain moment Examples: Examples: 1.Load user settings 2.Check for updates 3.Load all invoices from the database Sequence of actions to handle the event Sequence of actions to handle the event 90 InitializeApplication() ButtonConfirmClick()

91 Logical cohesion Logical cohesion Performs a different operation depending on an input parameter Performs a different operation depending on an input parameter Incorrect example: Incorrect example: Can be acceptable in event handlers (e.g. the KeyDown event in Windows Forms) Can be acceptable in event handlers (e.g. the KeyDown event in Windows Forms) 91 object ReadAll(int operationCode) { if (operationCode == 1) … // Read person name if (operationCode == 1) … // Read person name else if (operationCode == 2) … // Read address else if (operationCode == 2) … // Read address else if (operationCode == 3) … // Read date else if (operationCode == 3) … // Read date …}

92 Coincidental cohesion (spaghetti) Coincidental cohesion (spaghetti) Not related (random) operations are grouped in a method for unclear reason Not related (random) operations are grouped in a method for unclear reason Incorrect example: Incorrect example: 1.Prepares annual incomes report for given customer 2.Sorts an array of integers in increasing order 3.Calculates the square root of given number 4.Converts given MP3 file into WMA format 5.Sends email to given customer 92 HandleStuff(customerId, int[], ref sqrtValue, mp3FileName, emailAddress)

93 What is loose coupling? What is loose coupling? Minimal dependences of the method on the other parts of the source code Minimal dependences of the method on the other parts of the source code Minimal dependences on the class members or external classes and their members Minimal dependences on the class members or external classes and their members No side effects No side effects If the coupling is loose, we can easily reuse a method or group of methods in a new project If the coupling is loose, we can easily reuse a method or group of methods in a new project Tight coupling spaghetti code Tight coupling spaghetti code 93

94 The ideal coupling The ideal coupling A methods depends only on its parameters A methods depends only on its parameters Does not have any other input or output Does not have any other input or output Example: Math.Sqrt Example: Math.Sqrt Real world Real world Complex software cannot avoid coupling but could make it as loose as possible Complex software cannot avoid coupling but could make it as loose as possible Example: complex encryption algorithm performs initialization, encryption, finalization Example: complex encryption algorithm performs initialization, encryption, finalization 94

95 Intentionally increased coupling for more flexibility (.NET cryptography API): Intentionally increased coupling for more flexibility (.NET cryptography API): 95 byte[] EncryptAES(byte[] inputData, byte[] 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, inputData.Length); csEncryptor.Write(inputData, 0, inputData.Length); csEncryptor.FlushFinalBlock(); csEncryptor.FlushFinalBlock(); byte[] encryptedData = destStream.ToArray(); byte[] encryptedData = destStream.ToArray(); return encryptedData; return encryptedData;}

96 To reduce coupling we can make utility classes that hide the complex logic and provide simple straightforward interface (a.k.a. façade): To reduce coupling we can make utility classes that hide the complex logic and provide simple straightforward interface (a.k.a. façade): 96 byte[] EncryptAES(byte[] inputData, byte[] 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;}

97 Passing parameters through class fields Passing parameters through class fields Typical example of tight coupling Typical example of tight coupling Don't do this unless you have a good reason! Don't do this unless you have a good reason! 97 class 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 the numbers as parameters?

98 Reducing coupling with OOP techniques Reducing coupling with OOP techniques Abstraction Abstraction Define a public interface and hide the implementation details Define a public interface and hide the implementation details Encapsulation Encapsulation Make methods and fields private unless they are definitely needed Make methods and fields private unless they are definitely needed Define new members as private Define new members as private Increase visibility as soon as this is needed Increase visibility as soon as this is needed 98

99 Method is coupled to its parameters Method is coupled to its parameters This is the best type of coupling This is the best type of coupling Method in a class is coupled to some class fields Method in a class is coupled to some class fields This coupling is usual, do not worry too much This coupling is usual, do not worry too much Method in a class is coupled to static methods, properties or constants in external class Method in a class is coupled to static methods, properties or constants in external class This is normal, usually is not a problem This is normal, usually is not a problem Method is coupled to external static fields Method is coupled to external static fields Avoid this, classes should keep their fields private Avoid this, classes should keep their fields private 99

100 Method in a class is coupled to static fields in external class Method in a class is coupled to static fields in external class Avoid it consider refactoring Avoid it consider refactoring Methods take as input data some fields that could be passed as parameters Methods take as input data some fields that could be passed as parameters Check the intent of the method Check the intent of the method Is it designed to process internal class data or is utility method Is it designed to process internal class data or is utility method Method is defined public without being part of the public class's interface possible coupling Method is defined public without being part of the public class's interface possible coupling 100

101 Put most important parameters first Put most important parameters first First put the main input parameters First put the main input parameters Put non-important optional parameters last Put non-important optional parameters last Example: Example: Incorrect example: Incorrect example: 101 void RegisterUser(string username, string password, Date accountExpirationDate, Role[] roles) void RegisterUser(Role[] roles, string password, string username, Date accountExpirationDate,) void RegisterUser(string password, Date accountExpirationDate, Role[] roles, string username)

102 Do not modify the input parameters Do not modify the input parameters Use new variable instead Use new variable instead Incorrect example: Incorrect example: Correct example: Correct example: 102 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) { string usernameLowercase = username.ToLower(); string usernameLowercase = username.ToLower(); … // Check the username / password here … // Check the username / password here}

103 Use parameters consistently Use parameters consistently Use the same names and the same order in all methods Use the same names and the same order in all methods Incorrect example: Incorrect example: Output parameters should be put last Output parameters should be put last 103 void EncryptFile(Stream input, Stream output, string key); void DecryptFile(string key, Stream output, Stream input); FindCustomersAndIncomes(Region region, out Customer[] customers, out decimal[] incomes)

104 When should we pass an object containing few values and when these values separately? When should we pass an object containing few values and when these values separately? Sometime we pass an object and use only a single field of it – it is a good practice? Sometime we pass an object and use only a single field of it – it is a good practice? Examples: Examples: Look at the method's level of abstraction Look at the method's level of abstraction Is it intended to operate with employees of with rates and months? the first is incorrect Is it intended to operate with employees of with rates and months? the first is incorrect 104 CalculateSalary(Employee employee, int months); CalculateSalary(double rate, int months);

105 Limit the number of method parameters to 7 (+/-2) Limit the number of method parameters to 7 (+/-2) 7 is a magic number in psychology 7 is a magic number in psychology Human brain cannot process more than 7 (+/-2) things in the same time Human brain cannot process more than 7 (+/-2) things in the same time If the parameters need to be too much reconsider the method intent does it have clear intent? If the parameters need to be too much reconsider the method intent does it have clear intent? Consider putting few parameters in a new class Consider putting few parameters in a new class 105

106 How long should a method be? How long should a method be? There is no specific restriction There is no specific restriction Avoid methods longer than one screen (30 lines) Avoid methods longer than one screen (30 lines) Long methods are not always bad Long methods are not always bad Be sure you have a good reason for their length Be sure you have a good reason for their length Cohesion and coupling are more important than the method length! Cohesion and coupling are more important than the method length! Long methods often contain portions that could be extracted as separate methods with good name and clear intent check this! Long methods often contain portions that could be extracted as separate methods with good name and clear intent check this! 106

107 Best Practices

108 Always assign the result of a method in some variable before returning it. Benefits: Always assign the result of a method in some variable before returning it. Benefits: Improved code readability Improved code readability The returned value has self-documenting name The returned value has self-documenting name Simplified debugging Simplified debugging Example: Example: Incorrect example: Incorrect example: 108 return days * hoursPerDay * ratePerHour; int salary = days * hoursPerDay * ratePerHour; return salary; The intent of the formula is obvious. We can put a breakpoint at this line and check if the result is correct.

109 Initialize all variables before their first usage Initialize all variables before their first usage Class variables (fields) are automatically initialized with 0 / null by the C# compiler Class variables (fields) are automatically initialized with 0 / null by the C# compiler You still get a warning message You still get a warning message Local variables should be manually initialized Local variables should be manually initialized This C# code will result in compilation error: This C# code will result in compilation error: We can initialize variables at their declaration: We can initialize variables at their declaration: 109 int value; Console.WriteLine(value); int value = 0; Console.WriteLine(value);

110 Ensure objects cannot get into partially initialized state Ensure objects cannot get into partially initialized state Make all fields private and require valid values for all mandatory fields in all constructors Make all fields private and require valid values for all mandatory fields in all constructors Example: Student object is invalid unless it has Name and FacultyNumber Example: Student object is invalid unless it has Name and FacultyNumber 110 class Student { private string name, facultyNumber; private string name, facultyNumber; public Student(string name, string facultyNumber) public Student(string name, string facultyNumber) { … } { … }}

111 Variable scope defines how "famous" is a variable in the program Variable scope defines how "famous" is a variable in the program Static variables are more "famous" than instance variables, and they are more "famous" than local Static variables are more "famous" than instance variables, and they are more "famous" than local Variables' visibility is directly related to their scope Variables' visibility is directly related to their scope public, protected, internal, private public, protected, internal, private Always try to reduce the variable's scope Always try to reduce the variable's scope This reduces potential coupling This reduces potential coupling Avoid public fields (exception: readonly / const ) Avoid public fields (exception: readonly / const ) Access all fields through properties / methods Access all fields through properties / methods 111

112 112 public class Globals { public static int state = 0; public static int state = 0;} 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."); } else else { Console.WriteLine("Good bye."); Console.WriteLine("Good bye."); } }}

113 Variable span Variable span The average number of lines of code (LOC) between variable usages The average number of lines of code (LOC) between variable usages Variable lifetime Variable lifetime The number of lines of code (LOC) between the first and the last variable usage in a block The number of lines of code (LOC) between the first and the last variable usage in a block Keep variable span and lifetime as low as possible Keep variable span and lifetime as low as possible 113 Always define and initialize variables just before their first use and never before it!

114 114 int count; int[] numbers = new int[100]; for (int i = 0; i < numbers.Length; i++) { numbers[i] = i; numbers[i] = i;} count = 0; 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++) { if (numbers[i] % 3 == 0) if (numbers[i] % 3 == 0) { count++; count++; }}Console.WriteLine(count); span = 19 / 4 = 4.75 lifetime ("count") = 19

115 115 int[] numbers = new int[100]; for (int i = 0; i < numbers.Length; i++) { numbers[i] = i; numbers[i] = 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; for (int i = 0; i < numbers.Length; i++) { if (numbers[i] % 3 == 0) if (numbers[i] % 3 == 0) { count++; count++; }}Console.WriteLine(count); span= 9 / 3 = 3 lifetime = 9

116 Variables should have single purpose Variables should have single purpose Never use a single variable for multiple purposes! Never use a single variable for multiple purposes! Economizing memory is not an excuse Economizing memory is not an excuse Can you choose a good name for variable that is used for several purposes? Can you choose a good name for variable that is used for several purposes? Example: variable used to count students of to keep the average of their grades Example: variable used to count students of to keep the average of their grades Proposed name: studentsCountOrAvgGrade Proposed name: studentsCountOrAvgGrade 116

117 Don't define variables that are not used Don't define variables that are not used Compilers usually issues warnings Compilers usually issues warnings Don't use variables with hidden purpose Don't use variables with hidden purpose Incorrect example: Incorrect example: Instead use enumeration: Instead use enumeration: 117 int mode = 1; … if (mode == 1) …; // Read if (mode == 2) …; // Write if (mode == 3) …; // Read and write enum ResourceAccessMode { Read, Write, ReadWrite }

118 Best Practices

119 Never use complex expressions in the code! Never use complex expressions in the code! Incorrect example: Incorrect example: Complex expressions are evil because: Complex expressions are evil because: Make code hard to read and understand, hard to debug, hard to modify and hard to maintain Make code hard to read and understand, hard to debug, hard to modify and hard to maintain 119 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)-1]] * matrix[xCoords[findMax(i)+1]][yCoords[findMin(j)-1]] * matrix[yCoords[findMax(j)+1]][xCoords[findMin(i)-1]]; matrix[yCoords[findMax(j)+1]][xCoords[findMin(i)-1]]; }} What shall we do if we get at this line IndexOutOfRangeException ? There are 10 potential sources of IndexOutOfRangeException in this expression!

120 120 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; }}

121 When and How to Use Constants?

122 What is magic number or value? What is magic number or value? Magic numbers / values are all literals different than 0, 1, -1, null and "" (empty string) Magic numbers / values are all literals different than 0, 1, -1, null and "" (empty string) Avoid using magic numbers / values Avoid using magic numbers / values They are hard to maintain They are hard to maintain When change occurs, you need to modify all occurrences of the magic number / constant When change occurs, you need to modify all occurrences of the magic number / constant Their meaning is not obvious Their meaning is not obvious Example: what does the number 1024 mean? Example: what does the number 1024 mean? 122

123 123 public 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 axis2) public static double CalcElipseArea(double axis1, double axis2) { double area = 3.14159206 * axis1 * axis2; double area = 3.14159206 * axis1 * axis2; return area; return area; }}

124 124 public 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 axis2) public static double CalcElipseArea(double axis1, double axis2) { double area = PI * axis1 * axis2; double area = PI * axis1 * axis2; return area; return area; }}

125 Constants should be used in the following cases: Constants should be used in the following cases: When we need to use numbers or other values and their logical meaning and value are not obvious When we need to use numbers or other values and their logical meaning and value are not obvious File names File names Mathematical constants Mathematical constants Bounds and ranges Bounds and ranges 125 public const string SettingsFileName = "ApplicationSettings.xml"; "ApplicationSettings.xml"; public const double E = 2.7182818284; public const int READ_BUFFER_SIZE = 5 * 1024 *1024;

126 Sometime it is better to keep the magic values instead of using a constant Sometime it is better to keep the magic values instead of using a constant Error messages and exception descriptions Error messages and exception descriptions SQL commands for database operations SQL commands for database operations Titles of GUI elements (labels, buttons, menus, dialogs, etc.) Titles of GUI elements (labels, buttons, menus, dialogs, etc.) For internationalization purposes use resources, not constants For internationalization purposes use resources, not constants 126

127 Using Conditional Statements and Loops Correctly

128 Always use { and } for the conditional statements body, even when it is a single line: Always use { and } for the conditional statements body, even when it is a single line: Why omitting the brackets could be harmful? Why omitting the brackets could be harmful? This is misleading code + misleading formatting This is misleading code + misleading formatting 128 if (condition) { DoSometing(); DoSometing();} if (condition) DoSomething(); DoSomething(); DoAnotherThing(); DoAnotherThing();DoDifferentThing();

129 Do not use complex if conditions Do not use complex if conditions You can always simplify them by introducing boolean variables or boolean methods You can always simplify them by introducing boolean variables or boolean methods Incorrect example: Incorrect example: Complex boolean expressions are harmful Complex boolean expressions are harmful How you will find the problem if you get IndexOutOfRangeException ? How you will find the problem if you get IndexOutOfRangeException ? 129 if (x > 0 && y > 0 && x 0 && y > 0 && x < Width-1 && y < 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])

130 The last example can be easily refactored into self-documenting code: The last example can be easily refactored into self-documenting code: Now the code is: Now the code is: Easy to read – the logic of the condition is clear Easy to read – the logic of the condition is clear Easy to debug – breakpoint can be put at the if Easy to debug – breakpoint can be put at the if 130 bool inRange = x > 0 && y > 0 && x 0 && y > 0 && x < Width-1 && y < Height-1; 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 && !visited[x, y])

131 Deep nesting of conditional statements and loops makes the code unclear Deep nesting of conditional statements and loops makes the code unclear Deeply nested code is complex and hard to read and understand Deeply nested code is complex and hard to read and understand Usually you can extract portions of the code in separate methods Usually you can extract portions of the code in separate methods This simplifies the logic of the code This simplifies the logic of the code Using good method name makes the code self- documenting Using good method name makes the code self- documenting 131

132 132 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]; } else else { maxElem = arr[i + 2]; maxElem = arr[i + 2]; } } else else { if (arr[i + 1] < arr[i + 3]) if (arr[i + 1] < arr[i + 3]) { maxElem = arr[i + 3]; maxElem = arr[i + 3]; } else else { maxElem = arr[i + 1]; maxElem = arr[i + 1]; } } } (continues on the next slide)

133 133 else else { 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]; } else else { maxElem = arr[i + 2]; maxElem = arr[i + 2]; } } else else { if (arr[i] < arr[i + 3]) if (arr[i] < arr[i + 3]) { maxElem = arr[i + 3]; maxElem = arr[i + 3]; } else else { maxElem = arr[i]; maxElem = arr[i]; } } }}

134 134 private static int Max(int i, int j) { if (i < j) if (i < j) { return j; return j; } else else { return i; return i; }} 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; } else else { int maxElem = Max(i, k); int maxElem = Max(i, k); return maxElem; return maxElem; }} (continues on the next slide)

135 135 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 + 3]); int maxElem = Max(arr[i + 1], arr[i + 2], arr[i + 3]); return maxElem; return maxElem; } else else { 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) { maxElem = FindMax(arr, i); maxElem = FindMax(arr, i);}

136 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 136

137 137 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; } else else { tag = tag + ch; tag = tag + ch; } break; break; OutOfTag: OutOfTag: … }}

138 138 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); }}

139 Choosing the correct type of loop: Choosing the correct type of loop: Use for loop to repeat some block of code a certain number of times Use for loop to repeat some block of code a certain number of times Use foreach loop to process each element of array or collection Use foreach loop to process each element of array or collection Use while / do - while loop when you don't know how many times a block should be repeated Use while / do - while loop when you don't know how many times a block should be repeated Avoid deep nesting of loops Avoid deep nesting of loops You can extract the loop body in a new method You can extract the loop body in a new method 139

140 Keep loops simple Keep loops simple This helps readers of your code This helps readers of your code Treat the inside of the loop as it were a routine Treat the inside of the loop as it were a routine Dont make the reader look inside the loop to understand the loop control Dont make the reader look inside the loop to understand the loop control Think of a loop as a black box: Think of a loop as a black box: 140 while (!inputFile.EndOfFile() && !hasErrors) {} (black box code)

141 Using Assertions and Exceptions Correctly

142 Fundamental principle of defensive programming Fundamental principle of defensive programming Defensive programming means: Defensive programming means: To expect incorrect input and to handle it correctly To expect incorrect input and to handle it correctly To think not only about the usual execution flow, but to consider also unusual situations To think not only about the usual execution flow, but to consider also unusual situations To ensure that incorrect input results to exception, not to incorrect output To ensure that incorrect input results to exception, not to incorrect output 142 Any public method should check its input data, preconditions and postconditions

143 143 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:" + length); throw new ArgumentException("Invalid length:" + length); } … Debug.Assert(result.Length == length); Debug.Assert(result.Length == length);} Check the input and preconditions. Perform the method main logic. Check the postconditions.

144 Choose a good name for your exception class Choose a good name for your exception class Incorrect example: Incorrect example: Example: Example: Use descriptive error messages Use descriptive error messages Incorrect example: Incorrect example: Example: Example: 144 throw new Exception("File error!"); throw new FileNotFoundException("Cannot find file " + fileName); throw new Exception("Error!"); throw new ArgumentException("The speed should be a number " + "between " + MIN_SPEED + " and " + MAX_SPEED + "."); "between " + MIN_SPEED + " and " + MAX_SPEED + ".");

145 Catch only exceptions that you are capable to process correctly Catch only exceptions that you are capable to process correctly Do not catch all exceptions! Do not catch all exceptions! Incorrect example: Incorrect example: What about OutOfMemoryException ? What about OutOfMemoryException ? 145 try{ ReadSomeFile(); ReadSomeFile();}catch{ Console.WriteLine("File not found!"); Console.WriteLine("File not found!");}

146 Always include the exception cause when throwing a new exception Always include the exception cause when throwing a new exception 146 try{ WithdrawMoney(account, amount); WithdrawMoney(account, amount);} catch (DatabaseException dbex) { throw new WithdrawException(String.Format( throw new WithdrawException(String.Format( "Can not withdraw the amount {0} from acoount {1}", "Can not withdraw the amount {0} from acoount {1}", amount, account), dbex); amount, account), dbex);} We include in the exceptions chain the original source of the problem.

147 Throw exceptions at the corresponding level of abstraction Throw exceptions at the corresponding level of abstraction Example: Bank account withdrawal operation could throw InsufficientFundsException but cannot throw FileAccessDeniedException Example: Bank account withdrawal operation could throw InsufficientFundsException but cannot throw FileAccessDeniedException Display to the end users only messages that they could understand Display to the end users only messages that they could understand 147 or

148 Handle disposable resources with care Handle disposable resources with care All classes implementing IDisposable should follow the try-finally / using pattern: All classes implementing IDisposable should follow the try-finally / using pattern: 148 StreamReader reader = new StreamReader("file.txt"); new StreamReader("file.txt");try{ String line = reader.ReadLine(); String line = reader.ReadLine();}finally{ reader.Close(); reader.Close();} StreamReader reader = new StreamReader( new StreamReader( "file.txt"); "file.txt"); using (reader) { String line = String line = reader.ReadLine(); reader.ReadLine();} ==

149 The Concept of Self-Documenting Code

150 Effective comments do not repeat the code Effective comments do not repeat the code They explain it at higher level and reveal non- obvious details They explain it at higher level and reveal non- obvious details The best software documentation is the source code itself – keep it clean and readable The best software documentation is the source code itself – keep it clean and readable Self-documenting code is code that is self- explainable and does not need comments Self-documenting code is code that is self- explainable and does not need comments Simple design, small well named methods, strong cohesion and loose coupling, simple logic, good variable names, good formatting, … Simple design, small well named methods, strong cohesion and loose coupling, simple logic, good variable names, good formatting, … 150

151 Self-documenting code fundamental principles Self-documenting code fundamental principles 151 The best documentation is the code itself. Do not document bad code, rewrite it! Make the code self-explainable and self- documenting, easy to read and understand.

152 152 public static List FindPrimes(int start, int end) { // Create new list of integers // Create new list of integers List primesList = new List (); List primesList = new List (); // 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 prime // We found a divider -> the number is not prime prime = false; prime = false; // Exit from the loop // Exit from the loop break; break; } (continues on the next slide)

153 153 // 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;}

154 154 public static List FindPrimes(int start, int end) { List primesList = new List (); List primesList = new List (); 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 need comments. It is self-explaining.

155 155 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 name and are easy to read and understand. This comment explain non-obvious details. It does not repeat the code.

156 Improving the Quality of the Existing Code

157 What is refactoring of the source code? What is refactoring of the source code? Improving the design and quality of existing source code without changing its behavior Improving the design and quality of existing source code without changing its behavior Step by step process that turns the bad code into good code (if possible) Step by step process that turns the bad code into good code (if possible) Why we need refactoring? Why we need refactoring? Code constantly changes and its quality constantly degrades (unless refactored) Code constantly changes and its quality constantly degrades (unless refactored) Requirements often change and code needs to be changed to follow them Requirements often change and code needs to be changed to follow them 157

158 When should we perform refactoring of the code? When should we perform refactoring of the code? Bad smells in the code indicate need of refactoring Bad smells in the code indicate need of refactoring Unit tests guarantee that refactoring does not change the behavior Unit tests guarantee that refactoring does not change the behavior Rafactoring patterns Rafactoring patterns Large repeating code fragments e xtract repeating code in separate method Large repeating code fragments e xtract repeating code in separate method Large methods split them logically Large methods split them logically Large loop body or deep nesting extract method Large loop body or deep nesting extract method 158

159 Refactoring patterns Refactoring patterns Class or method has weak cohesion split into several classes / methods Class or method has weak cohesion split into several classes / methods Single change carry out changes in several classes classes have tight coupling consider redesign Single change carry out changes in several classes classes have tight coupling consider redesign Related data are always used together but are not part of a single class group them in a class Related data are always used together but are not part of a single class group them in a class A method has too many parameters create a class to groups parameters together A method has too many parameters create a class to groups parameters together A method calls more methods from another class than from its own class move it A method calls more methods from another class than from its own class move it 159

160 Refactoring patterns Refactoring patterns Two classes are tightly coupled merge them or redesign them to separate their responsibilities Two classes are tightly coupled merge them or redesign them to separate their responsibilities Public non-constant fields make them private and define accessing properties Public non-constant fields make them private and define accessing properties Magic numbers in the code consider extracting constants Magic numbers in the code consider extracting constants Bad named class / method / variable rename it Bad named class / method / variable rename it Complex boolean condition split it to several expressions or method calls Complex boolean condition split it to several expressions or method calls 160

161 Refactoring patterns Refactoring patterns Complex expression split it into few simple parts Complex expression split it into few simple parts A set of constants is used as enumeration convert it to enumeration A set of constants is used as enumeration convert it to enumeration Method logic is too complex and is hard to understand extract several more simple methods or even create a new class Method logic is too complex and is hard to understand extract several more simple methods or even create a new class Unused classes, methods, parameters, variables remove them Unused classes, methods, parameters, variables remove them Large data is passed by value without a good reason pass it by reference Large data is passed by value without a good reason pass it by reference 161

162 Refactoring patterns Refactoring patterns Few classes share repeating functionality extract base class and reuse the common code Few classes share repeating functionality extract base class and reuse the common code Different classes need to be instantiated depending on configuration setting use factory Different classes need to be instantiated depending on configuration setting use factory Code is not well formatted reformat it Code is not well formatted reformat it Too many classes in a single namespace split classes logically into more namespaces Too many classes in a single namespace split classes logically into more namespaces Unused using definitions remove them Unused using definitions remove them Non-descriptive error messages improve them Non-descriptive error messages improve them Absence of defensive programming add it Absence of defensive programming add it 162

163 163 Code Complete, 2 nd edition, Steve McConnell, Microsoft Press, 2004, ISBN 0735619670, Code Complete, 2 nd edition, Steve McConnell, Microsoft Press, 2004, ISBN 0735619670, http://www.cc2e.com http://www.cc2e.com The bible of high-quality software construction: The bible of high-quality software construction: The "High-quality programming code construction" course at Telerik Academy: The "High-quality programming code construction" course at Telerik Academy: http://codecourse.telerik.com http://codecourse.telerik.com http://codecourse.telerik.com

164 Questions?


Download ppt "Revealing the Secrets of Self-Documenting Code Svetlin Nakov Telerik Corporation www.telerik.com For C# Developers."

Similar presentations


Ads by Google