550 likes | 558 Views
This lecture provides an introduction to procedural abstraction and the principles of software engineering. Topics covered include documenting algorithms, self-documenting algorithms, the use of constants, and maintaining algorithms.
E N D
Lecture 4 Introduction to Software Engineering Principles Introduction to Procedural AbstractionProcedures and Functions
Reminder • Youse guys (Okay I’m from New Jersey) can control the pace of the lecture! • How? With questions! • Always welcome, don’t have to be clever: • “That makes no sense.” • “I have no idea what you’re talking about.” • “Could you repeat the last couple of slides?”
Documenting Algorithms FICTION: The main audience for an algorithm is a computer. FACTS: Only 10-20% of $$ cost is writing algorithm. 80-90% is subsequent repair, extension, reuse by people. TRUTH: Writing algorithms for the human audience is critical and essential. DOCUMENTATION: refers to brief, explanatory comments that are written into the algorithm for the purpose of making it easy for people to understand.
Documenting Algorithms • To signify documentation, use double slash marks (//). • Whatever follows is documentation (notes to the reader) • Computer will ignore everything on the line after the // • Document: • purpose of algorithm and modules • the role of data structures • key decision points • complex calculations • changes in flow of control • Don’t document the trite & trivial: // Assign the value 4 to a_value a_value <- 4
Self-Documenting Algorithms • Make the algorithm self-documenting by: • Using descriptive identifiers. Choose variable names that describe the data they will hold. If declaring variables to hold values for the radius and area of a circle . . . Good radius, area isoftype Num Bad x isoftype Num // store radius y isoftype Num // store area
CS Buzzword Alert Literals Data values that are “hardwired” into the algorithm: algorithm Literals num_one isoftype Num num_one <- 1 your_grade isoftype Char your_grade <- ‘A’ your_score isoftype Num your_score <- 42 print(“each stmt here has a literal”) endalgorithm
LB Hardwire • Literally: Physically connecting wires as opposed to using devices such as plugs or quick connectors • Meaning: To design, build or construct in a way that make change difficult i.e. inflexible, typically poor practice. • Example: Imagine wiring all electrical appliances directly into house wiring system as opposed to having wall plugs.
Constants Constants are non-variable values in an algorithm. A constant allows us to give a name (identifier) to a fixed value, making it easier to read and understand. PI is 3.1415926 JANUARY is 1 DECEMBER is 12 if (Month = 1) becomes if (Month = JANUARY) NOTE: You CANNOT print constants and assume you get the text name. E.g. print(JANUARY) will print “1” to screen.
LB Use Constants to Improve • Readability • 168 • 10560 • 8760 HOURS_PER_WEEK FEET_PER_2_MILES HOURS_PER_YEAR • Maintainability • WORKWEEK is 40 • WORKWEEK is 35 • PI is 3.141592 • PI is 3.141592653589793
Complete Algorithm algorithm Get_Circumference // Constants PI is 3.1415 //Variables radius, circumference, diameter isoftype Num // Get Data print(“Enter the radius”) read(radius) // Calculate and Show Data diameter <- radius * 2 circumference <- diameter * PI print(“Diameter is: ”, diameter) print(“Circumference is: ”, circumference) endalgorithm
LB Don’t Do This! algorithm Get_Circumference // Constants PI is 3.1415 TWO is 2 //Variables radius, circumference, diameter isoftype Num // Get Data print(“Enter the radius”) read(radius) // Calculate and Show Data diameter <- radius * TWO circumference <- diameter * PI print(“Diameter is: ”, diameter) print(“Circumference is: ”, circumference) endalgorithm
LB Nor This! algorithm Get_Circumference // Constants PI is 3.1415 DEUX is 2 //Variables radius, circumference, diameter isoftype Num // Get Data print(“Enter the radius”) read(radius) // Calculate and Show Data diameter <- radius * DEUX circumference <- diameter * PI print(“Diameter is: ”, diameter) print(“Circumference is: ”, circumference) endalgorithm
LB Maintaining Algorithms • Imagine trying to work with (maintain) an algorithm that someone had already written. • Without some way of logically grouping instructions ... • 100 instructions (lines of code) wouldn’t be too bad to handle • 1,000 would be difficult • 10,000 would be a nightmare • Millions of instructions would be impossible Are there really 1,000,000 line programs?
Poor Implementation algorithm Compute_Grade_Bad_Example // Calculates the course grade based // on the student’s assignments prog_avg, quiz_avg, lab_avg, exam_score, grade_avg isoftype Num letter_grade isoftype Char print(“The purpose of this algorithm”) print(“is to ask the user for grade”) print(“information, calculate the”) print(“numeric grade, and then print”) print(“the letter grade for the given”) print(“input.”)
Poor Implementation // continuing print(“Enter your program average:”) read (prog) print (“Enter your quiz average:”) read (quiz) print (“Enter your lab average:”) read (lab) print (“Enter your exam score:”) read (exam) grade_avg <- Average(prog_avg, quiz_avg, lab_avg, exam_score)
Poor Implementation // continuing if (grade_avg >= 90) then letter_grade <- ‘A’ elseif (grade_avg >= 80) then letter_grade <- ‘B’ elseif (grade_avg >= 70) then letter_grade <- ‘C’ elseif (grade_avg >= 60) then letter_grade <- ‘D’ else letter_grade <- ‘F’ endif print (“Your letter grade is”, letter_grade) endalgorithm
Modularity • Most algorithms solve complicated problems. • We need to break the algorithm into smaller pieces. • We write sub-algorithms to simplify the algorithm. • This is not just an “available option,” but the very core of good design. • Algorithms that don’t feature modularity feature low abstraction, are hard to understand and fix, and are bad. • This wasn’t always held to be true, thus have had to overcome bad precedents and habits. (Y2K) LB
A Hierarchy of Abstraction Each sub-algorithm handles a single logical “chunk” of the solution. The “main” algorithm coordinates the overriding logic. It’s abstraction because we’re “considering the essence” (each task) “apart from the embodiment” (it’s component parts). It’s a hierarchy of abstraction because we’re doing this at multiple levels (task, subtask, the details hidden within the subtask, etc.). Main Calc Grade Calc Letter Grade Display Purpose
Advantages of Modularity • Details of the algorithm are hidden in the sub-algorithms, enhances understanding by hiding obscurant detail • Makes the algorithm easier to write by helping us manage the complexity (allows multiple people to work together) • Saves time, space, and effort -- modules can be called from many places within an algorithm • Permits reuse of logic – modules can be reused across different algorithms as we extend the program language • Localize errors and help in maintenance of the algorithm
Scope of Data “Where in the algorithm can something be seen/accessed?” Global Data – constants and type definitions can be seen by all modules Local Data – variables are only visible in the module in which they are declared JANUARY is 1 Main profit, loss Task 3 Task 2 Task 1 tax_costs op_expenses gross income
LB Question If variables are only “visible” in the module where they are declared... ...How are we going to pass data back and forth between modules?
LB Parameters
Parameters • Because scope is limited, we need some way for modules to communicate with other parts of the algorithm. A parameter is a specific kind of variable which allows values to be passed between the main algorithm and its modules and among those modules themselves. • Parameters are the best way to handle inter-module communication regardless of a given language’s scope rules. • Don’t confuse what a given programming language will LET you do with what you SHOULD do.
Examples of Parameters read(number1, number2) print(“Hello World!”) print(“Sum = ”, number1 + number2)
Relations Between Modules User Caller Parameters Read/Print Actual Parameters Module Formal Parameters
LB Parameters Formal Parameters Actual Parameters
Three Kinds of Parameters The parameter type is defined in relation to which direction data is flowing relative to the server (module): Input parameters pass data into a module from wherever it was called (client) Output parameters passes data from the module back to the place of call (client) Input/Output parameters communicate both ways Don't confuse with read/print!
Input/Output Operations read print Parameter Passing in out in/out LB Mass Confusion? Not the same thing
Square Root QuadMath LB Module Example Calculator Display Menu Read Choice Quadratic
Two Flavors of Modules Each module must be either a functionor a procedure Functions 1. Resolve to a single value of any type 2. May not change “state of the world” (no effects on other data, no Input/Output) 3. May only have IN parameters Procedures 1. May produce any number of values 2. May change “the state of the world” (side effects on other variables, Input/Output OK) 3. May have IN, OUT, and IN/OUT parameters
LB Module Example Algorithm Calculator Procedure Display Menu Read Choice out None Procedure Quadratic Function Square Root In/Out In Procedure QuadMath
Use of Procedures and Functions A procedure is used as a statement A function is used as an expression algorithm Do_Stuff this_Num isoftype Num that_Num isoftype Num read(this_Num) that_Num <- Cube(this_Num) Do_Fancy_Output(this_Num,that_Num) this_Num <- that_Num + this_Num print(this_Num, that_Num) endalgorithm //Do_Stuff
Client/Server Module Relationship • The module (server) services a request from the caller (client) • The server (usually) expects some valid input • The client (usually) expects some valid output • A contract between the two is necessary • Pre-conditions, post-conditions, and purpose documentation establish this contract
Design by Contract Example Calculate_Avg returnsa num (num1, num2, num3) //Purpose: calculate the sum of input numbers //Pre-condition: three valid numbers are // passed in from the client //Post-condition: the correct numeric average // is returned to the client Note: this example module definition is syntactically simplified, but the comments are correct
Why Two Types of Modules? • We want to be able to describe the intent of the instructions as clearly as possible • If the module should have no side-effects and resolves to a single value, we want the ability to specify this • Makes clearer the intent • Restricts actions (helps in maintenance) • “Cleaner” solutions
Two Types of Modules • Procedures • Functions
Procedures • Used for varied tasks • Take any number of parameters of any kind (IN, OUT, IN/OUT) • Change the values of output or input/output variables • Used as an statement unto itself • Can perform reading & printing
Calling Procedures algorithm Compute_Grade // Calculates the course grade based // on the student’s assignments prog_avg, quiz_avg, lab_avg, exam_score, grade_avg isoftype Num Display_Purpose Get_Data(prog_avg, quiz_avg, lab_avg, exam_score) grade_avg <- Average(prog_avg, quiz_avg, lab_avg, exam_score) Output_Grade(grade_avg) endalgorithm
Procedure Declaration Template Fill in the name and list any parameters as needed: procedure <NAME> ( <OPTIONAL PARAMETERS> ) // contract information (purpose, pre- and // post-conditions Constants Variables Instructions endprocedure
Declaring Procedures procedure Display_Purpose // Purpose: Prints the purpose of the algorithm // Pre-condition: none // Post-condition: purpose of alg is displayed print(“The purpose of this algorithm”) print(“is to ask the user for grade”) print(“information, calculate the”) print(“numeric grade, and then print”) print(“the letter grade for the given”) print(“input.”) endprocedure // Display_Purpose
Declaring Procedures procedure Get_Data (prog, quiz, lab, exam isoftype out Num) // Purpose: Prompts user for data & returns them // Pre-condition: none // Post-condition: passes values back to point of call print(“Enter your program average:”) read (prog) print (“Enter your quiz average:”) read (quiz) print (“Enter your lab average:”) read (lab) print (“Enter your exam score:”) read (exam) endprocedure //Get_Data
Declaring Procedures procedure Output_Grade (grade_avg isoftype in Num) //Purpose: Prints the letter grade //Pre-condition: Numeric average passed in //Post-condition: correct letter grade printed letter_grade isoftype Char if (grade_avg >= 90) then letter_grade <- ‘A’ elseif (grade_avg >= 80) then letter_grade <- ‘B’ elseif (grade_avg >= 70) then letter_grade <- ‘C’ elseif (grade_avg >= 60) then letter_grade <- ‘D’ else letter_grade <- ‘F’ endif print (“Your letter grade is”, letter_grade) endprocedure //Output_Grade
Functions • Return a single value(reduces to that value) • Have any number of input parameters • NOT have output or input/output parameters • Be used as an expression(or as part of an expression) • Not be used as a statement
Calling the Function algorithm Compute_Grade // Calculates the course grade based // on the student’s assignments prog_avg, quiz_avg, lab_avg, exam_score, grade_avg isoftype Num Display_Purpose Get_Data(prog_avg, quiz_avg, lab_avg, exam_score) grade_avg <- Average(prog_avg, quiz_avg, lab_avg, exam_score) Output_Grade(grade_avg) endalgorithm