Skip to main content
Free AI courses. Free certificates of completion.Learn how
Interactive AI Lesson 13 min

Own the Problem Before Asking AI

Turn a request into an explicit contract, independent examples, and a plan you can explain.

Why this matters

An assistant produces a working feature before you have decided what the feature should do. You accept it, the demonstration looks convincing, and the ticket moves forward. A week later somebody asks why a large job was skipped, whether equal priorities have a stable order, or what happens when an estimate is invalid. You can find the function, but you cannot defend its decisions. The problem is not simply forgotten punctuation. You have lost contact with the reasoning that connects a request to its implementation.

This course teaches a practical way to keep that connection while using AI. You will build a small work-queue planner, ask for assistance at specific points, and check both the program and your understanding. The project is a local learning exercise, not a production scheduling service. Its deliberately limited scope makes every decision inspectable.

You do not need to memorize an entire language or avoid documentation. You do need enough independent fluency to explain a plan, write its central logic, recognize an incorrect result, and investigate a failure when an assistant is unavailable.

The idea

Treat a programming task as two outcomes: a change in the software and a change in your ability to work on it. They overlap, but they are not interchangeable. A generated function can satisfy an example while leaving you unable to adapt it. Conversely, struggling with a carefully chosen small problem can reveal exactly which concept you need to learn. Track both outcomes rather than assuming a successful demonstration measures understanding.

Before opening a chat, write a short problem contract. Name the inputs, the output, the rules, and the failure behavior. Separate facts supplied by the request from assumptions you are introducing. A request to prioritize work does not tell you whether priority means urgency, revenue, shortest duration, or dependency order. Those are product decisions. An assistant can suggest alternatives; it cannot determine which decision your stakeholder intended without evidence.

Next, decompose the task into operations you can describe without language syntax. Our planner validates records, orders them, scans the ordered sequence, selects jobs that fit, and returns their identifiers. Each verb becomes a question: what counts as valid, which order is deterministic, and what does fitting mean? This is the part to attempt yourself. Typing a loop becomes easier when the state transitions are already clear.

Use a graduated assistance rule. Start with your own example and attempt. If blocked, ask for a question or a hint. If the obstacle is a language feature, look up the precise feature and write a tiny experiment. If you need an implementation suggestion, request the smallest relevant function. Then close the suggestion and reconstruct the decision in your own words. The purpose is to choose assistance that removes the obstacle while leaving you responsible for the reasoning.

Research gives a reason for care, not a universal verdict about every AI tool. Shen and Tamkin's January 2026 study involved 52 developers learning an unfamiliar Python library. The AI group performed worse on an immediate comprehension quiz on average. The authors explicitly note that the study does not establish long-term effects, and their observations about different interaction patterns are not causal proof that one prompting style guarantees better learning. Our practice loop is a course exercise to evaluate for yourself, not a promise that it prevents skill loss.

Keep a simple record: what you predicted, what you tried, what assistance you used, and what you can now reproduce unaided. This is more useful than counting prompts. A short request can outsource the entire problem; a long discussion can help you understand one difficult assumption.

Diagram

Establish the contract and independent examples before requesting focused assistance. Verification reconnects the proposed change to your reasoning.1. Clarify the goal: separate assumptions. 2. Write the contract: inputs + rules + errors. 3. Trace examples: derive expected output. 4. Attempt a plan: own the core reasoning. 5. Request a hint: target the actual gap. 6. Verify and explain: keep the evidenceClarify the goalseparate assumptionsWrite the contractinputs + rules + errorsTrace examplesderive expected outputAttempt a planown the core reasoningRequest a hinttarget the actual gapVerify and explainkeep the evidence
Figure 1. Establish the contract and independent examples before requesting focused assistance. Verification reconnects the proposed change to your reasoning. 1. Clarify the goal: separate assumptions. 2. Write the contract: inputs + rules + errors. 3. Trace examples: derive expected output. 4. Attempt a plan: own the core reasoning. 5. Request a hint: target the actual gap. 6. Verify and explain: keep the evidence

Worked example

Imagine a team with seven available effort units for today's queue. Every task has an identifier, a priority from one to three, and a positive integer estimate. Higher priority runs first. Equal priorities are ordered by identifier in ascending order. Estimates are indivisible: a job either fits completely or is skipped. A skipped job does not stop the scan. The planner returns selected identifiers in selection order and must not modify the input.

Write this fixture on paper before coding:

IDPriorityEstimate
A35
B33
C22
D11

The ordered queue is A, B, C, D. Start with seven remaining units. Select A, leaving two. B needs three, so skip it and keep two. Select C, leaving zero. D no longer fits. The result is A followed by C. Notice that skipping B is not an error: it follows the agreed rule. Returning B, C, D might use six units and complete more jobs, but it would violate the priority-first selection policy by omitting A.

