Designing Methods Correctly, Cohesion and Coupling Svetlin Nakov Telerik Corporation www.telerik.com.

Slides:



Advertisements
Similar presentations
Revealing the Secrets of Self-Documenting Code Svetlin Nakov Telerik Corporation For C# Developers.
Advertisements

Code Correctness, Readability, Maintainability Svetlin Nakov Telerik Corporation
Quality of a Class Abstraction: Coupling & Cohesion Michael L. Collard, Ph.D. Department of Computer Science Kent State University.
Object Oriented Design An object combines data and operations on that data (object is an instance of class) data: class variables operations: methods Three.
Software Engineering and Design Principles Chapter 1.
Module: Definition ● A logical collection of related program entities ● Not necessarily a physical concept, e.g., file, function, class, package ● Often.
© Copyright 1992–2004 by Deitel & Associates, Inc. and Pearson Education Inc. All Rights Reserved. Chapter 5 - Functions Outline 5.1Introduction 5.2Program.
Computer Programming and Basic Software Engineering 4. Basic Software Engineering 1 Writing a Good Program 4. Basic Software Engineering 3 October 2007.
Chapter 1 Software Development. Copyright © 2005 Pearson Addison-Wesley. All rights reserved. 1-2 Chapter Objectives Discuss the goals of software development.
 2007 Pearson Education, Inc. All rights reserved C Functions.
Chapter 1 Principles of Programming and Software Engineering.
Chapter 8: I/O Streams and Data Files. In this chapter, you will learn about: – I/O file stream objects and functions – Reading and writing character-based.
© 2006 Pearson Addison-Wesley. All rights reserved2-1 Chapter 2 Principles of Programming & Software Engineering.
Computer Science 240 Principles of Software Design.
C++ fundamentals.
C++ Functions. 2 Agenda What is a function? What is a function? Types of C++ functions: Types of C++ functions: Standard functions Standard functions.
Chapter 9: Coupling & Cohesion Omar Meqdadi SE 273 Lecture 9 Department of Computer Science and Software Engineering University of Wisconsin-Platteville.
Design-Making Projects Work (Chapter7) n Large Projects u Design often distinct from analysis or coding u Project takes weeks, months or years to create.
Coupling and Cohesion Pfleeger, S., Software Engineering Theory and Practice. Prentice Hall, 2001.
CMSC 202 Exceptions. Aug 7, Error Handling In the ideal world, all errors would occur when your code is compiled. That won’t happen. Errors which.
Introduction CS 3358 Data Structures. What is Computer Science? Computer Science is the study of algorithms, including their  Formal and mathematical.
© The McGraw-Hill Companies, 2006 Chapter 4 Implementing methods.
Programming in Java Unit 2. Class and variable declaration A class is best thought of as a template from which objects are created. You can create many.
© Copyright 1992–2004 by Deitel & Associates, Inc. and Pearson Education Inc. All Rights Reserved. C How To Program - 4th edition Deitels Class 05 University.
1 Relational Expressions Relational expressions: –Expressions that compare operands –Sometimes called conditions –Evaluated to yield a result –Typically.
SWE 619 © Paul Ammann Procedural Abstraction and Design by Contract Paul Ammann Information & Software Engineering SWE 619 Software Construction cs.gmu.edu/~pammann/
How to Design Error Steady Code Ivaylo Bratoev Telerik Corporation
Low-Level Detailed Design SAD (Soft Arch Design) Mid-level Detailed Design Low-Level Detailed Design Design Finalization Design Document.
SE: CHAPTER 7 Writing The Program
Improving the Quality of Existing Code Svetlin Nakov Telerik Corporation
Cohesion and Coupling CS 4311
Code Correctness, Readability, Maintainability Svetlin Nakov Telerik Software Academy academy.telerik.com Technical Trainer
Introduction CS 3358 Data Structures. What is Computer Science? Computer Science is the study of algorithms, including their  Formal and mathematical.
An Object-Oriented Approach to Programming Logic and Design Fourth Edition Chapter 6 Using Methods.
Programming Logic and Design Using Methods. 2 Objectives Review how to use a simple method with local variables and constants Create a method that requires.
Intermediate 2 Software Development Process. Software You should already know that any computer system is made up of hardware and software. The term hardware.
1 Ch. 1: Software Development (Read) 5 Phases of Software Life Cycle: Problem Analysis and Specification Design Implementation (Coding) Testing, Execution.
1 FUNCTIONS - I Chapter 5 Functions help us write more complex programs.
The Software Development Process
1 CSCD 326 Data Structures I Software Design. 2 The Software Life Cycle 1. Specification 2. Design 3. Risk Analysis 4. Verification 5. Coding 6. Testing.
1-1 Software Development Objectives: Discuss the goals of software development Identify various aspects of software quality Examine two development life.
Designing Classes. Software changes Software is not like a novel that is written once and then remains unchanged. Software is extended, corrected, maintained,
Revealing the Secrets of Self-Documenting Code Svetlin Nakov Telerik Corporation
© 2006 Pearson Addison-Wesley. All rights reserved2-1 Chapter 2 Principles of Programming & Software Engineering.
Object Oriented Programming
© 2006 Pearson Addison-Wesley. All rights reserved 2-1 Chapter 2 Principles of Programming & Software Engineering.
Testing OO software. State Based Testing State machine: implementation-independent specification (model) of the dynamic behaviour of the system State:
Software Engineering and Object-Oriented Design Topics: Solutions Modules Key Programming Issues Development Methods Object-Oriented Principles.
Intermediate 2 Computing Unit 2 - Software Development.
High-Quality Methods Design and Implement High-Quality Methods. Cohesion and Coupling SoftUni Team Technical Trainers Software University
SEG 4110 – Advanced Software Design and Reengineering Topic T Introduction to Refactoring.
High-Quality Methods Design and Implement High-Quality Methods. Cohesion and Coupling SoftUni Team Technical Trainers Software University
High-Quality Programming Code Code Correctness, Readability, Maintainability Svetlin Nakov Technical Trainer Software University
Refactoring Agile Development Project. Lecture roadmap Refactoring Some issues to address when coding.
More Patterns CS 124. More Basic Patterns Patterns you’ve already seen (without knowing it) Observer / Listener Wrapper Composite Decorator / Filter Patterns.
ECE450 - Software Engineering II1 ECE450 – Software Engineering II Today: Key Principles of Software Architecture and Design (II) adapted from Dave Penny’s.
Object Oriented Programming. OOP  The fundamental idea behind object-oriented programming is:  The real world consists of objects. Computer programs.
Chapter 9: Coupling & Cohesion Omar Meqdadi SE 273 Lecture 9 Department of Computer Science and Software Engineering University of Wisconsin-Platteville.
Programming Logic and Design Fifth Edition, Comprehensive Chapter 7 Using Methods.
Coupling and Cohesion Schach, S, R. Object-Oriented and Classical Software Engineering. McGraw-Hill, 2002.
Coupling and Cohesion Pfleeger, S., Software Engineering Theory and Practice. Prentice Hall, 2001.
OOP Tirgul 7. What We’ll Be Seeing Today  Packages  Exceptions  Ex4 2.
BIL 104E Introduction to Scientific and Engineering Computing Lecture 4.
High-Quality Methods How to Design and Implement High-Quality Methods? Understanding Cohesion and Coupling High-Quality Code Telerik Software Academy
Coupling and Cohesion 1.
Data Abstraction: The Walls
Chapter 5 - Functions Outline 5.1 Introduction
Improving the Design “Can the design be better?”
Programming Logic and Design Fourth Edition, Comprehensive
Software Design Lecture : 9.
Presentation transcript:

