跪拜 Guibai
← Back to the summary

Stop Telling AI to Code; Start Handing It a Blueprint

Goodbye "Spaghetti" and "Hallucinations": A Practical Guide to AI Collaboration from "Vibe Coding" to "Glue Programming"

Introduction: When "Vibe Coding" Hits the Wall of Reality

AI programming assistants (such as Cursor, GitHub Copilot, Codex) have brought the dream of "driving software development with natural language" to life. This futuristic development model has been vividly termed "Vibe Coding" by the overseas developer community.

However, the ideal is full, but the reality is stark. Many developers, especially beginners, often encounter two cold showers after their first attempts:

  1. "Hallucination Code": The AI confidently generates a piece of code that looks logically sound, but throws an error as soon as it runs. It might call a non-existent library function or generate a fabricated API field.
  2. "Legacy Spaghetti Code": The code barely runs, but its structure is chaotic. Global variables and local variables fly together, business logic and UI rendering share the same color. You want to modify a small feature, but it's like pulling a critical block from a crumbling tower of blocks—you have no idea where to start, and it collapses at the slightest touch.

What's the problem? Did we overestimate AI's capabilities, or underestimate the complexity of software engineering?

The answer lies in our collaboration method with AI. This article will share a proven, effective methodology for AI-assisted development—Plan First, Then Glue, Then Evolve. It's not just about teaching you to write prompts, but about teaching you how to manage, constrain, and efficiently collaborate with AI, this "super intern," like a senior architect, to write reliable, maintainable, production-grade code.

I. Core Mindset: From "Code Porter" to "AI Architect"

When collaborating with AI, we must change our role. We are no longer mere "code porters" or "instruction inputters," but the project's architect and product manager.

Core Methodology: Plan First, Glue Together, Self-Evolve.

We can visualize this process as constructing a building:

We will use a classic React + TailWind CSS Todo List application as a practical demo throughout the article, demonstrating this methodology step-by-step.

II. Step 1: Planning is Everything — How to Constrain AI's "Wild Imagination"

Many developers' first reaction upon receiving a requirement is: "Hey, AI, write me a Todo List page." This is like telling a new intern: "Go, refactor the company's core business." Without context and constraints, the AI can only guess based on "intuition," generating code that "looks correct." This is the source of "hallucinations" and "spaghetti."

The Solution: /init (Initialize Context). We must first force the AI to understand our tech stack, project specifications, and business boundaries. It's like giving a new employee a copy of the "Company Java Development Manual" to familiarize them with the environment before starting work.

In practice, we don't directly ask the AI to write code, but instead have it first output a complete "Project Technical Plan and Feature Decomposition Document."

Step Breakdown: How to Make an AI-Friendly Plan

Phase One: Only plan, prohibit any code output.

Below is an example of the prompt we give to the AI, which includes a complete structured thinking framework:

Adhere to glue programming thinking: Prioritize using mature solutions, avoid creating logic out of thin air.

Phase One: Only plan, prohibit any code output.

1.  **Confirm Tech Stack**:
    - Frontend Framework: React 19 (using Hooks for state management)
    - UI Solution: TailWind CSS (for rapid style layout)
    - State Management: useState (sufficient for the current scenario, no need for Redux/Zustand)

2.  **Define Feature Boundaries (Core: Define scope to prevent bloat)**:
    - **Included Features**: Add todo, delete todo, toggle task completion status.
    - **Explicitly Excluded (Scope Exclusion)**: No local persistence (localStorage), no filtering, no drag-and-drop sorting. This step is crucial to prevent the AI from arbitrarily adding complex features to "show off," leading to bloated code.

3.  **Decompose Modules (Lego Component Thinking)**:
    - `InputArea`: Input box component, responsible for capturing user input and triggering add events.
    - `TodoItem`: Todo item component, responsible for displaying the text and status of a single task, and handling delete and toggle interactions.
    - `TodoList`: List container component, responsible for rendering all `TodoItem`s and managing the overall layout of the list.

