25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

15KB

Context Engineering — Chapter-16: Project organization

  • Source: /library/Context Engineering/source-file.pdf
  • PDF pages: 109–117
  • Pages without text: none

Project organization The previous chapter ended on a layer of context nobody writes: the structure of the project itself. Before I defend that idea, look at what happens when it fails. It is a Monday, and Vila Nova Clinic’s clinical coordinator asks for a small change: on Saturdays the limit on work-ins, the extra appointments squeezed into a full schedule, drops from two to one per provider, because the smaller Saturday crew cannot absorb the weekday pace. You hand the task to the agent with the work-in spec in the window, the way chapter 8 taught, and you watch the session. Its first move is the first move of every session: list the directory to get oriented. And the listing that comes back is this one, VilaSchedule as it is organized today: ├── controllers │ ├── appointment_controller.ts │ ├── provider_controller.ts │ ├── report_controller.ts │ ├── scheduling_controller.ts │ └── workin_controller.ts ├── models │ ├── appointment.ts │ ├── block.ts │ ├── interval.ts The agent’s question is “where does the daily work-in limit live?” and the structure does not answer it. controllers says how the system receives requests; models says it has entities; no folder says where a business rule lives. So the agent does the one thing

left: it searches. It opens workin_controller.ts , which only translates errors. It opens workin.ts in models , which declares the entity. It opens workin_validator.ts in validators , finds a limit check and changes it. The tests pass, the diff looks complete, and the change is wrong: the same rule also lives in workin_service.ts , inside services , where work-in creation applies it again before saving. On the following Saturday, the front desk books the second work-in through the path that never touches the validator, and the new limit does not exist. The session had already cost real money before it got the answer wrong: four files loaded into the window to find two, tokens billed by the arithmetic of chapter 6 and distractors competing for attention the way chapter 5 measured. The agent did not fail for lack of written context; it failed because the context it reads first, the structure, says nothing about the system. The context source you do not write Every artifact in Part II so far costs time to write and to maintain: you draft the spec for each task, continuous integration verifies the living doc, and every review prunes the persistent file. The folder structure is different: it already exists, because every project has one, and it is already read, because listing directories is the first step of any agent in any session, before the spec, before the doc, before the persistent file itself tells it to read anything. Every folder name and file name that shows up in a listing enters the window and informs, or misinforms, the model. It is context at zero marginal cost: you write no extra document, you maintain no extra test, you only pick names and places you would have had to pick anyway. The right question, then, is what your structure says when it is read as text. In 2011, Robert C. Martin published “Screaming Architecture” (blog.cleancoder.com) with a direct test: look at the

