Iza prompta: Izgradite softver iz kojeg će AI rado učiti
Most AI coding discussions begin with the prompt: how specific it should be, which context to include, how to ask for tests, when to request a plan. Those things matter. But they are not the foundation.
The quality of an AI-assisted change is often decided long before anyone opens a chat window. It is decided by the software system itself: its boundaries, naming, tests, documentation, operational signals, and the ease with which a person can understand what happens when something goes wrong.
AI does not need software to be fashionable. It needs software to be legible.
AI is a new reader of your codebase
A capable model can summarize files, trace references, propose changes, and draft tests quickly. Yet it still works from evidence. If the evidence is scattered, contradictory, or absent, the model can produce code that looks plausible while quietly violating the system’s actual rules.
Human developers face the same problem, just more slowly. A new engineer may learn that an endpoint should not call a database directly only after finding a convention hidden in another service, a comment in a pull request, or an incident postmortem. An AI agent has less organizational memory to fall back on. It will infer a pattern from what it sees.
That makes existing patterns unusually important. Inconsistent conventions do not merely annoy a model; they create multiple competing answers to the question, “How is this supposed to work here?”
The practical goal is not to make every repository perfectly uniform. It is to make important decisions discoverable and local enough that a reader can verify them.
Design for clear boundaries
AI performs better when a requested change has an identifiable home. A task such as “add a new notification preference” should lead naturally to a domain model, an API contract, validation rules, persistence, a user-facing flow, and tests. If those concerns are blended across unrelated files, both humans and agents must reconstruct the architecture before making a safe edit.
Clear boundaries are especially valuable around the places where mistakes are expensive:
- authorization and identity checks;
- financial calculations and state transitions;
- external service integrations;
- schema changes and data migrations;
- background jobs, retries, and idempotency;
- configuration and secret handling.
For example, an integration should expose a small interface that represents the application’s needs, rather than allowing application code to call a vendor SDK everywhere. That structure gives an AI agent a constrained place to add behavior and a clear seam for tests. It also makes human review more meaningful: reviewers can focus on the business behavior instead of rediscovering integration details in every call site.
Boundaries are not abstraction for its own sake. They are a way to reduce the number of assumptions required to make a change.
Make behavior executable, not merely implied
Tests are among the best context documents a codebase can have, provided they test behavior rather than implementation trivia. A well-named test tells a reader what must remain true after a change. It gives an AI agent a target, and it gives the team a fast way to reject an attractive but incorrect implementation.
Consider a retrying job. “Retry on failure” is not enough specification. Which failures are retryable? How many attempts are allowed? What prevents duplicate side effects? What happens after retries are exhausted? A small set of focused tests can answer those questions more reliably than an unwritten convention.
it("does not retry a request rejected by validation", async () => {
const result = await deliverMessage(invalidMessage);
expect(result.status).toBe("rejected");
expect(queue.enqueue).not.toHaveBeenCalled();
});
This example does not prescribe a framework or architecture. It expresses a boundary: invalid input is not a transient delivery failure. That distinction prevents an agent from adding broad retry logic that creates noise, cost, or repeated bad work.
Tests should also cover failure paths deliberately. AI-generated code often handles the happy path competently because happy paths are common in training examples and codebases alike. The risk accumulates in partial failures, stale data, timeouts, missing permissions, and repeated requests.
Write documentation where decisions happen
Documentation is most useful when it answers questions that source code cannot answer on its own. Avoid repeating what a function obviously does. Explain why a constraint exists, what invariant matters, or which tradeoff the team chose.
A concise README for a service can describe its purpose, local startup path, dependencies, test commands, and ownership boundaries. A decision record can explain why an operation is asynchronous or why a particular consistency model is acceptable. An operational runbook can say what signals indicate a stalled worker and what safe recovery looks like.
These documents help AI agents gather context, but their primary value is still human. The best documentation lowers the cost of being careful.
Keep instructions close to the work
Repository-wide guidance is useful for broad rules: formatting, validation commands, security requirements, and architectural principles. More specific instructions should sit near the subsystem they govern. A payments module may have rules that do not apply to a reporting package; a migration directory may require checks that ordinary code changes do not.
Specificity prevents two common failures: an agent applying a global rule too broadly, and a developer assuming local constraints do not exist.
Give automation a reliable path to confidence
An AI agent is not a substitute for delivery safeguards. Treat it like a fast contributor that can make changes, explain them, and run agreed checks. It still needs a system that reveals whether the change is safe to merge and deploy.
A useful change loop is simple:
- State the intended behavior and affected boundary.
- Inspect the relevant code, tests, and local guidance.
- Make the smallest coherent change.
- Run targeted tests, then the relevant broader checks.
- Review the diff for scope, security, and operational consequences.
- Deploy through the same controlled path used for human-authored changes.
The phrase “smallest coherent change” matters. A request to add a field should not become an unsolicited framework migration, broad refactor, or new dependency. AI can make large edits cheaply; that makes scope discipline more valuable, not less.
Continuous integration should provide dependable feedback, not a ritual that frequently fails for unrelated reasons. If tests are flaky, setup is obscure, or environments differ unpredictably, people and agents will learn to treat green checks as luck. Reliable automation turns model output from a suggestion into a verifiable candidate change.
Preserve accountability in the workflow
Responsible adoption does not mean banning autonomy. It means assigning it appropriately. An AI agent can prepare a patch, enumerate affected files, draft a migration plan, generate test cases, or investigate an incident timeline from available logs. A human should remain accountable for decisions involving risk, ambiguous product intent, privacy, security, irreversible data changes, and production release approval.
Review quality improves when reviewers ask concrete questions: What invariant changed? What happens if the dependency is unavailable? Can this operation run twice? Which authorization path permits it? What evidence shows that old behavior remains intact?
Those questions are valuable whether the author is a staff engineer, a new hire, or an agent.
The durable advantage is understandable software
Better prompts may produce better first drafts. Better systems produce better outcomes repeatedly. A codebase with clear boundaries, executable behavior, useful documentation, and trustworthy delivery checks gives AI something far more valuable than a clever instruction: a map of how to act safely.
Build software that a careful new teammate could learn from. AI will benefit too. More importantly, the people responsible for the software will be able to move faster without losing their grip on what the system is doing, why it behaves that way, and how to change it with confidence.