4.  **Define Data Flow and Data Structure (Eliminate field hallucinations at the root)**:
    - The data structure must be explicit and cannot be defined by the AI (the AI might use chaotic fields like `title`, `content`, `isDone`).
    - **Unified Data Structure**:
      ```typescript
      interface Task {
        id: string;      // Unique identifier, using Date.now() + Math.random() or uuid
        text: string;    // Task content
        completed: boolean; // Completion status
      }
      ```
    - **Data Flow**: `useState<Task[]>` stores the data array. `InputArea` passes data upwards via an `onAdd` callback; `TodoItem` affects the parent component's state via `onDelete` and `onToggle` callbacks.

5.  **Output this complete plan, wait for my confirmation, and then implement the code in segments.**

Deep Thinking: The Underlying Logic Behind the Plan

  1. Scope Definition: This is the firewall against AI's "over-engineering." An explicit "not-to-do list" is more important than a "to-do list," as it directly nips the soil where AI hallucinations grow due to unclear context.
  2. Forced Modularization: Decomposing the UI into independent, single-responsibility components. This not only makes the generated code highly readable and easy to maintain but also facilitates our review of each piece of logic generated by the AI.
  3. Predefined Data Contract: {id, text, completed} is the contract between the front-end and back-end (or UI and state layer). Mandating field names and types completely eliminates the "field hallucination" caused by the AI arbitrarily changing field names across different conversation rounds.

This planning document will become the "constitution" for our collaboration with the AI throughout the project lifecycle. All subsequent prompts will automatically carry the context of this plan to maintain consistency.

III. Step 2: "Glue" Programming Mindset — Be a Smart "Integrator"

With a clear plan, we enter the coding phase. But there's a "trap" here: Don't command the AI to reinvent the wheel from scratch.

Wrong Example vs. Correct Approach

Wrong Example (Imperative):

"Help me write a drag-and-drop sorting feature in React so the todo list can be dragged up and down."

Consequence: The AI will likely "thoughtfully" hand-write a complex set of onMouseDown, onMouseMove, onMouseUp coordinate listening logic, coupled with complex array sorting algorithms. Hand-written drag-and-drop has numerous edge cases (like scrolling, touch events, performance issues), which is tantamount to creating a petri dish for bugs.

Correct Approach (Glue-Style): According to the "glue programming" principle—Copy if you can, connect if you can, don't build if you don't have to. Our job is Research -> Selection -> Gluing.

Step 1: Research Mature Solutions

In the React ecosystem, react-beautiful-dnd is a battle-tested drag-and-drop library developed by the Atlassian team and verified by hundreds of millions of users. We don't need to care how it internally implements Droppable and Draggable; we only care about how its provided API connects to our TodoList.

Step 2: Write the "Glue Code"

What we need to do is write very little "glue code" to bind the ready-made <DragDropContext>, <Droppable>, <Draggable> components with our TodoList.

Complete Code and Annotated Explanation:

// 1. Install dependency (command line operation)
// pnpm add react-beautiful-dnd

// 2. TodoList Component - Focuses on gluing logic
import React, { useState } from 'react';
import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';

// Assumed initial data
const initialTasks = [
  { id: '1', text: 'Learn Vibe Coding', completed: false },
  { id: '2', text: 'Read React Official Documentation', completed: true },
];