blueprint of a building and it screams what the building is, a house, a library, a clinic. “Your architectures should tell readers about the system, not about the frameworks you used in your system.” The argument was about human readers and about decisions worth deferring; it gained a new reader in 2026, and that reader is the most literal of them all. An experienced developer makes up for a silent structure with memory: after a month on the project, they know the work-in rule lives in the service and in the validator, and they do not even read the listing. The agent of chapter 3 does not get that month; it starts every session with no memory and rereads the structure every time, from scratch. What the tree screams is what the agent hears. Here I should set the scope, because organizing systems by feature fills an entire book. If you have read my book FOCUS Architecture (https://books.kodel.com.br/en/books/focus/), you know the method and the vocabulary: the criterion is the axis of change, which puts together what changes together; the cut it produces is the vertical slice, everything a feature needs, from the edge to the database; and the folder per feature is the symptom of both. That book covers what lives inside each slice, which dependencies are allowed and how all of it holds up as the system grows. This chapter reteaches none of that, and you do not need to have read it to follow from here. The cut here is this book’s: the folder tree as a source of context for the AI, what it communicates for free and what it charges when it communicates the wrong thing. How to arrive at a good organization is FOCUS’s topic; what a good one is worth inside a context window is this chapter’s. What the technical tree screams Apply Martin’s test to Monday’s full structure:

technical-structure ├── config │ └── scheduling.yml ├── migrations │ ├── 013-create-block.sql │ └── 014-create-workin.sql └── src ├── controllers │ ├── appointment_controller.ts │ ├── provider_controller.ts │ ├── report_controller.ts │ ├── scheduling_controller.ts │ └── workin_controller.ts ├── models │ ├── appointment.ts │ ├── block.ts │ ├── interval.ts │ ├── provider.ts │ ├── weekly_schedule.ts │ └── workin.ts ├── repositories │ ├── appointment_repository.ts │ ├── provider_repository.ts │ └── workin_repository.ts ├── services │ ├── confirmation_service.ts │ ├── scheduling_service.ts │ ├── utilization_service.ts │ └── workin_service.ts ├── utils │ ├── dates.ts │ └── whatsapp.ts └── validators ├── appointment_validator.ts └── workin_validator.ts The first level screams “layered web application,” and nothing else. Controllers, models, repositories, services, validators: that tree describes VilaSchedule about as well as it would describe an online store, a bank or a forum, because it catalogs the kinds of parts the framework has, not the system’s features. The business

does show up, but scattered: the work-in, a single feature, is spread across five folders, one file per layer. To answer “how does a work-in work?” a human or an agent has to assemble five files spread across the tree; to answer “where do I change the daily limit?” either one has to guess which layer the rule fell into, and Monday showed the price of the guess: it fell into two. That scattering compounds everything Part I measured. Every business task, and business tasks are most of them, turns into a file-gathering exercise across the whole tree, and every file opened by mistake is a token paid for and attention diluted. Worse: the technical tree ages in the wrong direction. When the services folder holds four files, the damage is small; when it holds forty, every search sweeps forty candidates, and the listing that opens every session becomes a page of names that all end the same way. The technical tree does not lie the way the bloated file of chapter 12 does, but it commits the other sin of context: it takes up the window without informing it. What the feature tree screams Now the same system, the same files, with the tree organized by what changes together: feature-structure ├── config │ └── scheduling.yml ├── migrations │ ├── 013-create-block.sql │ └── 014-create-workin.sql └── src ├── features │ ├── appointments │ │ ├── appointment.ts │ │ ├── appointment_controller.ts │ │ ├── appointment_orchestrator.ts

│ │ ├── appointment_repository.ts │ │ ├── book_appointment.ts │ │ └── confirmation │ │ ├── day_before_reminder.ts │ │ └── whatsapp_confirmation.ts │ ├── providers │ │ ├── provider.ts │ │ ├── provider_controller.ts │ │ ├── provider_orchestrator.ts │ │ └── provider_repository.ts │ ├── reports │ │ ├── report_controller.ts │ │ └── utilization.ts │ ├── scheduling │ │ ├── block.ts │ │ ├── interval.ts │ │ ├── interval_generation.ts │ │ ├── scheduling_controller.ts │ │ ├── scheduling_orchestrator.ts │ │ └── weekly_schedule.ts │ └── workins │ ├── day_limits.ts │ ├── workin.ts │ ├── workin_controller.ts │ ├── workin_orchestrator.ts │ └── workin_repository.ts └── shared └── dates.ts Read the first level of features as a sentence: appointments, providers, reports, scheduling, work-ins. That is VilaSchedule described in five words, obtained without opening a single file, and notice where those words come from: they are the same terms the living doc of chapter 9 and in the vocabulary the conventions of chapter 11 protect. The tree now speaks the language of the project’s other artifacts, and every directory listing reinforces, for free, the vocabulary you pay to maintain in the documents.

Notice what the second level does not have: inside workins there is no controllers , no services and no repositories , and there is also no view , no orchestrator , no usecases and no data . The files of the slice sit flat in its folder, and each one’s role is in its name, not in the folder that holds it. Here I owe you an explicit note about a choice of mine, because it is more restrictive than FOCUS’s: there, a slice may organize itself internally into those four parts, and nothing about that is wrong. This chapter’s criterion is a different one, narrower on purpose, because it looks only at what the listing hands to whoever arrives with no memory. A folder with four drawers returns four names any slice would have, and the answer to “where does the daily limit live?” takes a guess again; the flat folder shows day_limits.ts in the first listing. Oskar Dudycz made a similar point in “My thoughts on Vertical Slice Architecture,” when he said that organizing by feature is sometimes just rearranging folders with the same layers intact one level down. The point does not convince me as a criticism of the architecture, and FOCUS answers it on the merits: a slice is not a mold with four drawers, and what sets a slice’s internal size is the axis of change, not symmetry. But the observation does describe the effect that matters here, the one about the tree as text read in every session. When a slice grows too big, what it gets is a subfeature, not a layer, and appointments/confirmation shows the shape: one more cut of the domain, with all of its files inside. Now run Monday again on this tree. The question “where does the daily work-in limit live?” now has a one-line answer: in the workins slice, in the file day_limits.ts , which the folder listing puts in front of you with no hop in between. The agent opens one file, the right one, and the rule is whole in there, because organizing by feature removes the reason it used to be scattered: there is no longer a validator at one end of the tree and a service at the other for the same rule to land in twice. Saturday’s change touches one slice, the diff stays inside it, and the review checks one feature, not five layers. The session’s cost drops too: instead of sweeping

the whole tree, the agent loads one small folder, and chapters 5 and 6 already gave you the two ways of counting that gain, fewer distractors in the window and fewer tokens on the bill. The comparison fits in one sentence: the two trees hold the same files, but the technical one answers “what parts is the system made of,” a question the agent never asks, and the feature one answers “what does the system do and where,” which is the opening question of every session. The right answer enters the window at the moment of greatest leverage, the first step, when the agent decides what to read next; getting it wrong there contaminates the rest of the session, as Monday’s blind search showed. And notice what the feature tree makes unnecessary: the persistent file of chapter 12 needs no “map of the project” section that explains where each topic lives, because the structure is already the map. A good structure shrinks the written artifacts; a silent one forces them to make up, one paid line at a time, what it failed to say. I should record the cost, so you do not leave here thinking the change is free: reorganizing an existing project is a large refactoring, and doing it for the agent alone rarely justifies the bill. The good news is that the agent does not have to justify it alone: the same organization that orients the agent orients a new developer, contains the feature’s diff and shows up as a central argument in FOCUS, for reasons that have nothing to do with AI. The agent comes in as one more beneficiary of a decision that was already worth making, and the one who reads it most often. On a new project, the choice does not even carry that cost: the two trees cost the same to create, and only one of them works for free in every session. One last point about what the feature tree does not do. It says where each topic lives, but it does not keep anyone out: nothing in appointments forbids a direct import of workins/day_limits.ts , and

the work-in rule can leak into appointment scheduling without any folder complaining. Structure communicates; it does not enforce. And over time the communication degrades if the boundary lines are not real: every import shortcut smudges the map a little, and the listing promised it whole. Turning those folders into real boundary lines, deciding what each module hides and what it exposes, and seeing how that changes the context the agent receives is the topic of the next chapter.

Powered by TurnKey Linux.