Designing Programs

#drnsecdesign1#1027> The preceding sections show that the development of a program requires many different steps. We need to determine what's relevant in the problem statement and what we can ignore. We need to understand what the program consumes, what it produces, and how it relates inputs to outputs. We must know, or find out, whether Scheme provides certain basic operations for the data that our program is to process. If not, we might have to develop auxiliary programs that implement these operations. Finally, once we have a program, we must check whether it actually performs the intended computation. This might reveal syntax errors, run-time problems, or even logical errors. To bring some order to this apparent chaos, it is best to set up and to follow a <#60424#><#1028#>DESIGN RECIPE<#1028#><#60424#>, that is, a step-by-step prescription of what to do next and in what order we should do things. Based on what we have experienced thus far, the development of a program requires at least the following four activities:
Understanding the Program's Purpose:
The goal of designing a program is to create a mechanism that consumes and produces data. We therefore start every program development by giving the program a meaningful name and by stating what kind of information it consumes and produces. We call this a <#60425#><#1030#>CONTRACT<#1030#><#60425#>. Here is how we write down a contract for <#60426#><#1031#>area-of-ring<#1031#><#60426#>, one of our first programs:
<#70650#>;; <#60428#><#1038#>area-of-ring<#1038#> <#1039#>:<#1039#> <#1040#>number<#1040#> <#1041#>number<#1041#> <#1042#><#1042#><#1043#>-;SPMgt;<#1043#><#1044#><#1044#> <#1045#>number<#1045#><#60428#><#70650#>
The semicolons indicate that this line is a <#60429#><#1049#>COMMENT<#1049#><#60429#>. The contract consists of two parts. The first, to the left of the colon, states the program's name. The second, to the right of the colon, specifies what kind of data the program consumes and what it produces; the inputs are separated from the output by an arrow. Once we have a contract, we can add the <#60430#><#1050#>HEADER<#1050#><#60430#>. The program header re-states the program's name and gives each input a distinct name. These names are (algebraic) variables and are referred to as the program's <#60431#><#1051#>PARAMETERS<#1051#><#60431#>. Let's take a look at the contract and header for <#60433#><#1054#>area-of-ring<#1054#><#60433#>:
  <#70651#>;; <#60434#><#1058#>area-of-ring<#1058#> <#1059#>:<#1059#> <#1060#>number<#1060#> <#1061#>number<#1061#> <#1062#><#1062#><#1063#>-;SPMgt;<#1063#><#1064#><#1064#> <#1065#>number<#1065#><#60434#><#70651#>
  <#1066#>(define<#1066#> <#1067#>(area-of-ring<#1067#> <#1068#>outer<#1068#> <#1069#>inner)<#1069#> <#1070#>...)<#1070#> 
It says that we will refer to the first input as <#60435#><#1073#>outer<#1073#><#60435#> and the second one as <#60436#><#1074#>inner<#1074#><#60436#>. Finally, using the contract and the parameters, we should formulate a short <#60437#><#1075#>PURPOSE STATEMENT<#1075#><#60437#> for the program, that is, a brief comment of <#1076#>what<#1076#> the program is to compute. For most of our programs, one or two lines will suffice; as we develop larger and larger programs, we may need to add more information to explain a program's purpose. Here is the complete starting-point for our running example:
  <#70652#>;; <#60438#><#1080#>area-of-ring<#1080#> <#1081#>:<#1081#> <#1082#>number<#1082#> <#1083#>number<#1083#> <#1084#><#1084#><#1085#>-;SPMgt;<#1085#><#1086#><#1086#> <#1087#>number<#1087#><#60438#><#70652#>
  <#1088#>;; to compute the area of a ring whose radius is<#1088#> 
  <#70653#>;; <#60439#><#1089#>outer<#1089#><#60439#> and whose hole has a radius of <#60440#><#1090#>inner<#1090#><#60440#><#70653#> 
  <#1091#>(define<#1091#> <#1092#>(area-of-ring<#1092#> <#1093#>outer<#1093#> <#1094#>inner)<#1094#> <#1095#>...)<#1095#> 
