Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Don't Prompt Harder, Structure Better

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest. →

Don't Prompt Harder, Structure Better

Avatar for Yusuke Kita

Yusuke Kita

April 14, 2026

More Decks by Yusuke Kita

Other Decks in Programming

Transcript

  1. What LLM generates without context Prompt: "Write a login test

    for our iOS driver app" func testLogin() { let app = XCUIApplication() app.textFields["username"].tap() // No such identifier app.textFields["username"].typeText("test") app.buttons["Log in"].tap() // Actually "Sign in" app.staticTexts["Welcome"].tap() // No wait — not loaded yet } 4
  2. Three Failure Modes Mode Problem 1 Hallucinated selectors IDs that

    don't exist 2 Wrong text "Log in" but actually "Sign in" 3 No wait strategy Race conditions 5
  3. How do we give LLM enough context? Not by writing

    better prompts — by structuring the context it receives. 6
  4. Three Layers of Structured Context Layer Role Provides IR (Intermediate

    Representation) "What to test" Spec intent, machine-readable Scenarios + Definitions "What exists" Step order, selectors, timeouts Templates "How to write" Code patterns, conventions Pipeline: PRD/Figma → IR → Code 8
  5. IR — "What to test" ir: name: Driver Login preconditions:

    - Operator account exists input_fields: - { name: operator_name, type: select } - { name: password, type: password } - { name: branch_office, type: select } - { name: radio_number, type: text } - { name: driver_number, type: text } IR captures intent separately from implementation → prevents hallucination. 9
  6. Scenarios — "What steps in what order" name: ride-complete parameters:

    passengerName: { type: string, default: "anonymous" } paymentAmount: { type: number, default: 50 } variants: anonymous: {} designated: { driverNumber: "${DRIVER_NUMBER}" } steps: - performFullLogin - acceptRideRequest - completeRideJourney: { passengerName: "${passengerName}" } - enterPaymentAmount: { amount: "${paymentAmount}" } - confirmPayment - endWorkDay Fixed steps → no hallucinated flows. Variants → multiple tests. 10
  7. Definitions — "What exists" ios: helpers: performFullLogin: signature: "(app: XCUIApplication)

    -> Void" acceptRideRequest: signature: "(app: XCUIApplication) -> Void" completeRideJourney: signature: "(app, passengerName: String?) -> Void" timeouts: login_process: 30 accessibility_ids: button_login: "button-login" button_confirm: "button-confirm" LLM gets: real selectors, reusable helpers, proven timeouts — no guessing. 11
  8. Templates — "How to write" final class RideUITests: XCTestCase {

    func testAcceptAndCompleteRide() throws { performFullLogin(app: app) acceptRideRequest(app: app) completeRideJourney(app: app, passengerName: "anonymous") } } // Selector priority: accessibilityIdentifier > label > predicate app.buttons["button-login"].tap() app.staticTexts["Enter driver number"].waitForExistence(timeout: 30) // Wait: waitForExistence for UI, sleep only for backend (with reason) // reason: "Backend processes state change" Thread.sleep(forTimeInterval: 5) 12
  9. How it works in practice Step What Action 1 Scenario

    YAML Define WHAT to test 2 Definitions Define WHAT exists (helpers, selectors) 3 Templates Define HOW to write (patterns) 4 Test Cases Compose into tests AI follows this chain every time. 14
  10. Same prompt, different context Prompt: "Write a ride completion test"

    Without context → LLM guesses everything app.buttons["login"].tap() // wrong ID sleep(3) // arbitrary wait app.staticTexts["Welcome"].exists // wrong text With IR + Scenarios + Definitions + Templates → LLM uses real values performFullLogin(app: app) // from scenarios app.buttons["button-login"].tap() // from definitions app.staticTexts["Enter driver number"] .waitForExistence(timeout: 30) // from definitions // reason: "Backend processes state change" Thread.sleep(forTimeInterval: 5) // from templates 15
  11. The Formula Reliable AI-generated test code = IR (what to

    test) + Scenarios (what steps) + Definitions (what exists) + Templates (how to write) 17
  12. Three Things to Take Home 1. Structure > Prompts Give

    LLM selectors, definitions, patterns — not just instructions. 2. Single Source of Truth Update once → all tests benefit. Humans and AI read the same source. 3. Context Prevents Hallucination AI knows what to test, what exists, and how to write → no guessing. 18
  13. One More Thing Don't build for AI. Build for your

    team. The context that helps your team write consistent code — is the same context AI needs. 19
  14. Why it works for your team Reviewable — review context

    before any code is generated Single source of truth — update one file, all tests stay consistent Onboarding — new members read structured files, not ask around 20