Designing Methods Correctly, Cohesion and Coupling Svetlin Nakov Telerik Corporation

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

start: mov ah,08 mov ah,08 int 21h int 21h mov bl,al mov bl,al JMP output JMP output mov ah,01 mov ah,01 int 21h int 21houtput: mov dl,"(" mov dl,"(" mov ah,02 mov ah,02 int 21h int 21h mov dl,bl mov dl,bl int 21h int 21h mov dl,")" mov dl,")" int 21h int 21hexit: mov ah,4ch mov ah,4ch mov al,00 mov al,00 int 21h int 21h 3 Jump Imagine a long program consisting of instructions and jumps not organized in any structural way

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

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

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

7 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( throw new ArgumentException( "Sides should be positive."); "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;}

 Method errors are often not indicated in real code as done correctly in the example of the previous slide: 8 internal object getValue(string propertyName) { PropertyDescriptor descriptor = PropertyDescriptor descriptor = propertyDescriptors[propertyName]; propertyDescriptors[propertyName]; return descriptor.GetDataBoundValue(); return descriptor.GetDataBoundValue();}

 If the property name does not exist  A null reference exception will be thrown (implicitly)  It is not meaningful  Use the correct exception instead: 9 internal object getValue(string propertyName) { PropertyDescriptor descriptor = PropertyDescriptor descriptor = propertyDescriptors[propertyName]; propertyDescriptors[propertyName]; if (descriptor == null) if (descriptor == null) { throw new ArgumentException ("Property name: " throw new ArgumentException ("Property name: " + propertyName + " does not exists!"); + propertyName + " does not exists!"); } return descriptor.GetDataBoundValue(); return descriptor.GetDataBoundValue();}

 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 returns incorrect output when its input is incorrect or unusual  low quality  Acceptable for private methods only  The method does too many things  bad cohesion  The method has side effects  spaghetti code  Method returns strange value when an error condition happens  it should indicate the error 10

11 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; // Hidden side effect elements[i] = 0; // Hidden side effect } 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; // Incorrect result return 0; // Incorrect result } 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;}

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

 Functional cohesion (independent function)  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  No external dependencies or side effects  Examples: 13 Math.Sqrt(value)  square root String.Substring(str, startIndex, length) Char.IsLetterOrDigit(ch)

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

 Communicational cohesion (common data)  A set of operations used to process certain data and produce a result  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 15 DisplayAnnualExpensesReport(int employeeId)

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

 Logical cohesion  Performs a different operation depending on an input parameter  Incorrect example:  Can be acceptable in event handlers (e.g. the KeyDown event in Windows Forms) 17 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 …}

 Coincidental cohesion (spaghetti)  Not related (random) operations are grouped in a method for unclear reason  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 to given customer 18 HandleStuff(customerId, int[], ref sqrtValue, mp3FileName, Address) mp3FileName, Address)

 What is loose coupling?  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  No side effects  If the coupling is loose, we can easily reuse a method or group of methods in a new project  Tight coupling  spaghetti code 19

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

 Intentionally increased coupling for more flexibility (.NET cryptography API): 21 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;}

 To reduce coupling we can make utility classes  Hide the complex logic and provide simple straightforward interface (a.k.a. façade): 22 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;}

 Passing parameters through class fields  Typical example of tight coupling  Don't do this unless you have a good reason! 23 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()); }}

 Say, we have a large piece of software  We need to update subsystems and the subsystems are not really independent  E.g. a change in filtering affects sorting, etc: 24 class GlobalManager { public void UpdateSorting() {…} public void UpdateSorting() {…} public void UpdateFiltering() {…} public void UpdateFiltering() {…} public void UpdateData() {…} public void UpdateData() {…} public void UpdateAll () {…} public void UpdateAll () {…}}

