37
Notes about writing Notes about writing functions functions Juin-Der Lee

Notes about writing functions

Embed Size (px)

Citation preview

Notes about writing functionsNotes about writing functions

Juin-Der Lee

•Software Design

•Procedural Programming

•Factory

•Matlab

•Object-Oriented Programming

Input dataLocal data

function

Output data

Local data

function

Global data

•An Example of bad function

•Advantages of using functions

•Cohesion

•Coupling

•Defensive functions

Outline

An Example of bad function

Procedure HandleStuff( Var InputRec: CORP_DATA,

CrntQtr: integer, Emprec: EMP_DATA,

Var EstimRevenue: Real, YTDRevenue: Real,

ScreenX: integer, ScreenY: integer,

Var NewColor: COLOR_TYPE, Var PreColor: COLOR_TYPE,

Var Status:STATUS_TYPE, ExpenseType: integer);

Begin

for I := 1 to 100 do begin

InputRec.revenue[i] := 0;

InputRec.expense[i] := CorpExpense[ CrntQtr, i]

end;

UpdateCorpDatabse( EmpRec );EstimRevenue := YTDRevenue * 4.0 / real( CrntQtr );NewColor := PrevColor;Status := Success;if ExpenseType = 1 then begin for I := 1 to 12 do Profit[i] := Revenue[i] – Expense. Type1[i] endelse if ExpenseType = 2 then begin Profit[i] := Revenue[i] – Expense.Type2[i] endelse if ExpenseType = 3 then begin Profit[i] := revenue[i].Type3[i] endend

•Function name

•No comments

•Inconsistent Layout

•Frequently Access Global variables

•No error handling

•Magic numbers

•Some input arguments are not used

•Too many parameters

Problems

An Example of bad function

Procedure HandleStuff( Var InputRec: CORP_DATA,

CrntQtr: integer, Emprec: EMP_DATA,

Var EstimRevenue: Real, YTDRevenue: Real,

ScreenX: integer, ScreenY: integer,

Var NewColor: COLOR_TYPE, Var PreColor: COLOR_TYPE,

Var Status:STATUS_TYPE, ExpenseType: integer);

Begin

for I := 1 to 100 do begin

InputRec.revenue[i] := 0;

InputRec.expense[i] := CorpExpense[ CrntQtr, i]

end;

UpdateCorpDatabse( EmpRec );EstimRevenue := YTDRevenue * 4.0 / real( CrntQtr );NewColor := PrevColor;Status := Success;if ExpenseType = 1 then begin for I := 1 to 12 do Profit[i] := Revenue[i] – Expense. Type1[i] endelse if ExpenseType = 2 then begin Profit[i] := Revenue[i] – Expense.Type2[i] endelse if ExpenseType = 3 then begin Profit[i] := Revenue[i].Type3[i] endend

•Function name

•No comments

•Inconsistent Layout

•Frequently Access Global variables

•No error handling

•Magic numbers

•Some input arguments are not used

•Too many parameters

Problems

An Example of bad function

Procedure HandleStuff( Var InputRec: CORP_DATA,

CrntQtr: integer, Emprec: EMP_DATA,

Var EstimRevenue: Real, YTDRevenue: Real,

ScreenX: integer, ScreenY: integer,

Var NewColor: COLOR_TYPE, Var PreColor: COLOR_TYPE,

Var Status:STATUS_TYPE, ExpenseType: integer);

Begin

for I := 1 to 100 do begin

InputRec.revenue[i] := 0;

InputRec.expense[i] := CorpExpense[ CrntQtr, i]

end;

UpdateCorpDatabse( EmpRec );EstimRevenue := YTDRevenue * 4.0 / real( CrntQtr );NewColor := PrevColor;Status := Success;if ExpenseType = 1 then begin for I := 1 to 12 do Profit[i] := Revenue[i] – Expense. Type1[i] endelse if ExpenseType = 2 then begin Profit[i] := Revenue[i] – Expense.Type2[i] endelse if ExpenseType = 3 then begin Profit[i] := Revenue[i].Type3[i] endend

•Function name

•No comments

•Inconsistent Layout

•Frequently Access Global variables

•No error handling

•Magic numbers

•Some input arguments are not used

•Too many parameters

Problems

An Example of bad function

Procedure HandleStuff( Var InputRec: CORP_DATA,

CrntQtr: integer, Emprec: EMP_DATA,

Var EstimRevenue: Real, YTDRevenue: Real,

ScreenX: integer, ScreenY: integer,

Var NewColor: COLOR_TYPE, Var PreColor: COLOR_TYPE,

Var Status:STATUS_TYPE, ExpenseType: integer);

Begin

for I := 1 to 100 do begin

InputRec.revenue[i] := 0;

InputRec.expense[i] := CorpExpense[ CrntQtr, i]

end;

UpdateCorpDatabse( EmpRec );EstimRevenue := YTDRevenue * 4.0 / real( CrntQtr );NewColor := PrevColor;Status := Success;if ExpenseType = 1 then begin for I := 1 to 12 do Profit[i] := Revenue[i] – Expense. Type1[i] endelse if ExpenseType = 2 then begin Profit[i] := Revenue[i] – Expense.Type2[i] endelse if ExpenseType = 3 then begin Profit[i] := Revenue[i].Type3[i] endend

