انتقل إلى المحتوى
أمين أبوزيد
منشورBEG-016-L06

عرض عملي: التخطيط قبل الكود على مشكلة جديدة

  • الدرس 6 من 6
  • 11 دقيقة قراءة
  • مبتدئ
في هذا الدرس 11 موضوعات

هذا الدرس متاح حاليًا باللغة الإنجليزية فقط، ولم تُنشر نسخته العربية بعد.

Lesson Overview

You have learned the four parts of the routine one at a time: understanding a problem, decomposing it, writing pseudocode, tracing by hand, and listing edge cases. In this lesson you do them together on a problem you have not seen before, from the first read to the final check.

Follow along on paper, and try each step yourself before reading how it is done. The map analogy applies one last time: plan the whole route, check the risky roads, and only then start the engine.

Why this matters: this is the routine for the lab and the assessment, and for a ticket at work. The plan is graded as much as the code, because a clear plan is evidence of clear thinking.

The previous lesson, "Thinking in edge cases", gave you the checklist.

Learning Objectives

By the end of this lesson you will be able to:

  • Apply the full routine (restate, plan, edge cases, trace, code, check) to an unseen problem.
  • Write a plan that matches the code, line by line.
  • Use the edge-case list to find a bug before a user does.
  • Decide, record, and test a decision about unusual input.
  • Check that every listed edge case is handled by the finished code.

Written Explanation

The routine

Use these steps, in order, on every unseen problem.

  1. Read and restate. Say the problem in your own words and list inputs, outputs, and constraints. Ask your questions and record assumptions.
  2. Plan. Decompose it and write pseudocode (or a flowchart).
  3. List edge cases with the expected result for each, using the checklist.
  4. Trace. Run one example through the plan with a variable table.
  5. Code. Only now write the Java, line by line from the plan.
  6. Check. Run every line of the edge-case list. Make sure the plan and the code still match.

If a later step reveals a flaw, go back and fix the plan, then the code. The demo below shows this.

Examples

The three examples in this lesson are three stages of one demo.

Example 1: read, restate, plan, list the edge cases (simple)

The problem: "Count how many words in a sentence are longer than 4 letters."

Step 1: restate. Given a sentence, count the words that have more than four letters. Inputs, outputs, and constraints:

text
Problem (my words):   Count the words of a text that have more than 4 letters.
Input:                String text
Output:               int count
Constraints:          What separates words? What is a "letter"? Empty text?
Questions/decisions:  Words are separated by one or more spaces.
                      Length 5 or more counts (more than 4).
                      Punctuation is not a letter (decision pending, see edge cases).
                      Empty text or only spaces -> 0.
Example by hand:      "plan before you write code" -> before (6), write (5) -> 2

Step 2: plan. Decomposition:

text
1. Cut the text into words.
2. Start a counter at 0.
3. For each word, if it has more than 4 letters, add 1.
4. Return the counter.

Pseudocode:

text
SET words = the words of text
SET count = 0
FOR EACH word IN words
    IF length of word > 4
        SET count = count + 1
RETURN count

Step 3: edge cases. Using the checklist:

InputExpectedWhy
plan before you write code2Happy path
empty text0Empty
only spaces0Empty after trimming
hello brave world 3Extra spaces at the ends and between words
hello1One word
four fives1Exactly 4 letters (not counted) and exactly 5 (counted): the boundary
Hi, there!1Punctuation
Wait four! Great, stuff2Punctuation on words at the boundary

The last two rows are the interesting ones. The last expects 2: Great and stuff have five letters each, while four! has four letters but five characters.

Example 2: trace, code, and find the bug (practical)

Step 4: trace. Trace the plan on the hand example plan before you write code:

stepwordlength> 4?count
start---0
1plan4false0
2before6true1
3you3false1
4write5true2
5code4false2

The plan gives 2, as expected, and a word of length exactly 4 is not counted.

Step 5: code the first idea. Translating the plan directly gives:

java
static int countLongWordsV1(String text) {
    String[] words = text.split(" ");
    int count = 0;
    for (String w : words) {
        if (w.length() > 4) count++;
    }
    return count;
}

Step 6: run the list. Running version 1 over the inputs gave this:

InputExpectedVersion 1
plan before you write code22
hello brave world 33
Wait four! Great, stuff23

Two surprises. First, the extra spaces did not cause a wrong answer. With split(" "), extra spaces produce empty pieces, but an empty piece has length 0, which is never above 4, so the count is unaffected. Before you "fix" something, check what it really does. (If the problem had been "count the words", the empty pieces would have broken it: " hello brave world " gives 8 pieces with split(" ") but 3 real words.)

Second, the last row is wrong: version 1 returned 3 instead of 2. The word four! has four letters but five characters, so counting length counts the punctuation. The edge-case list found this before any user did; a happy-path test would have passed.

Example 3: fix the plan, then the code, then check (realistic)

