300 likes | 591 Views
High-Quality Routines. Chapter 5-6. Review Class Quality Checklist. Outline. What is a Routine? Valid Reasons to Create a Routine Design at the Routine Level Good Routine Names How Long Can a Routine Be? How to Use Routine Parameters?. What Is a Routine?.
E N D
High-Quality Routines Chapter 5-6
Outline • What is a Routine? • Valid Reasons to Create a Routine • Design at the Routine Level • Good Routine Names • How Long Can a Routine Be? • How to Use Routine Parameters?
What Is a Routine? • An individual method or procedure invokcable for a single purpose • Function in C, macros in C/C++ • Method in Java • What is a high/low-quality routine?
Problems • Bad routine name – it tells you nothing • No documentation • Bad layout • InputRec is changed • if it is input, its value should not be modified (const), o.w. it should not be called inputRec • Read/write global variables • Read from corpExpense • Write to profit
Problems - cont • Non-single purpose • No defense against bad data – crntQtr =0? • Use of magic numbers - 100, 4.0, 12, 2, 3 • Unused routine parameters: screenX, screenY • Two many parameters • Poorly ordered, undocumented parameters
Another Example if ( ( (‘a’<=inputChar) && (inputChar <=‘z’)) || ( (‘A’<=inputChar) && (inputChar <=‘Z’))) { charType = CharacterType.Letter; } else if ( (inputChar==‘ ‘) ||(inputChar == ‘,’) || (inputChar==‘.‘) || (inputChar==‘!‘) || (inputChar==‘(‘) || (inputChar==‘)‘) || (inputChar==‘:‘) || (inputChar==‘;‘) || (inputChar==‘?‘) || (inputChar==‘-‘)) { charType = CharacterType.Punctuation; } else if ((‘0’<=inputChar) && (inputChar <=‘9’)) { charType = CharacterType.Digit; }
Valid Reasons to Create a Routine • Reduce complexity • Introduce an intermediate, understandable abstraction • Putting a section of code into a well-named routine is one of the best way to document its purpose • if (node<>null) then while (node.next<>null) do node=node.next leafName = node.name end while else leafName = “” end if • leafName = GetLeafName(node)
Valid Reasons to Create a Routine - cont • Avoid duplicate code • Creation of similar code in two routines implies an error in decomposition • Support subclassing • Need less new code to override a short, well-factored routine than a long, poorly factored routine • Reduce the chance of error in subclass if overrideable routines are kept simple • Hide sequences • Good to hide the order in which events happen to be processed • Independently get data from the user and from a file • Read the top of a stack and decrement StackTop variable PopStack
Valid Reasons to Create a Routine - cont • Hide pointer operations • Improve portability • Simplify complicated boolean tests • Get the details of the test out of the way • A descriptive routine name summarizes the purpose of the test • Improve performance • Having code in one place will make it easier to profile to find inefficiencies • Optimize the code in one place instead of in several places
Operations That Seem Too Simple • Assume the calculation in a dozen places points = deviceUnits * (POINTS_PER_INCH/DeviceUnitsPerInch()) • What does the expression mean? • Convert a measurement in device units to a measurement in points • Put the expression into a routine?
Function Version • Function DeviceUnitsToPoints(deviceUnits Integer): Integer DeviceUnitsToPoints = deviceUnits * (POINTS_PER_INCH/DeviceUnitsPerInch()) End Function • Function Call points = DeviceUnitsToPoints(deviceUnits) • More readable – even approaching self-doc • Any other benefit of the function?
Design at Routine Level • Cohesion: • how much do two routines have to know about each other? • Criteria • size of the coupling • how many things do two routines share? • Intimacy • how closely coupled is the shared information? • Ex: Function A(p1, p2, p3) { Function B(p1); Function C(p2); Function D(p3); } # using local variables rather than global variables increases intimacy and visibility# hide data, but not manipulation of it. • Flexibility • how easily can you change the connection between routines? • you want to be able to change any routine without impacting other routines
Design at Routine Level • Functional cohesion – strongest and best • A routine performs one and only operation • Sin, GetCustomerName, EraseFile • Assume they do what their names say they do
Cohesion Less Than Ideal • Sequential cohesion – operations in routine • must be performed in a specific order • share data from step to step • don’t make up a complete function • Calculate Birthrate->age->retirement date • Communicational cohesion - operations in routine • make use of the same data, aren’t related in any other way • Print a summary and re-init the data passed to it • Temporal cohesion • Operations are combined into a routine because they are all done at the same time • Read config file->init scratch file->set up a memory manager and how an screen
Cohesion Unacceptable • Procedural cohesion • Operations are done in a specified order and the operation don’t need to be combined for any other reason. • A routine gets an employee name, then an address, and then a phone number – matching the order in which the user is asked for • Another routine gets the rest of the employee data - procedural cohesion • Make sure the calling routine has a single, complete job: getEmployee() vsGetFirstPart…()
Cohesion Unacceptable - cont • illogical cohesion • Several operations are stuffed into the same routine and one of the operations is selected by a control flag that is passed in • Control flow is the only thing that ties them together • Compute(), Edit(), Print(); • Coincidental cohesion • The operations in a routine have no discernible relationship to each other • HandleStuff
Good Routine Names • Describe everything the routine does • Describe all the outputs and side effects • ComputeReportTotals - inadequate for ‘compute report totals and open an output file’ • ComputeReportTotalsAndOpenOutputFile – too long and silly • Not to use less-descriptive names • To avoid side effects • Avoid meaningless, vague, or wishy-washy verbs • HandleCalculation, PerformService, DealWithOutput don’t tell you what the routines do
Good Routine Names - cont • Don’t differentiate names solely by number • OutputUser, OutputUser1, OutputUser2 • Make names as long as necessary • Optimum average length for variables: 9-15 • Routine names tend to be longer • For a function, use a description of the return value • printer.IsReady, pen.CurrentColor() • Use opposite precisely • Show/hide, open/close, source/target,… • FileOpen and _lclose • Establish conventions for common operations
Hong Long Can a Routine Be? • Theoretical best max length: one screen or one/two pages – approximately 5-100 lines • non-comment, non-blank • IBM once limited routines to 50 lines • Complex algorithm: 100-200 lines • Decades of evidence say that routines of such length are no more error-prone than short routines • Be careful if you want to write routines longer than about 200 lines
How to Use Routine Parameters • Put parameters in input-modify-output order • The sequence of operations - inputting data, changing it and sending back a result • Conflicts with the C-lib convention • If several routines use similar parameters, put them in a consistent order • Use all the parameters • Don’t use parameters as working variables int sample (int inputVal) { inputVal = inputVal * CurrentMultiplier(inputVal); … return inputVal; }
How to Use Routine Parameters - cont • Document interface assumptions about paras • Whether input-only, modified, or output-only • Units of numeric parameters (inches, meters,…) • Meanings of status codes and error values if enumerated types are not used • Ranges of expected values • Specific values that should never happen • Limit the number of parameters to about 7