Artificial intelligence can save time when implementing a feature, proposing tests, or investigating an error. But it can also produce code that looks convincing while failing important scenarios. The problem is not always the model: it is often how we integrate its output into our development process.
Here are five common mistakes and practices you can use to reduce their impact.
1. Requesting code without defining requirements
“Create an endpoint to register users” sounds precise, but it leaves many decisions open. Which fields are required? What happens when an email already exists? Which permissions apply? How are errors returned?
Without clear requirements, the assistant may fill gaps with assumptions that do not match your application.
Better practice: provide goals, constraints, and acceptance criteria:
Implement POST /users in ASP.NET Core.
- Email is required and must be valid.
- Return 409 when the email already exists.
- Never log passwords or tokens.
- Add tests for successful registration and duplicate email.
- Before editing, identify the files you plan to inspect.
The goal is not longer prompts. It is a shared definition of done.
2. Accepting code you do not understand
An automatically generated diff is not a code review. It might contain redundant conditions, concurrency defects, inefficient queries, or changes in existing behavior.
Before integration, ask yourself:
- Which files changed, and why?
- Which assumptions were introduced?
- Were public contracts, validation rules, or permissions affected?
- Could I troubleshoot this change in production?
Better practice: inspect the diff, ask the assistant to explain decisions, and verify claims against the code and relevant documentation. Human review should be more than clicking “Accept.”
3. Trusting unverified results
An assistant saying “all tests pass” is not proof that tests ran. It may describe the expected outcome without having shell access, dependencies, or a completed execution.
Better practice: run checks and inspect actual output:
dotnet build
dotnet test
These checks are only a starting point. Depending on the project, you may also need integration tests, static analysis, security checks, and behavior verification.
When a test fails, identify the specific failure and investigate its relationship to the change. Avoid asking the assistant to “make everything green” without understanding the problem.
4. Sharing too much context or granting excessive permissions
Models may need project files to solve a problem, but that does not mean you should expose an entire repository, credentials, production customer records, or unrestricted system access.
Risks include secret exposure, sensitive-data leakage, and unnecessary actions.
Better practice: apply least privilege:
- Provide only relevant files and excerpts.
- Keep credentials and personal data out of examples and logs.
- Review permissions before allowing writes or command execution.
- Prefer test environments and synthetic data.
- Inspect third-party instructions and tooling before adoption.
More context does not always mean better context. Careful selection can improve both accuracy and safety.
5. Requesting oversized changes in one step
“Migrate the backend, update every dependency, and rewrite the tests” combines many decisions into a single request. When something fails, it becomes hard to isolate and revert the problematic change.
Better practice: make work incremental:
- Define scope and success criteria.
- Break the work into small changes.
- Implement one focused piece.
- Review the diff and run tests.
- Create a descriptive commit.
- Continue with the next piece.
Small commits are not a guarantee of quality, but they make review and recovery easier.
Diagram: from mistake to practice
This is a summary of working habits, not a system that guarantees correct code. Each project needs its own validation strategy.
Practical scenario: validate a registration endpoint
Imagine an ASP.NET Core API that must reject duplicate email addresses. A careful workflow looks like this:
| Stage | Action | Expected evidence |
|---|---|---|
| Requirements | Define duplicate-email behavior | Acceptance criterion: HTTP 409 |
| Exploration | Inspect endpoint, service, repository | Relevant files and dependencies identified |
| Implementation | Add a check and error response | Focused diff |
| Testing | Run duplicate-email test | Actual execution result |
| Review | Consider concurrency and error handling | Recorded findings and decisions |
| Integration | Approve and commit | Traceable change |
A simple “check before insert” can still fail under concurrent requests. A real implementation may also require a database uniqueness constraint and appropriate mapping of that constraint error to an HTTP response. This is exactly the sort of detail that can be missed when generated code is accepted without scrutiny.
Benefits and trade-offs
AI can accelerate repetitive work, help explore alternatives, and draft tests. Results depend on the context, available tools, and problem complexity. Suggestions may be outdated, insecure, or incompatible with your business rules.
Effective AI-assisted development retains essential engineering practices: clear requirements, reviews, reproducible tests, security, and incremental delivery.
Final thoughts
You do not need to abandon AI coding tools to reduce risk. You need a process that you can explain and verify. Define goals, inspect changes, test what matters, restrict permissions, and work in manageable increments.
AI can write the code. We remain responsible for integrating it.
The BoricuaCoder series will continue exploring the tools and decisions behind more reliable AI-assisted software development.