Go back to the plan, because the plan said "length of word", and length is not what we mean. We need a decision and a plan change.

Decision (recorded): a word's size is the number of letters in it; digits, punctuation, and other symbols do not count.

Updated pseudocode:

text
SET words = the words of trimmed text, split on runs of spaces
SET count = 0
FOR EACH word IN words
    IF the number of letters in word > 4
        SET count = count + 1
RETURN count

That adds a small step, "count the letters of a word", which we make its own method. To find out whether a character is a letter we use Character.isLetter, a library method that this course has not covered yet, so treat it as a preview: it takes one char and answers true or false. For splitting, we also use trim() and split("\\s+"). The pattern \\s+ is a regular expression meaning "one or more whitespace characters", another preview topic: for now, read it as "split on any run of spaces". Trimming first matters because a text that starts with spaces would otherwise give an empty first piece.

java
static int lettersIn(String w) {
    int n = 0;
    for (int i = 0; i < w.length(); i++) {
        if (Character.isLetter(w.charAt(i))) n++;
    }
    return n;
}

static int countLongWords(String text) {
    String[] words = text.trim().split("\\s+");
    int count = 0;
    for (String w : words) {
        if (lettersIn(w) > 4) count++;
    }
    return count;
}

Run the whole list again. Real results:

InputExpectedResult
Wait four! Great, stuff22
empty text00
only spaces00
Hi, there!11

I also ran the other rows of the list on this version and they match their expected column (for example hello gives 1 and four fives gives 1). The plan and code now match line for line: SET words is the trim and split line, the loop is the loop, number of letters in word is lettersIn, and the counter is count.

One more detail the list made us look at: for empty text, "".trim().split("\\s+") gives an array holding one empty string, not an empty array, so the loop runs once with a zero-letter word and the count stays 0. (For a problem that counts words, empty text would wrongly give 1 and need an if.)

Backend Insight

A ticket arrives ("count how many items in an order are expensive"). You restate it and ask the questions (what is expensive? is the limit included?), write a short plan, agree on edge cases such as an empty order, and only then code and run the cases. Reviewers read the plan and edge cases first, because they show quickly whether you understood the task.

Notice how the bug was found: not by clever debugging, but by a list written before the code.

Common Mistakes

Mistake 1: Coding from the first idea

  • Incorrect: typing split(" ") and a loop as soon as the problem is read.
  • Correct: restating, planning, listing edge cases, and tracing first.

The demo's first version was a reasonable first idea. It still hid a bug that only the list could find.

Mistake 2: "Fixing" a problem you have not confirmed

Spaces looked tricky, but here they were not the failing case. Check what the code does before changing it.

Mistake 3: Fixing only the code

When the list reveals a flaw, update the plan too. If the plan still says "length of word" while the code counts letters, they no longer match, and the next reader is misled.

After any change, rerun the whole list: a fix can break a row that passed before.

Exercises

Try each exercise yourself before opening the solutions. Do the full routine where an exercise asks for it.

Level A: Foundation

A1. List the six steps of the routine in order.

أظهر الحل A1

A1. Read and restate; plan (decompose, pseudocode or flowchart); list edge cases; trace an example; code; check the whole list and that the plan matches the code.

A2. Restate "count the words in a text" with input, output, and constraints.

أظهر الحل A2

A2. Problem: given a text, say how many words it has. Input: a String. Output: an int. Constraints: what separates words (one or more spaces?), is punctuation part of a word, and what is the answer for empty text (0)?

A3. List at least four edge cases for "count the words in a text", with expected results.

أظهر الحل A3

A3. Empty text gives 0; only spaces gives 0; one word gives 1; "one two" gives 2; "one two" (extra spaces) gives 2; " one " gives 1. (A plain split on empty text gives one piece, so empty text needs a special check.)

Level B: Application

B1. Run the routine for "is an int array a palindrome (reads the same forwards and backwards)?". Give the restatement, pseudocode, and an edge-case list of at least five rows, then write and run the Java method.

أظهر الحل B1

B1.

text
Problem (my words):   Does the array read the same from both ends?
Input:                int[] a
Output:               boolean
Constraints:          Empty array? (decision: yes, a palindrome)
text
FOR i FROM 0 UP TO (length / 2) - 1
    IF a[i] differs from a[length - 1 - i]
        RETURN false
RETURN true

Edge cases: {} true; {7} true; {4, 4} true; {1, 2, 1} true (middle element is not compared); {1, 2, 3, 1} false. Java:

java
static boolean isPalin(int[] a) {
    for (int i = 0; i < a.length / 2; i++) {
        if (a[i] != a[a.length - 1 - i]) return false;
    }
    return true;
}

Running the five cases in the order above printed true true true false true for {}, {7}, {1,2,1}, {1,2,3,1}, {4,4}, matching the expectations.

B2. Trace the final countLongWords on " a bigger test ": give the pieces after trim() and split("\\s+"), then the count.