const TodoList = () => {
  const [tasks, setTasks] = useState(initialTasks);

  // Glue function: Handles data update after drag ends
  // This is the only "gluing" logic we need to hand-write
  const handleOnDragEnd = (result) => {
    // The result object contains the source and destination positions of the drag
    // 1. Robustness check: If dragged outside the list (no destination), do nothing
    if (!result.destination) return;

    // 2. Data reorganization: Use spread operator and splice to simulate array element movement
    // This part of the logic is standard "glue," connecting UI interaction (drag) with data state (tasks)
    const items = Array.from(tasks);
    const [reorderedItem] = items.splice(result.source.index, 1);
    items.splice(result.destination.index, 0, reorderedItem);

    // 3. Update state, trigger UI re-render
    setTasks(items);
  };

  return (
    // Glue container: DragDropContext is the context provider for the entire drag area
    <DragDropContext onDragEnd={handleOnDragEnd}>
      {/* Glue container: Droppable defines a droppable area, requires a droppableId */}
      <Droppable droppableId="todoList">
        {/* Note: The (provided, snapshot) here are props provided by the library and must be correctly bound */}
        {(provided, snapshot) => (
          <div
            {...provided.droppableProps} // Must bind, contains necessary DOM attributes
            ref={provided.innerRef}       // Must bind ref so the library can control the DOM
            className="p-4 bg-gray-100 rounded-lg"
          >
            {tasks.map((task, index) => (
              // Glue component: Draggable defines a draggable element, requires draggableId and index
              <Draggable key={task.id} draggableId={task.id} index={index}>
                {/* Similarly, the (provided, snapshot) here must also be correctly bound to the actual DOM element */}
                {(provided, snapshot) => (
                  <div
                    ref={provided.innerRef}       // Must bind ref
                    {...provided.draggableProps}  // Must bind, contains attributes needed for dragging
                    {...provided.dragHandleProps} // Must bind, defines the drag handle area
                    className={`p-3 mb-2 bg-white shadow rounded flex justify-between ${
                      // Use the information provided by snapshot to change styles during drag, enhancing UX
                      snapshot.isDragging ? 'bg-blue-50 shadow-lg' : ''
                    }`}
                  >
                    <span className={task.completed ? 'line-through text-gray-400' : ''}>
                      {task.text}
                    </span>
                    {/* Delete and toggle status buttons omitted here, as they are unrelated to drag logic */}
                  </div>
                )}
              </Draggable>
            ))}
            {/* Must add provided.placeholder, it's used to hold space during drag to prevent list jitter */}
            {provided.placeholder}
          </div>
        )}
      </Droppable>
    </DragDropContext>
  );
};

export default TodoList;

Deep Thinking: What is the Essence of "Glue Code"?

The amount of "glue code" we write is minimal, and the logic is clear. The possibility of AI producing hallucinations and spaghetti is exponentially reduced.

IV. Step 3: Meta-Methodology — Letting AI Self-Evolve

If "planning" is a static constraint and "glue" is the connection between modules, then the "meta-methodology" is the dynamic engine that continuously optimizes the entire system.

In advanced AI programming tools (like Cursor's Composer, Harness architecture), an important concept is "self-evolving prompts." Its core idea is: AI can not only write code but also help you optimize its own prompts.

This concept can be broken down into two roles:

Practice Flow:

  1. You use the α prompt to have the AI generate a module.
  2. You then input the Ω prompt, for example: "Please review the TodoList component code you just generated, score it from three dimensions: readability, performance (whether React.memo is used), and compliance with the plan, and generate optimization suggestions."
  3. The AI will act as a "code reviewer" examining its own output and provide an improvement plan.
  4. You use the improvement plan as new context and ask the AI to refactor again.

This mechanism transforms the AI from a tool that can only "generate forward" into an intelligent agent capable of "reflection." It effectively utilizes the large language model's own knowledge base (which contains patterns from countless excellent codebases) to continuously optimize its output quality.

Thought: For beginners, the Ω prompt is equivalent to a senior mentor available 24/7. You don't need to fully understand all best practices; the AI will help you gradually elevate your code quality from 60 points to 90 points through self-play.

V. Summary: The Core Competitiveness of Engineers in the AI Era

Through this practical Todo List exercise, we can see that in the AI era, the standards for measuring an engineer's ability have quietly shifted:

Finally, remember these three core action guidelines:

  1. Plan First, Code Later: Spending 20% of the time on planning can save 80% of the time debugging "hallucinations" and refactoring "spaghetti."
  2. Be the Glue, Don't Reinvent the Wheel: The less code you have, the less chance for errors. Make good use of the community's mature "Lego bricks," and you are only responsible for writing the thinnest layer of "glue."
  3. Use Evolution, Replace Blind Obedience: Let AI participate in code review and prompt optimization, leveraging its powerful knowledge base for self-iteration.

I hope this guide helps you truly master AI programming, write more elegant and robust code, and enjoy the real fun that "Vibe Coding" brings.