<#1098#>Hints:<#1098#> \ If the problem statement provides a mathematical formula, the number of distinct variables in the formula suggests how many inputs the program consumes. For other word problems, we must inspect the problem to separate the given facts from what is to be computed. If a given is a fixed number, it shows up in the program. If it is an unknown number, that is to be fixed by someone else later, it is an input. The question (or the imperative) in the problem statement suggests a name for the program. external ~<#60441#>Initially, your students should write down example as comments, following the contract and purpose statement; the tests should <#1100#>always<#1100#> be added to the bottom of the <#1101#>definitions<#1101#> window and should be derived from the examples. Later, as students gain more confidence, you may wish to allow them to formulate the examples as tests and to add them to the bottom immediately.<#60441#>
Program Examples:
To gain a better understanding of what the program should compute, we make up examples of inputs and determine what the output should be. For example, <#60442#><#1102#>area-of-ring<#1102#><#60442#> should produce <#60443#><#1103#>50.24<#1103#><#60443#> for the inputs <#60444#><#1104#>5<#1104#><#60444#> and <#60445#><#1105#>3<#1105#><#60445#>, because it is the difference between the area of the outer disk and the area of the inner disk. We add examples to the purpose statement:
  <#70654#>;; <#60446#><#1110#>area-of-ring<#1110#> <#1111#>:<#1111#> <#1112#>number<#1112#> <#1113#>number<#1113#> <#1114#><#1114#><#1115#>-;SPMgt;<#1115#><#1116#><#1116#> <#1117#>number<#1117#><#60446#><#70654#>
  <#1118#>;; to compute the area of a ring whose radius is<#1118#> 
  <#70655#>;; <#60447#><#1119#>outer<#1119#><#60447#> and whose hole has a radius of <#60448#><#1120#>inner<#1120#><#60448#><#70655#> 
  <#70656#>;; example: <#60449#><#1121#>(area-of-ring<#1121#> <#1122#>5<#1122#> <#1123#>3)<#1123#> <#1124#>=<#1124#> <#1125#>50.24<#1125#><#60449#><#70656#> 
  <#1126#>(define<#1126#> <#1127#>(area-of-ring<#1127#> <#1128#>outer<#1128#> <#1129#>inner)<#1129#> <#1130#>...)<#1130#> 
Making up examples---<#1134#>before we write down the program's body<#1134#>---helps in many ways. First, it is the only sure way to discover logical errors with testing. If we use the finished program to make up examples, we are tempted to trust the program because it so much easier to run the program than to predict what it does. Second, examples force us to think through the computational process, which, for the complicated cases we will encounter later, is critical to the development of the function body. Finally, examples illustrate the informal prose of a purpose statement. Future readers of the program, such as teachers, colleagues, or buyers, greatly appreciate illustrations of abstract concepts.
The Body:
Finally, we must formulate the program's body. That is, <#1135#>we must replace the ``...'' in our header with a expression<#1135#>. The expression computes the answer from the parameters, using Scheme's basic operations and Scheme programs that we already <#60450#><#1136#>define<#1136#><#60450#>d or intend to <#60451#><#1137#>define<#1137#><#60451#>. We can only formulate the program's body if we understand how the program computes the output from the given inputs. If the input-output relationship is given as a mathematical formula, we just translate mathematics into Scheme. If, instead, we are given a word problem, we must craft the expression carefully. To this end, it is helpful to revisit the examples from the second step and to understand <#1138#>how<#1138#> we computed the outputs for specific inputs. In our running example, the computational task was given via an informally stated formula that re-used <#60452#><#1139#>area-of-disk<#1139#><#60452#>, a previously <#60453#><#1140#>define<#1140#><#60453#>d program. Here is the translation into Scheme:
  <#1144#>(d<#1144#><#1145#>efine<#1145#> <#1146#>(area-of-ring<#1146#> <#1147#>outer<#1147#> <#1148#>inner)<#1148#>
    <#1149#>(-<#1149#> <#1150#>(area-of-disk<#1150#> <#1151#>outer)<#1151#> 
       <#1152#>(area-of-disk<#1152#> <#1153#>inner)))<#1153#> 