أظهر الحل B2

B2. After trim() the text is "a bigger test"; split("\\s+") gives a, bigger, test.

a has 1 letter (count stays 0), bigger has 6 (count 1), test has 4 (count stays 1). The result is 1, which the program also printed.

B3. A plan says "IF the word has more than 4 letters, add 1". The code says if (lettersIn(w) >= 4) count++;. Which edge-case row would reveal the difference, and what would the code return for it?

أظهر الحل B3

B3. The row four fives (exactly 4 letters and exactly 5 letters). The plan says 4 letters is not counted, but >= 4 counts it, so the code returns 2 instead of the expected 1. The boundary row exposes it.

Level C: Challenge

C1. Run the full routine for "return the length of the longest run of equal neighbouring values in an int array" (for {1, 1, 2, 2, 2, 3} the answer is 3). Decide what happens for an empty array. Include a trace, an edge-case list of at least five rows, the Java method, and the results of running your list.

أظهر الحل C1

C1. Restatement: input int[], output the length of the longest block of equal neighbours; decision: an empty array gives 0.

text
IF array is empty RETURN 0
SET best = 1, run = 1
FOR i FROM 1 TO length - 1
    IF a[i] equals a[i - 1]
        SET run = run + 1
    ELSE
        SET run = 1
    IF run > best
        SET best = run
RETURN best

Trace on {1, 1, 2, 2, 2, 3}: run goes 1, 2, 1, 2, 3, 1 and best ends at 3. Edge cases: {} 0, {5} 1, {1, 1, 2, 2, 2, 3} 3, {2, 2, 2} 3 (the whole array), {1, 2, 3} 1 (no repeats). Java:

java
static int longestRun(int[] a) {
    if (a.length == 0) return 0;
    int best = 1, run = 1;
    for (int i = 1; i < a.length; i++) {
        if (a[i] == a[i - 1]) run++; else run = 1;
        if (run > best) best = run;
    }
    return best;
}

Running the five cases in that order printed 0 1 3 3 1, matching. The run that ends at the last element is counted because best is updated inside the loop on every pass.

Mini Challenge

Solve this unseen problem with the full routine and hand in the plan with the code: "Given a text, count how many words start with a capital letter."

  1. Restate it, with inputs, outputs, constraints, and your decisions (is a word that starts with a digit counted? what about punctuation at the front?).
  2. Write the pseudocode.
  3. Write an edge-case list of at least eight rows with expected results.
  4. Trace one example with a variable table.
  5. Write the Java and run every row. If a row fails, say whether the plan or the code was wrong, and fix both.

Check your work: plan, list, and trace came before the code; every row was run; plan and code match. (Hint: Character.isUpperCase, a preview method, tests one character.)

Summary & Next Lesson

Key takeaways

  • The routine is: read and restate, plan, list edge cases, trace, code, check.
  • The edge-case list is what finds bugs the happy path hides. Write it before the code.
  • Check what the code actually does before "fixing" a suspicion.
  • When a flaw appears, update the plan first and the code second. Rerun the whole list after any change.
  • The plan and the code must match, and the plan is graded as much as the code.

Next lesson

This was the last lesson of the module. The module's lab, "Plan before code", has you apply the routine to three unseen problems and submit the plan with the code. The next module, BEG-017, opens with "What an algorithm is".

Self-check

  1. In what order do the six steps of the routine come?
  2. In the demo, which step found the real bug?
  3. Why did the extra spaces not break the long-word count?
  4. What should you do when the edge-case list shows a flaw in your plan?
  5. Why run the whole list again after a fix?
أظهر الإجابات
  1. Restate, plan, edge cases, trace, code, check.
  2. Running the edge-case list (the row with punctuation), which was written before the code.
  3. Extra spaces create empty pieces, which have length 0 and are never longer than 4, so they did not change the count.
  4. Fix the plan first, then the code, so that they still match.
  5. A fix can break a row that passed before.

References

  • Oracle, Java SE 21 API: String. Supports trim() (removes leading and trailing characters up to the space character) and split (a positive-width match at the start of the text gives an empty leading piece, which is why we trim first).
  • Oracle, Java SE 21 API: Character. Supports isLetter(char), which answers whether a character is a letter. isUpperCase in the Mini Challenge hint was not checked against the page.
  • The Java methods in this lesson were compiled and run with JDK 21; the quoted results are from those runs. The explanation of \\s+ as "one or more whitespace characters" is standard regular-expression meaning that I did not verify against a primary source here; it is flagged in the text as a preview topic.

التطبيق

طبّق هذا الدرس بمختبر الوحدة وتمارينها واختبارها.

المختبر والتمارين الاختبار

تعليم الدرس كمكتمل اختياري ويمكنك التراجع عنه في أي وقت. يبقى تقدمك محفوظًا في هذا المتصفح.

اكتب للبحث في المستويات والمراحل والوحدات والدروس.