•Function name

•No comments

•Inconsistent Layout

•Frequently Access Global variables

•No error handling

•Magic numbers

•Some input arguments are not used

•Too many parameters

Problems

An Example of bad function

Procedure HandleStuff( Var InputRec: CORP_DATA,

CrntQtr: integer, Emprec: EMP_DATA,

Var EstimRevenue: Real, YTDRevenue: Real,

ScreenX: integer, ScreenY: integer,

Var NewColor: COLOR_TYPE, Var PreColor: COLOR_TYPE,

Var Status:STATUS_TYPE, ExpenseType: integer);

Begin

for I := 1 to 100 do begin

InputRec.revenue[i] := 0;

InputRec.expense[i] := CorpExpense[ CrntQtr, i]

end;

UpdateCorpDatabse( EmpRec );EstimRevenue := YTDRevenue * 4.0 / real( CrntQtr );NewColor := PrevColor;Status := Success;if ExpenseType = 1 then begin for I := 1 to 12 do Profit[i] := Revenue[i] – Expense. Type1[i] endelse if ExpenseType = 2 then begin Profit[i] := Revenue[i] – Expense.Type2[i] endelse if ExpenseType = 3 then begin Profit[i] := Revenue[i].Type3[i] endend

•Function name

•No comments

•Inconsistent Layout

•Frequently Access Global variables

•No error handling

•Magic numbers

•Some input arguments are not used

•Too many parameters

Problems

An Example of bad function

Procedure HandleStuff( Var InputRec: CORP_DATA,

CrntQtr: integer, Emprec: EMP_DATA,

Var EstimRevenue: Real, YTDRevenue: Real,

ScreenX: integer, ScreenY: integer,

Var NewColor: COLOR_TYPE, Var PreColor: COLOR_TYPE,

Var Status:STATUS_TYPE, ExpenseType: integer);

Begin

for I := 1 to 100 do begin

InputRec.revenue[i] := 0;

InputRec.expense[i] := CorpExpense[ CrntQtr, i]

end;

UpdateCorpDatabse( EmpRec );EstimRevenue := YTDRevenue * 4.0 / real( CrntQtr );NewColor := PrevColor;Status := Success;if ExpenseType = 1 then begin for I := 1 to 12 do Profit[i] := Revenue[i] – Expense. Type1[i] endelse if ExpenseType = 2 then begin Profit[i] := Revenue[i] – Expense.Type2[i] endelse if ExpenseType = 3 then begin Profit[i] := revenue[i].Type3[i] endend

•Function name

•No comments

•Inconsistent Layout

•Frequently Access Global variables

•No error handling

•Magic numbers

•Some input arguments are not used

•Too many parameters

Problems

An Example of bad function

Procedure HandleStuff( Var InputRec: CORP_DATA,

CrntQtr: integer, Emprec: EMP_DATA,

Var EstimRevenue: Real, YTDRevenue: Real,

ScreenX: integer, ScreenY: integer,

Var NewColor: COLOR_TYPE, Var PreColor: COLOR_TYPE,

Var Status:STATUS_TYPE, ExpenseType: integer);

Begin

for I := 1 to 100 do begin

InputRec.revenue[i] := 0;

InputRec.expense[i] := CorpExpense[ CrntQtr, i]

end;

UpdateCorpDatabse( EmpRec );EstimRevenue := YTDRevenue * 4.0 / real( CrntQtr );NewColor := PrevColor;Status := Success;if ExpenseType = 1 then begin for I := 1 to 12 do Profit[i] := Revenue[i] – Expense. Type1[i] endelse if ExpenseType = 2 then begin Profit[i] := Revenue[i] – Expense.Type2[i] endelse if ExpenseType = 3 then begin Profit[i] := revenue[i].Type3[i] endend

•Function name

•No comments

•Inconsistent Layout

•Frequently Access Global variables

•No error handling

•Magic numbers

•Some input arguments are not used

•Too many parameters

Problems

An Example of bad function

Procedure HandleStuff( Var InputRec: CORP_DATA,

CrntQtr: integer, Emprec: EMP_DATA,

Var EstimRevenue: Real, YTDRevenue: Real,

ScreenX: integer, ScreenY: integer,

Var NewColor: COLOR_TYPE, Var PreColor: COLOR_TYPE,

Var Status:STATUS_TYPE, ExpenseType: integer);

Begin

for I := 1 to 100 do begin

InputRec.revenue[i] := 0;

InputRec.expense[i] := CorpExpense[ CrntQtr, i]

end;

UpdateCorpDatabse( EmpRec );EstimRevenue := YTDRevenue * 4.0 / real( CrntQtr );NewColor := PrevColor;Status := Success;if ExpenseType = 1 then begin for I := 1 to 12 do Profit[i] := Revenue[i] – Expense. Type1[i] endelse if ExpenseType = 2 then begin Profit[i] := Revenue[i] – Expense.Type2[i] endelse if ExpenseType = 3 then begin Profit[i] := revenue[i].Type3[i] endend

