Someone needs to know the plan (and that someone isn't just me anymore)

John RobinsJohn Robins
13 min read

I’ve been working on some software with my VS Code copilot, and we have been embarking on some pretty ambitious stuff. Stuff I wouldn’t try on my own, to be honest. Like implementing complex internal API frameworks to create an extensible system for end users. Or creating thread-safe asynchronous processing. Or a full refactor of 14,000 lines of nightmarish spaghetti code (a product of my early work using a code-copilot).

These are not trivial undertakings. My software skills are a little rusty, and establishing asynchronous processing looks very different on 2025 python compared to the last time I had to implement in 2004 using .NET.

Ambitions meet reality

I’ll admit .. some of it didn’t go great. It turns out that the best way to ruin a thread-safe asynch implementation is to try to implement thread pooling in a misguided effort to optimize the memory use of the application. I wouldn’t recommend that path.

But even those things that didn’t go great taught me some important lessons in how to write better software using code copilots.

The importance of a plan

And that brings me to my thesis. Someone has to know the plan. For much of my coding, that someone is me. I know what I want, how I want it architected, and how to judge whether the code meets my standards or not.

But that doesn’t mean I’m bound to only code what I know. I developed a workflow that extends my limited software engineering knowledge to unbelievable scales. And honestly, I think it will do the same for you.

Gory technical details follow

We have three different problems to solve: planning, development, and testing. This is standard software development stuff. You start with the functional requirements that you want to see, then sit down with the team and plan how you are going to develop your code to satisfy the requirements.

Then you build something. And break it. And rebuild it. And swear and drink coffee and rebuild it again.

And then you test it and the dev cycle is done … off to ops.

The Product Owner Workflow

I’m an AI product owner in my day job, so this is my life. I talk to users to hear their non-technical statement of needs, and try my best to turn it into a workable development plan. Let’s explore how to implement a product owner workflow with your llm:

First identify the feature set you want to develop. This is not your tactical functional requirements, this is you as the end user expressing what you want the agent to build for you in plain non-technical terms.

Next, issue the first prompt in your workflow: “Consult professionally credible best practice in [describe the type of software you are building here] and develop a detailed functional requirements list that would be found in best in class software to deliver the following features: [your features here]. Deliver the FR’s in a bulleted list.” For example:

Consult professionally credible best practice in children's educational software developed in react and develop a detailed functional requirements list that would be found in best in class software to deliver the following features: a dyslexia UX mode to support young readers with dyslexia. Deliver the FRs as a bulleted list.

Here is the output I get from Google Gemini 2.5 Pro:

<AI_output>

Of course. Here is a detailed functional requirements list for a best-in-class dyslexia UX mode in children's educational software, based on professionally credible accessibility and UX best practices.


Functional Requirements: Dyslexia UX Mode

This document outlines the functional requirements for a "Dyslexia Mode," an accessibility feature designed to support young readers with dyslexia by providing a customizable and highly readable user experience.


1.0 Mode Activation and Persistence

  • FR-1.1: The system shall provide a clearly visible and easily accessible control (e.g., a toggle switch or button with an icon and label) within a main settings or accessibility menu to enable and disable "Dyslexia Mode."

  • FR-1.2: Once activated or deactivated, the state of the Dyslexia Mode shall persist across all user sessions for that user's profile until manually changed. This state can be managed using browser local storage or user account settings.

  • FR-1.3: Upon activation, all settings specified below shall be applied globally across all relevant text-based components of the application.


2.0 Typography Customization

  • FR-2.1 Font Family: The system shall allow the user to select from a curated list of at least three dyslexia-friendly sans-serif fonts. The default font upon mode activation shall be a widely supported sans-serif font (e.g., Arial).

    • Recommended font options: OpenDyslexic, Arial, Verdana.
  • FR-2.2 Font Size: The user must be able to adjust the global font size of all core content using a simple control like a slider or stepper. The control must provide at least five distinct size settings.

  • FR-2.3 Character Spacing: The user must be able to select from at least three levels of character spacing (tracking) to increase the distance between letters (e.g., Normal, Wide, Widest).

  • FR-2.4 Line Spacing: The user must be able to adjust the space between lines of text (leading). The system shall default to a minimum of 1.5 times the font size and allow the user to increase it.

  • FR-2.5 Word Spacing: The system shall provide at least three options to increase the spacing between words.


3.0 Color and Contrast Settings

  • FR-3.1 Pre-defined Themes: The system shall provide a minimum of four pre-defined, high-contrast color themes designed to reduce visual stress. These themes must avoid pure white (#FFFFFF) backgrounds.

    • Example themes: Black text on an off-white/cream background; Black text on a light-blue background; Dark grey text on a pastel yellow background; High-contrast dark mode (e.g., light-yellow text on a dark grey background).
  • FR-3.2 Theme Application: When a theme is selected, the color combination for text and background shall be applied consistently to all readable content, buttons, and interface elements.


4.0 Layout and Content Presentation

  • FR-4.1 Text Alignment: The system shall automatically render all paragraphs and multi-line text blocks as left-aligned. Justified text alignment must be disabled in this mode.

  • FR-4.2 Line Length: The system shall format text blocks to have a maximum line length of 65-75 characters to facilitate easier tracking between lines.

  • FR-4.3 Distraction Reduction: When Dyslexia Mode is active, the system shall automatically hide or significantly reduce non-essential visual elements, such as decorative animations, complex background patterns, and purely cosmetic images.


5.0 Text-to-Speech (TTS) and Reading Aids

  • FR-5.1 Read Aloud Functionality: The system must provide a "read aloud" button for all primary educational content and instructions.

  • FR-5.2 Real-time Highlighting: As the text-to-speech engine reads the text, the system must visually highlight the current word being spoken.

  • FR-5.3 Sentence Pacing: In addition to word highlighting, the system shall apply a secondary, less prominent highlight (e.g., a light background color) to the entire sentence currently being read.

  • FR-5.4 User Playback Controls: The user must have controls to play, pause, and stop the audio playback at any time.

  • FR-5.5 Speed and Voice Control: The user must be able to adjust the reading speed (e.g., 0.8x, 1.0x, 1.2x) and select from at least two different voices.


6.0 Interactive Focus Tools

  • FR-6.1 Digital Reading Ruler: The system shall provide a toggleable "reading ruler" tool. When activated, this tool shall mask the screen content except for a single horizontal strip that follows the user's mouse cursor or finger, helping to isolate the line being read.

  • FR-6.2 Picture Dictionary: The system must support an interactive dictionary where pre-selected vocabulary words can be clicked or tapped. Upon interaction, the system shall display a pop-up containing a simple definition and a representative image or icon.

</AI_output>

Wow. I wouldn’t have thought of ANY of that. Or I would have spent weeks researching it! So now we are starting to get a plan, but it’s not a plan yet. We need to transform our functional requirements into a full dev and test plan. Take a look at this JSON structure:

{
  "title": "Backlog Title",
  "version": "1.0",
  "overview": "",
    "goals": [
    "Goal 1",
    "Goal 2",
    "Goal n"
  ],
  "tasks": [
    {
      "id": 1,
      "title": "Task title",
      "description": "Task description",
      "files": [
        "in-scope file 1",
        "in-scope file n"
      ],
      "acceptance_criteria": [
        "acceptance criteria 1",
        "acceptance criteria n",
      ],
      "dependencies": [package_list],
      "status": "todo"
    },
    ...

This is a JSON representation of how I think about backlog management. It’s nothing revolutionary, but it’s a tight package that captures most of the ideas you’d find in a well managed Agile backlog.

💡
This JSON structure is a clean, practical template I co-developed with my LLM. It’s not a formal standard but is heavily influenced by Agile principles, capturing the essentials—tasks, acceptance criteria, dependencies—in a format that’s easy for both humans and AI to parse. It’s designed to be a perfect bridge between high-level requirements and actionable code.

Using this template, we issue our next prompt in the workflow: “Using best practice in professional [your app language] development, turn these functional requirements into a project development backlog using this JSON structure as a template: [insert JSON structure].”

Using best practice in professional JavaScript/React development, turn these functional requirements into a project development backlog using this JSON structure as a template:

{
"title": "Backlog Title",
"version": "1.0",
"overview": "",
"goals": [
"Goal 1",
"Goal 2",
"Goal n"
],
"tasks": [
{
"id": 1,
"title": "Task title",
"description": "Task description",
"files": [
"in-scope file 1",
"in-scope file n"
],
"acceptance_criteria": [
"acceptance criteria 1",
"acceptance criteria n",
],
"dependencies": [package_list],
"status": "todo"
},
...

From that I get this output (again on Gemini Pro 2.5):

<AI_output>

Certainly. Here are the functional requirements turned into a project development backlog, following professional best practices and formatted using your specified JSON structure.

This backlog breaks down the requirements into discrete, actionable tasks for a development team.

JSON

{
  "title": "Dyslexia UX Mode - Project Backlog",
  "version": "1.0",
  "overview": "This project involves developing a comprehensive 'Dyslexia Mode' for our children's educational software. This feature will provide a suite of user-configurable options to improve readability and reduce visual stress for young readers with dyslexia, based on established accessibility best practices.",
  "goals": [
    "Enhance the application's accessibility and inclusivity for users with dyslexia.",
    "Provide a customizable and comfortable reading experience through user-controlled settings.",
    "Integrate assistive technologies like text-to-speech to support different learning styles."
  ],
  "tasks": [
    {
      "id": 1,
      "title": "Develop Dyslexia Mode Toggle and State Management",
      "description": "Create the main toggle UI element in the settings panel to activate/deactivate Dyslexia Mode. Implement the logic to manage and persist the user's choice across sessions.",
      "files": [
        "src/components/Settings/AccessibilityPanel.js",
        "src/context/SettingsContext.js",
        "src/hooks/useLocalStorage.js",
        "src/App.js"
      ],
      "acceptance_criteria": [
        "A toggle switch for 'Dyslexia Mode' is present in the accessibility settings.",
        "Clicking the toggle activates a global state or CSS class (e.g., on the <body> tag).",
        "The on/off state of the toggle is saved to local storage and persists after the user refreshes the page or ends the session."
      ],
      "dependencies": [
        "react (useState, useContext)"
      ],
      "status": "todo"
    },
    {
      "id": 2,
      "title": "Implement Typography Customization Panel",
      "description": "Build the UI controls within the settings panel that allow users to adjust font family, font size, and spacing for characters, words, and lines. These settings should only be visible when Dyslexia Mode is active.",
      "files": [
        "src/components/Settings/TypographyControls.js",
        "src/context/SettingsContext.js",
        "src/styles/themes/dyslexia-mode.css"
      ],
      "acceptance_criteria": [
        "User can select from at least 3 dyslexia-friendly fonts.",
        "User can adjust font size using a slider or stepper.",
        "User can select from 3 predefined levels for character, word, and line spacing.",
        "Selected typography settings are applied globally to all educational text content.",
        "Changes are reflected on the screen in real-time as the user adjusts them."
      ],
      "dependencies": [
        "styled-components or CSS variables"
      ],
      "status": "todo"
    },
    {
      "id": 3,
      "title": "Implement Color Theme Selector",
      "description": "Develop a component that allows users to choose from several pre-defined, high-contrast color themes designed to reduce visual stress. This includes text and background color combinations.",
      "files": [
        "src/components/Settings/ThemeSelector.js",
        "src/context/SettingsContext.js",
        "src/styles/themes/dyslexia-mode.css"
      ],
      "acceptance_criteria": [
        "User can select from at least 4 pre-defined color themes.",
        "Themes must avoid pure white (#FFFFFF) backgrounds.",
        "The selected theme is applied globally across the application.",
        "The chosen theme preference is persisted with the other mode settings."
      ],
      "dependencies": [],
      "status": "todo"
    },
    {
      "id": 4,
      "title": "Apply Dyslexia-Friendly Layout Rules",
      "description": "Implement global CSS rules that activate when Dyslexia Mode is on. These rules will enforce left-aligned text, limit line length, and reduce visual distractions.",
      "files": [
        "src/styles/themes/dyslexia-mode.css",
        "src/components/ui/TextContainer.js"
      ],
      "acceptance_criteria": [
        "All justified text is forced to left-align.",
        "Maximum line length for primary content is constrained to ~75 characters.",
        "Non-essential decorative animations and background images are hidden via CSS."
      ],
      "dependencies": [],
      "status": "todo"
    },
    {
      "id": 5,
      "title": "Integrate Text-to-Speech (TTS) Engine",
      "description": "Integrate the browser's native Web Speech API or a third-party library to provide 'read aloud' functionality. This task includes creating the UI for playback controls (play, pause, stop) and settings for speed/voice.",
      "files": [
        "src/components/TTS/SpeechControls.js",
        "src/hooks/useTextToSpeech.js"
      ],
      "acceptance_criteria": [
        "A 'read aloud' button is available on all primary content blocks.",
        "User can play, pause, and stop the speech playback.",
        "User can adjust the reading speed and select from available voices.",
        "The TTS engine correctly reads the designated text content."
      ],
      "dependencies": [
        "Web Speech API (native browser feature)"
      ],
      "status": "todo"
    },
    {
      "id": 6,
      "title": "Implement Real-time Word and Sentence Highlighting",
      "description": "Develop the logic to visually track the text being read by the TTS engine. This requires highlighting the current word and the current sentence simultaneously using different visual styles.",
      "files": [
        "src/hooks/useTextToSpeech.js",
        "src/components/ui/HighlightedText.js",
        "src/styles/components/highlight.css"
      ],
      "acceptance_criteria": [
        "As the TTS reads, the specific word being spoken is highlighted (e.g., with a different color or underline).",
        "The entire sentence containing the spoken word has a distinct background highlight.",
        "Highlighting accurately tracks the audio playback in real-time.",
        "Highlighting styles have sufficient color contrast to be clearly visible."
      ],
      "dependencies": [
        "Web Speech API (SpeechSynthesisUtterance.onboundary event)"
      ],
      "status": "todo"
    },
    {
      "id": 7,
      "title": "Develop Digital Reading Ruler Tool",
      "description": "Create a toggleable reading ruler component. When active, it should overlay the screen and follow the user's cursor or finger, masking the page except for a horizontal strip to help the user focus on a single line of text.",
      "files": [
        "src/components/Tools/ReadingRuler.js",
        "src/styles/components/reading-ruler.css"
      ],
      "acceptance_criteria": [
        "A control exists to toggle the reading ruler on and off.",
        "When on, a semi-transparent overlay covers the screen.",
        "A clear horizontal strip within the overlay follows the vertical position of the mouse cursor.",
        "The ruler does not interfere with the ability to click on underlying elements."
      ],
      "dependencies": [
        "react (useEffect, useState)"
      ],
      "status": "todo"
    }
  ]
}

</AI_output>

That’s a killer backlog! And not only is it a killer backlog, it means that we have a plan, and I didn’t have to come up with it.

Now we enter a Copilot development cycle of:

What's the next task on our backlog?

Execute the development plan in that task

Create a unit test plan accoding to the acceptance criteria

Mark that task as complete and identify the next task

[once all tasks are done]

Create a smoke test plan for this workplan

Create an integration test plan for this workplan

We’ll explore what this development cycle looks like in future instalments, but for the time being, I’d like to invite you to play with it.

What problems does this solve?

  1. Always use a playbook when you have the choice. Playbooks are accelerators. They are auditable. They are automatable. And they have already worked for someone else. You don’t have to use this playbook, but find a “vibe-coding” playbook and get really comfortable with it.

  2. This backlog checklist preserves the context when you go down long debugging rabbit holes. I often found that both the LLM and I would lose sight of our original goal if one of us wasn’t keeping a plan. The LLM’s context gets so bloated with the back and forth debugging discussion that it loses sight of what you were working on and can start introducing bad advice from broken context. There are other strategies to deal with this, but I prefer to sidestep the whole issue and keep a formal backlog. That way, when we are done debugging, we re-anchor the context on the next task in the checklist.

  3. The backlog gives you a record that you can show to your employer, your users, your oversight team, that you haven’t just been “vibe coding.” You’ve been engaged in professional software engineering using established best practice and conforming to established testing practice. Because you have, and now you get to prove it.

If this guide doesn’t help you accelerate your development ambitions, then tell me what’s not working for you. I want to show all of you that you can build your dream software package whether you know code or not. Because your LLM is already the expert. You just need to ask how.

I’m looking forward to sharing the code I’ve been developing with the community once I get the hang of Git … sure wish I had a tool like Git the first time I was a dev! As always, I’d love to hear from the community. Try the workflow, share the results!

0
Subscribe to my newsletter

Read articles from John Robins directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

John Robins
John Robins

I used to be a developer. Then I was a soldier. Then I became a corporate leader. And now I'm also a researcher. All of these parts of me can be found in my blog and my research. I am also the father of three boys, a hobby woodworker, hobby gardener, hobby philosopher, hobby historian, and hobby anything else that captures my ever growing interests. My linkedIn posts are mostly AI-Assisted. This blog, however, is 100% my own work. I believe in transparency and will always be clear about what comes from me and what is AI-assisted.