Week 7: Top Down Design (TDD)
Week 7 Goals
-
Learn to read data from files
-
Learn key Top Down Design concepts
-
Learn how to write functions stubs
-
Learn how to implement a design bottom-up
-
Learn to design and test functions incrementally
Week 7 Code
-
using_files.py
: reading a file and printing its contents-
Open a pointer into a file:
fp = open(filename, 'r')
-
Treat the file as a sequence of lines:
for line in fp:
-
Strip off the newline character from the end of a string:
str.strip()
-
Split up a string:
str.split()
-
Close the file when all lines have been processed:
fp.close()
-
-
students.py
: practice reading in files -
section1.csv
,section2.csv
,section3.csv
: sample csv files with stuent names and class years in each section of cs21 -
design_flashcards.py
: designing a flashcard program -
french.csv
,german.csv
,spanish.csv
: sample csv files for flashcards program
Top Down Design
One of the primary topics in this class is Top Down Design (TDD), a problem solving technique that computer scientists use to solve larger problems. It is a technique that is done before coding where we:
-
Start with general description of problem
-
Break it into several high-level steps
-
Iteratively break the steps into smaller steps until you have steps that are easier to solve
Top-down design is a lot like creating a paper outline for a large paper where you start with the main sections, and iteratively refine each part with more and more detail until you are ready to start writing the paper.
When you use top-down design, your resulting program’s structure will
match the above idea of an outline. The main
function should have
calls to a few high-level functions, one for each high-level
step. High-level functions have calls to medium-level functions that
implement sub-steps of the high-level steps. Once a function
represents a small concept that you can easily implement, you can
proceed to bottom-up implementation.
Iterative Refinement
When writing a large program, programmers use iterative refinement. After an initial top-down design, you write function stubs for each function with a minimal implementation that allows you to test the overall flow of the program. Iteratively fill in the implementation of each function, refining and testing one function at a time. The idea is to write some code, test it, then write a little more code, and test it before writing even more. Usually we write a function, then test it, then write another function and test it. By being careful about testing, you can often isolate bugs in my program to the new code you just added.
Function Prototyping
We often use prototyping to just put in function stubs so we can test the whole program’s flow of control without having to have a full implementation. For example, below is a stub for a function to compute the average of a list of numbers. The function doesn’t actually do anything related to the task, but we can call it from other parts of our program to see if the program’s flow matches the design.
def main():
values = [3, 1, 6]
# a sample call to our function to see if it works
test = average_of_list(values)
# for now, the program doesn't crash, but returns an incorrect result
# of the correct type. We can now go back and refine our function
print("Answer is: %.2f " % (test))
def average_of_list(nums):
"""
This function computes the average of a list of numbers
Parameters:
nums (list)
returns (float) the average of the numbers in the list
"""
print("inside average_or_list")
# TODO: implement this function
return 2.0 # a bogus return value, but it lets us run the program
# and make calls to this function to model program flow
main()