•Function name

•No comments

•Inconsistent Layout

•Frequently Access Global variables

•No error handling

•Magic numbers

•Some input arguments are not used

•Too many parameters

Problems

An Example of bad function

Procedure HandleStuff( Var InputRec: CORP_DATA,

CrntQtr: integer, Emprec: EMP_DATA,

Var EstimRevenue: Real, YTDRevenue: Real,

ScreenX: integer, ScreenY: integer,

Var NewColor: COLOR_TYPE, Var PreColor: COLOR_TYPE,

Var Status:STATUS_TYPE, ExpenseType: integer);

Begin

for I := 1 to 100 do begin

InputRec.revenue[i] := 0;

InputRec.expense[i] := CorpExpense[ CrntQtr, i]

end;

UpdateCorpDatabse( EmpRec );EstimRevenue := YTDRevenue * 4.0 / real( CrntQtr );NewColor := PrevColor;Status := Success;if ExpenseType = 1 then begin for I := 1 to 12 do Profit[i] := Revenue[i] – Expense. Type1[i] endelse if ExpenseType = 2 then begin Profit[i] := Revenue[i] – Expense.Type2[i] endelse if ExpenseType = 3 then begin Profit[i] := revenue[i].Type3[i] endend

Advantages of using functions

if ( Node <> NULL)

while ( Node.Next <> NULL ) do

Node = Node.Next

LeafName = Node.Name

else

LeafName = “”

End

•Reduce program complex

•Readability

•Avoid redundant code

•Information hiding

•Data structure

•Algorithm (how it does vs. what it does)

•Reusability

LeafName = GetLeafName (Node);

node

root

node

leaf

using functions even simple codes

Points = DeviceUnits * (POINTS_PER_INCH / DeviceUnitsPerInch());

DeviceUnitsToPoints(DeviceUnits Integer) : Integer;

begin

DeviceUnitsToPoints = DeviceUnits * (POINTS_PER_INCH / DeviceUnitsPerInch());

end

Points = DeviceUnitsToPoints( DeviceUnits );

•Functional Cohesion

•Sequential Cohesion

•Communicational Cohesion

•Temporal Cohesion

Cohesion

(Why those codes are put together into a function)

•Work together for a single purpose•sin()•GetCustomerName()•EraseFile()•CalcLoanPayment()•GetIconLocation()

Functional Cohesion

•Sequential operations

Sequential Cohesion

Function f()

//OpenFile

//ReadFile

//Calculate

//OutputResult

//CloseFile

return

Function f()

//Input Birthday

//Calculate Age

//Calculate Retire Date

return

•Access the same data

Communication Cohesion

Function f()

//Print Abstract

//Initialize Abstract

return

•In this example, no functional or sequential cohesion

•Operations at the same time

•Startup(), shutdown()

Temporal Cohesion

Function Startup()

//load configure file

//Initialize temporary file

//setup memory management program

//display startup screen

return

•Simple data coupling

•Structural data coupling

•Control coupling

•Global data coupling

•Content coupling (Basic and assembly language)

Coupling

(Relations between two functions)

•Parameters are simple data type•The fewer the number of parameters the better •sin(double angle)

Simple Data Coupling

•Parameters are complex data type (i.e. structure)

•It’s not a good idea to passing structure variable if not all fields are used

Structural Data Coupling

Struct EmpRec

{

String name;

String address;

String phoneNumber;

String birthday;

String IDNumber;

};

PrintLetter(EmpRec ER);

Void PrintLetter(EmpRec ER)

{

//print Name

//print address

}

Void PrintLetter(string name, string address)

{//…}

•Control the behavior of callee function

Control Coupling

Void PrintCalendar(int op)

{

if (op==1)

//print yearly

else if (op==2)

//print monthly

else if (op==3)

//print weekly

}

Void PrintCalendarYearly()

{

}

Void PrintCalendarMonthly(){ … }

Void PrintCalendarWeekly(){ … }

•Functions communicate through global data

Global Data Coupling

Function f1()

{

//do something to g_var

//call f2()

f2();

}

Function f2()

{

//do something to g_var

}

global g_var;

Defensive Functions

•Driving car

•Assumption

•Assert()

Assert

assert( assumption, error message);

Example:

assert( Denominator <> 0, ‘the denominator is zero’);

•Supported by C language, but not Matlab

function assert( assumption, errmsg)

if ~all(assumption),

error( errmsg );

end

return

Examples of using assert

function f(x)

%x is a 3-by-4 matrix

assert( size(x)==[3 4], ‘x is not a 3-by-4 matrix’);

return

Check data size:

assert( fclose(fid) ~= 0, ‘error closing file’);

Check operation status:

status = fclose(fid);

assert( status ~= 0, ‘error closing file’);

summary

•Take advantages of using functions whenever possible

•Maximize cohesion

•Minimize coupling

•Make functions defensive using assert()