25 Data Layer Presentation Layer  Say, we have an application consisting of two layers:  Do not use a method for both top-down and bottom-up updates!  Both updates are essentially different, e.g. a RemoveCustomer routine in the DataLayer.

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

 Method is coupled to its parameters  This is the best type of coupling  Method in a class is coupled to some class fields  This coupling is usual, do not worry too much  Method in a class is coupled to static methods, properties or constants in external class  This is normal, usually is not a problem 27

 Method in a class is coupled to static fields in external class  Avoid this, classes should keep their fields private  Consider refactoring  Methods take as input data some fields that could be passed as parameters  Check the intent of the 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 28

 Put most important parameters first  First put the main input parameters  Put non-important optional parameters last  Example:  Incorrect example: 29 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)

 Do not modify the input parameters  Use new variable instead  Incorrect example:  Correct example: 30 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}

 Use parameters consistently  Use the same names and the same order in all methods  Incorrect example:  Output parameters should be put last 31 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)

 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?  Examples:  Look at the method's level of abstraction  Is it intended to operate with employees of with rates and months?  the first is incorrect 32 CalculateSalary(Employee employee, int months); CalculateSalary(double rate, int months);

 Limit the number of method parameters to 7 (+/-2)  7 is a magic number in psychology  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?  Consider putting few parameters in a new class 33

 How long should a method be?  There is no specific restriction  Avoid methods longer than one screen (30 lines)  Long methods are not always bad  Be sure you have a good reason for their 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! 34

 Pseudocode can be helpful in:  Routines design  Routines coding  Code verification  Cleaning up unreachable branches in a routine 35

 What the routine will abstract i.e. the information a routine will hide?  Routine input parameters  Routine output  Preconditions  Conditions that have to be true before a routine is called  Postconditions  Conditions that have to be true after routine execution 36

 Why it is better to spend time on design before you start coding:  The functionality may be already available in a library, so you do not need to code at all!  You need to think of the best way to implement the task considering your project requirements  If you fail on writing the code right the first time, you need to know that programmers get emotional to their code 37

38 Routine that evaluates an aggregate expression for a database column (e.g. Sum, Avg, Min) Parameters: Column Name, Expression Preconditions: (1) Check whether the column exists and throw an argument exception if not (2) If the expression parser cannot parse the expression throw an ExpressionParsingException Routine code: Call the evaluate method on the DataView class and return the resulting value as string

 Design is iterative in nature  When you spend time on design you find shortcomings that you will otherwise find later  When it will be harder to fix them  Use natural language in writing pseudocode  Pseudocode can be used as comments thus documenting the code 39

 Public routines in libraries and system software is hard to change, because customers demand no breaking changes  Two reasons why you need to change a public routine:  New functionality has to be added conflicting with the old features  The name is confusing and makes the usage of the library unintuitive 40

 When deprecating an old routine always include that in the documentation and specify the new routine that has to be used in its place  Example:  Obsolete attribute in.NET Framework 41 [Obsolete("CreateXml is deprecated. Use CreateXmlReader instead.")] Use CreateXmlReader instead.")] public void CreateXml (…) { …}

 Inline routines provide two benefits:  Abstraction  Performance benefit of not creating a new routine on the stack  Some applications (e.g. games) need that optimization  Used for the most frequently used routines  Example: a short routine called 100,000 times  Not all languages support Inline routines 42

 Designing and coding routines is engineering activity  There is no perfect solution  Competing solutions usually demonstrates different trade-offs  The task of the programmer is to evaluate the requirements and choose the most appropriate solution from the available options 43

Questions?