Now change the question: does the algorithm maximize completed jobs or total effort used? No. This greedy policy commits to earlier eligible tasks without exploring all subsets. That limitation belongs in the contract. Asking an assistant to optimize the function without specifying the objective can silently replace the intended policy with a different scheduling problem.

List boundaries. With capacity zero, the result is empty, but malformed records must still be rejected. With capacity five, A fits exactly. With capacity four, A is skipped, B is selected, C is skipped, and D is selected, producing B and D. An empty queue produces an empty result. Duplicate identifiers are rejected because the output would otherwise become ambiguous.

Choose validation behavior before implementation. For this course, capacity must be an integer greater than or equal to zero; estimates must be positive integers; priority must be one, two, or three; identifiers must be nonempty strings with no surrounding whitespace. Booleans are rejected for numeric fields even though Python permits some integer-like behavior for them. Missing required fields and invalid records raise ValueError. Extra fields are permitted and ignored. The input is a list of dictionaries.

Finally, write pseudocode: validate everything; make a new ordered list; initialize remaining capacity and an empty result; visit each record once; append its ID and subtract its estimate only if it fits; return the result. You can now ask AI to challenge your boundary cases without asking it to invent the policy. A useful prompt is: “Here is my contract and four worked examples. Identify an ambiguity or missing boundary. Do not write the implementation.”

Code

Save this as first_attempt.py and run python first_attempt.py. This small version assumes already-valid records; later lessons add the full validation contract. Predict both assertions before executing it.

def choose_valid_tasks(tasks, capacity):
    ordered = sorted(tasks, key=lambda task: (-task["priority"], task["id"]))
    remaining = capacity
    selected = []
    for task in ordered:
        if task["estimate"] <= remaining:
            selected.append(task["id"])
            remaining -= task["estimate"]
    return selected

jobs = [
    {"id": "A", "priority": 3, "estimate": 5},
    {"id": "B", "priority": 3, "estimate": 3},
    {"id": "C", "priority": 2, "estimate": 2},
    {"id": "D", "priority": 1, "estimate": 1},
]
assert choose_valid_tasks(jobs, 7) == ["A", "C"]
assert choose_valid_tasks(jobs, 4) == ["B", "D"]
print("Both hand-derived examples passed.")

The negative priority makes an ascending sort place higher priorities first. The second key settles ties. Explain both parts before accepting a more compact alternative.

Common mistakes

Treating a fluent plan as an agreed requirement. This is tempting because a detailed answer feels like progress. In practice, an unstated optimization objective can change the feature before any code is written. Separate stakeholder rules from proposed assumptions, and settle the important assumptions with examples.

Measuring learning by successful execution. It is satisfying to see a green result after pasting a function. That result checks one execution, not your ability to predict a new case. Follow the run with a changed input and a short explanation of the state after each iteration. If you cannot explain the output without rerunning it, revisit the reasoning.

Refusing all help until frustration becomes exhaustion. Independent thinking does not mean unlimited unproductive struggle. Set a small attempt window, identify the exact obstacle, and request the narrowest useful help. A question about how a tuple sort key works preserves more practice than delegating the entire feature because one expression is unfamiliar.

Assuming the greedy rule is a universal scheduler. Its simple code makes it attractive beyond the exercise. Actual queues may have dependencies, deadlines, interruption costs, fairness requirements, and concurrency. Our policy intentionally omits those concerns. Understanding where a simple algorithm stops being suitable is part of engineering judgment.

Your turn

Work without an assistant for your first attempt. Create five tasks with two tied priorities and one estimate larger than the total capacity. Write expected results for capacities zero, four, and seven. Include a trace with one row per visited task: remaining capacity before the decision, selected or skipped, and remaining capacity afterward.

Then ask AI only to search for ambiguity in your contract. Keep a record of one suggestion you accepted or rejected and why. Do not change your expected result merely because the assistant disagrees; trace the rule and resolve the disagreement with evidence.

Your success criterion is specific: your implementation matches all three hand-derived outputs, your trace explains a skipped task followed by a selected task, and you can state one objective that this algorithm does not optimize. Close your code and rewrite the pseudocode from memory. If a step is missing, add it to a short practice list for the next session. This exercise is self-directed; the site does not review your trace.

Recap

  • A usable problem contract specifies failure behavior as well as successful output.
  • Independent examples provide a basis for checking an assistant's proposed implementation.
  • A skipped oversized task must not terminate this project's queue scan.
  • This priority-first greedy policy does not guarantee the maximum number of completed jobs.
  • Narrow assistance can resolve a blocker while leaving the core decision with the engineer.

Sources

Knowledge Checkpoint

A request says to prioritize work but does not define the optimization objective. What should you do first?

Read to the end of the lesson