Testing:
After we have completed the program definition, we must still test the program. At a minimum, we should ensure that the program computes the expected outputs for the program examples. To facilitate testing, we may wish to add the examples to the bottom of the <#1156#>Definitions<#1156#> window as if they were equations. Then, when we click the <#1157#>Execute<#1157#> button, they are evaluated, and we see whether the program works properly on them. Testing cannot show that a program produces the correct outputs for all possible inputs---because there are typically an infinite number of possible inputs. But testing can reveal syntax errors, run-time problems, and logical mistakes. For faulty outputs, we must pay special attention to our program examples. It is possible that the examples are wrong; that the program contains a logical mistake; or that both the examples and the program are wrong. In either case, we may have to step through the entire program development again.
Figure~#figrecipe1example#1159> summarizes what we see after we have developed the program according to our recipe; figure~#figdesign1#1160> summarizes the recipe in tabular form. It should be consulted whenever we design a program.
<#70657#>;; <#1165#>Contract<#1165#>: <#60454#><#1166#>area-of-ring<#1166#> <#1167#>:<#1167#> <#1168#>number<#1168#> <#1169#>number<#1169#> <#1170#><#1170#><#1171#>-;SPMgt;<#1171#><#1172#><#1172#> <#1173#>number<#1173#><#60454#><#70657#>
<#60455#>;; <#1174#>Purpose<#1174#>: to compute the area of a ring whose radius is<#60455#> 
<#70658#>;; <#60456#><#1175#>outer<#1175#><#60456#> and whose hole has a radius of <#60457#><#1176#>inner<#1176#><#60457#><#70658#> 
<#70659#>;; <#1177#>Example<#1177#>: <#60458#><#1178#>(area-of-ring<#1178#> <#1179#>5<#1179#> <#1180#>3)<#1180#> <#1181#>=<#1181#> <#1182#>50.24<#1182#><#60458#><#70659#> 
<#60459#>;; <#1183#>Definition<#1183#>: [refines the header]<#60459#> 
<#1184#>(d<#1184#><#1185#>efine<#1185#> <#1186#>(area-of-ring<#1186#> <#1187#>outer<#1187#> <#1188#>inner)<#1188#> 
  <#1189#>(-<#1189#> <#1190#>(area-of-disk<#1190#> <#1191#>outer)<#1191#> 
     <#1192#>(area-of-disk<#1192#> <#1193#>inner)))<#1193#> 
  
<#60460#>;; <#1194#>Tests<#1194#>:<#60460#> 
<#1195#>(area-of-ring<#1195#> <#1196#>5<#1196#> <#1197#>3)<#1197#> <#1198#>=<#1198#> <#1199#>50.24<#1199#> 
<#1203#>Figure: The design recipe: a complete example<#1203#>
external ~<#1206#>None of these skills are computer-specific; all of them are needed to solve all kinds of problems. Even lawyers and doctors, artisans and secretaries can benefit from laying out their work along these lines.<#1206#>

#tabular1208#

<#1266#>Figure: The design recipe at a glance<#1266#>


The design recipe is not a magic bullet for the problems we encounter during the design of a program. It provides some guidance for process that can often appear to be overwhelming. The most creative and most difficult step in our recipe concerns the design of the program's body. At this point, it heavily relies on our ability to read and understand written material, on our ability to extract mathematical relationships, and on our knowledge of basic facts. None of these skills are specific to the development of computer programs; the knowledge we exploit is specific to the domain of information with which we are working. The remainder of the book will show what and how much computing can contribute to this most complicated step.

<#1268#>Domain Knowledge<#1268#>:\ Formulating the body of a program often requires knowledge about the area, also known as domain, from which the problem is drawn. This form of knowledge is called <#60462#><#1269#>DOMAIN KNOWLEDGE<#1269#><#60462#>. It may have to be drawn from simple mathematics, such as arithmetic, from complex mathematics, such as differential equations, or from non-mathematical disciplines: music, biology, civil engineering, art, and so on. Because programmers cannot know all of the application domains of computing, they must be prepared to understand the language of a variety of application areas so that they can discuss problems with domain experts. The language is often that of mathematics, but in some cases, the programmers must invent a language, especially a data language for the application area. For that reason, it is imperative that programmers have a solid understanding of the full possibilities of computer languages.~<#60463#><#60463#>