Impact of Program Design · 程序设计的影响
| English | 中文 | Pinyin · 拼音 |
|---|---|---|
| modular/ˈmɒdjʊlə/ | 模块化 | mó kuài huà |
Two neat designs can report different averages
- A fictional record contains scores 80, absent and 100. Treating absence as zero gives
(80 + 0 + 100) / 3 = 60; omitting the absent result gives(80 + 100) / 2 = 90. - Separate methods can calculate either result correctly. Organization does not choose the reporting policy: establish what absence means, who decides, and which denominator the report must show before using the result.
Scores are 80, absent and 100. Under the available-score policy, what is the average?
The sum of present scores is 180 and the number present is 2, so 180/2 = 90.
Turn a requirement into a contract
- Specify whether absence means an unattempted assessed task, a task not assigned, or data not yet entered. These cases need not share a rule; the fictional example demonstrates consequences and does not prescribe a school grading policy.
- State the accepted input, the treatment of missing values and the result. If the rule is “average available scores”, an all-missing record has no average; report that case explicitly instead of inventing zero or dividing by zero.
Separate responsibilities for checking
- A modular 模块化 design separates
readScores,averageAvailableandprintReport. The average method can be checked with known values without reading a file or capturing formatted output. - Separation helps when interfaces remain clear. A change to the meaning of absence can still require changes in calculation, reporting and checks; small methods and good names alone do not prevent those dependencies.
Check ordinary and boundary cases
- For the available-score policy, check [80, absent, 100] gives 90, a single 80 gives 80, and [absent, absent] produces the agreed “no result” outcome. Do not merely check that the program runs.
- The calculation below uses
nullfor missing values. It returns a double average and rejects the all-missing case. It assumes a non-null array of ordinary scores; input validation and reporting are separate responsibilities.
public class AverageAvailable {
public static double averageAvailable(Integer[] scores) {
double total = 0;
int present = 0;
for (Integer score : scores) {
if (score != null) {
total += score;
present++;
}
}
if (present == 0) {
throw new IllegalArgumentException("No available scores");
}
return total / present;
}
}
A modular design (independent, well-named pieces) is mainly easier to...
Modularity makes changes safer and pieces reusable.
When several callers reuse one method, correcting that method can benefit all callers without editing duplicated copies.
True: callers reuse the implementation. Its contract and the effects of the change still need review.
Bias in a program's data or logic can produce unfair results at scale.
Design choices affect real people — consider who is impacted.
For checking the average calculation independently of input and printed output, which design best isolates that responsibility?
Separating the calculation from input and output allows known-score checks without those other operations. Merely having small methods does not guarantee correctness.
Program design is purely cosmetic and doesn't affect how safely code can change.
Design decides how safely a program can be modified.
The shown averageAvailable method returns zero for an all-missing array.
False: it rejects that case with IllegalArgumentException because no available scores define an average.
Report consequences to affected users
- A report of 90 should state that it averages two available scores out of three records, with one absent result omitted. Reporting only 90 hides information a reader needs to compare outcomes.
- Review who may be affected by the data and policy. A consistent calculation may still treat different kinds of absence inappropriately; test the agreed requirements and make the outcome understandable to users.
Modularity makes a policy easier to inspect and test; it does not make that policy fair or appropriate. The averages 60 and 90 use different denominators. Choose and disclose the rule rather than silently selecting whichever result looks better.
Good or poor design? · 好设计还是差设计?
Design choices have real consequences. Sort each outcome.
Carry a policy change across the design
- If the authorized requirement changes to count an unattempted task as zero, update the denominator, relevant examples, checks and report wording. Reusing a method is useful only when its contract matches the new task.
- Review testability, correctness and user understanding separately. Clear boundaries reduce some change risks, but callers and shared assumptions must still be checked when a method's contract changes.
Program design affects maintainability and people. Separate responsibilities so behavior can be checked, define the missing-data policy, test its boundary cases and disclose the denominator. Correct arithmetic and neat structure do not establish an appropriate policy by themselves.
Match the change to the issue it addresses.
A modular structure enables checking but cannot choose the right policy by itself.