選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

15KB

Spec Driven Development — Chapter-22: 10 - Edit Task: The Spotlight on implement

  • Source: /library/Spec Driven Development/source-file.pdf
  • PDF pages: 402–414
  • Pages without text: none

10 - Edit Task: The Spotlight on implement The Last Loop Starts on main main is stable with four features: create and list, complete and reopen, filter by state, delete. The fifth repeats the usual gesture: the 005-editar-tarefa branch cut from main , the whole cycle run inside it, and the merge handing the result back at the end. It is the last lap on the map, the feature that closes the app. The map is the usual one. It is worth reopening it one last time, not to relearn it, but to get your bearings:

It is the same diagram from Chapter 5; what changes is only where you stand on it. This time the spotlight falls on the step that was still unlit, implement , where the task list turns into code that passes the tests. The feature this time is editing a task: the person fixes the text of something they already created, the title or the description. It serves implement precisely because it is small. The rules are already known, the entity already exists, the stack was chosen four loops ago; little is left to decide and much to execute. That frees the chapter to look closely at the act of building, which is what has not yet had the spotlight. And it is minimal on purpose (Principle V, Simplicity). Editing changes the textual content the task already has, without inventing a new field. Out of scope, declared as non-goals: an edit

history, bulk editing and any field beyond title and description. Keeping the feature lean is what leaves the spotlight on implement instead of spending it arguing over scope. From specify to analyze , at a Light Pace You have already seen each of these steps under the spotlight, in the four earlier chapters. Here they run light, just to reach the door of implement with the groundwork ready. specify is short: the person wants to fix the text of an existing task. clarify ties up the predictable loose ends: editing changes title and description (the text the task already has); the title rules apply again (required and not repeated, as in creation); the edit happens in place, without changing the position in the list or the creation date; and editing a task that no longer exists is error as value, not an exception. plan inherits the usual stack and decides a lean how: one new use case, EditTask , that looks the task up, revalidates the title and writes the corrected version. Here the first reward of accumulated simplicity shows up: the repository gains no new method. getById and update have existed since the second loop, and update already updates in place without reordering the list. Editing, in the data layer, is the same update that completing already used. Four loops of accumulated simplicity pay off here: the fifth feature barely asks for new infrastructure, just a use case that ties together pieces that were already in place. checklist passes without flagging a hole in form. analyze crosses spec, plan and tasks and finds them coherent with each other: every requirement has a task, every plan decision comes from a clarification, the order is TDD's. Clean report, zero conflicts. Unlike the previous chapter, editing does not collide with any old

decision: it reuses the creation rules instead of reopening them. Keep that “clean report” in mind: it will come back later, when implement shows that clean is not a synonym for complete. implement Reads the Artifacts, Not the Chat implement arrives: the core-loop step that executes the tasks one by one and produces the code that passes the tests. It is the step that finally writes software, and this chapter's central point is where it draws what it needs to write. The answer surprises anyone used to chatting with the AI: implement does not reread the chat. It starts from the versioned artifacts. It checks the prerequisites, opens tasks.md and the feature's available documents (the spec, the plan, the data model), and works down the task list phase by phase, executing each one and marking it done.1 The source of truth is the documentation the earlier steps recorded, not the memory of the window. The agent reads “T002: test of EditTask , fails first” and goes and does exactly that, consulting the spec and the plan when it needs the detail, without depending on remembering what was said three steps ago. This is where the /clear habit, repeated since Chapter 5, collects its meaning. Throughout the whole chapter you wiped the context between steps and, even so, nothing was lost, because what mattered was on disk, not in the conversation. implement is the final proof of this: it is able to build the feature reading only the artifacts because the artifacts were made to be read on their own. If the step depended on the chat history, /clear would have been a shot in the foot; because it depends on the documents, /clear was what kept each step lean and focused. The spec → plan → tasks → code chain stops being a metaphor here: it is literally the path implement walks, link by link.

This changes what “asking an AI for code” means. In improvisation, code comes out of a conversation: you describe, it guesses, you correct in the next reply, and the quality of the result depends on how much of the conversation still fits in the context. In implement , code comes out of a chain of reviewed documents, and each document has already passed your approval. The difference is in the source, not the tool. Red, Green, Refactor Inside implement , code is not born just any way: it is born under the red-green cycle of TDD. There are three beats. First the red: you write a test of the desired behavior and run it knowing it will fail, because the code does not exist yet. Then the green: you write the minimum of code that makes that test pass. Finally, the refactor: with the test passing as a safety net, you clean the code without fear, because any regression relights the red at once. It is the TDD of Chapter 1, now in action, and it is Principle IV of the To-Do constitution coming off the page. Watch the first beat in practice. Task T002 orders writing the EditTask test before the implementation. One of the cases says editing must, in fact, change the task's text: it(“changes the title and description of an existing task”, async () => { const repository = new InMemoryTaskRepository(); const task = await seedTask(repository, “Buy bread”, “id-1”); const editTask = makeEditTask(repository);

const result = await editTask({ id: task.id, title: “Buy whole-grain bread” , description: “at the corner bakery” }); expect(result.kind).toBe(“success”); const stored = await repository.getById(task.id); expect(stored?.title).toBe(“Buy whole-grain bread”); expect(stored?.description).toBe(“at the corner bakery”); }); Running the suite now goes red, and the red is honest: the use case file does not exist yet. FAIL test/domain/edit-task.test.ts [ test/domain/edit-task.test.ts ] Error: Failed to load url ../../src/domain/usecases/edit-task ... Does the fi le exist? That is the most common red at the start of a feature: not an assertion that fails, but “the thing you are about to build is not here yet.” The test has already pinned the intent; the code is what is missing to meet it. The green beat is writing that code, and only it. EditTask looks the task up, applies the title rules in order and writes the corrected version, returning error as value at each predictable failure:

export const makeEditTask = (repository: TaskRepository): EditTask => async ({ id, title, description = "” }) => { const task = await repository.getById(id); if (task === null) { return failure({ kind: “task-not-found” }); } const trimmedTitle = title.trim(); if (trimmedTitle.length === 0) { return failure({ kind: “title-required” }); } const existing = await repository.getAll(); const isDuplicate = existing.some((other) => other.title.trim() === trimm edTitle);

if (isDuplicate) { return failure({ kind: “duplicate-title” }); } const edited: Task = { ...task, title: trimmedTitle, description: descrip tion.trim() }; await repository.update(edited); return success(edited); }; With the use case in place, the suite closes green: ✓ test/domain/edit-task.test.ts (5 tests) Test Files 9 passed (9) Tests 43 passed (43) The third beat, the refactor, is discreet here and instructive for that reason. Notice the duplicate check: it is identical to the one in task creation, back from the first loop. implement did not reinvent the rule; it reused the same criterion (title compared after trim ), keeping the behavior consistent between creating

and editing with the test suite guarding the change. Refactoring is not always rewriting; sometimes it is recognizing that the right path already exists and following it. The cycle repeats in the next phases (the editTask action in the store, the edit mode on the screen), always on the same beat: a test that describes the behavior, the minimum code that satisfies it, the cleanup done with the suite green confirming nothing broke. Why does the test come before, and not after? Because the test written before describes the intent; the test written after tends to describe the code you already wrote, wrong and all. The red that comes first is the proof that the test really exercises something that does not exist yet; the green that comes next is the proof that the code does what the spec asked, and not what the programmer assumed in the heat of the moment. Reviewing What the Agent Wrote implement produces code, but it does not produce automatic trust. The generated code is reviewed before being accepted, and reviewing here has a precise meaning: checking, in the code, whether it honors the To-Do constitution. It is a reading against principles, where personal taste does not enter. Look at EditTask again with the principles in hand. The layered architecture (Principle I) is respected: the use case talks to the domain and the repository, and knows neither the screen nor localStorage . The business logic isolated from the UI (Principle II) is in the right place: the three decisions (does the task exist? is the title valid? is it a duplicate?) all live in the use case, not the view; the screen only collects text and shows the result. And error as value (Principle III) appears at every failure exit: task-not-found , title-required , duplicate-title are Result s returned, not exceptions crossing layers. The review confirms that what the constitution

preaches is what the code demonstrates. That is the sense of reviewing: you do not ask “does the code look good?” but “does the code obey the rules we agreed on?". The full repertoire of that check, with far more items than the three the To-Do's constitution fixed, is in FOCUS Architecture (2026, https://books.kodel.com.br/en/books/focus/), the second volume in this trilogy, which answers where each rule lives and why dependencies point inward. You do not need it here: this chapter's checklist is the constitution itself, and it fits on one page. And when the review finds a deviation? That is what happened here, and the case is worth more than any principle stated in the abstract. The suite was green, the build clean, analyze had passed with no conflicts. Even so, the manual validation of the quickstart ran into a simple scenario: editing only the description, keeping the title. Reduced to a test, the result was this: × EditTask keeps its own title when editing only the description (not a dupl icate) → expected ‘failure’ to be ‘success’ The cause was in plain sight in the code you just read: the duplicate check, copied from creation, compares the new title against all tasks, including the one being edited. Keeping your own title fell as a duplicate. The wrong reflex, at this point, would be to open EditTask and patch the condition right there, in a hurry. The right reflex is another: go back to the source artifact. The defect was not born from a typo; it was born from an incomplete spec. FR-003 said “title not repeated, on the same criterion as creation” and never said whether the task itself counted. The code just executed, faithfully, an ambiguous instruction.

So the fix goes down the chain, in the order it exists. First the spec: FR-003 is rewritten to say “not repeated among the other tasks; keeping your own title is not a duplicate,” with a new clarification recording where the adjustment came from. Then the tasks: T002 gains the “keeping your own title returns success” case. Only then the code, and now with a test first: the red case above, and the one-line amendment that makes it pass. const isDuplicate = existing.some( (other) => other.id !== id && other.title.trim() === trimmedTitle ); The suite closes green again, now with the missing case covered: Test Files 9 passed (9) Tests 46 passed (46) It is the “fix at the source” of Chapter 9 again, now triggered by implement instead of analyze : patching the code would have made the test pass and left the spec lying. And there is the lesson the “clean report” was keeping: checklist and analyze check form and consistency between artifacts, but they do not guess what the wording left implicit. What caught what slipped through were the test and the review. Code outside the expected, before being a programming bug, is a sign of an incomplete artifact asking for a fix back at the source.

Loop Closed, App Complete With the suite green and the build clean, the final path is the familiar one. You commit the work on the branch (the artifacts and the code, including the commit that records the fix at the source) and merge 005-editar-tarefa back into main . The main line is stable once again, now with five capabilities where, at the start of this journey, there were none. And with the fifth feature integrated, the app is complete. Create, complete, filter, delete, edit: the life cycle of a personal task, whole, from birth to correction. The whole-picture look at the five laps comes at the end of this part. Chapter 11 does not open a new loop; it turns back and does the retrospective: what each repetition taught, what is gained by trading improvisation for the chain of artifacts, and why the same cycle served five features so different from one another. The app is ready. What is left is to name what it taught us.

Footnotes Command names, the order of the steps, and the exact form of invocation may evolve between versions of spec-kit; the excerpts in this chapter were generated with version 0.11.8. For details that change per release (flags, subcommands, internal paths), check the official spec-kit documentation instead of fixing them from memory.

Powered by TurnKey Linux.