AIcodingbest practicessoftware development

Guiding AI Developers to Modern Coding Practices

This post explores strategies for guiding AI developers to adopt modern, idiomatic coding practices. Learn how to foster clean, maintainable, and efficient AI codebases by leveraging best practices, design patterns, and up-to-date language features. Elevate your team's AI development standards for

·21 min read
blog cover image
Table of Contents

AI coding quality is a governance problem: models follow the clearest local pattern, not your unstated engineering standards.

01 THE PROBLEM

AI-generated code drift is the failure mode where code passes the immediate task but violates the language, framework, and operational conventions your team depends on.

The damage is rarely visible in the first pull request.

It shows up 30 to 90 days later as inconsistent error handling, duplicate abstractions, brittle tests, insecure defaults, and review queues clogged with “small” style and architecture corrections. Teams think they are accelerating delivery. What they are often doing is moving effort from authoring to remediation.

This is not mainly about code being syntactically wrong.

Modern coding agents are already good enough to produce valid code in TypeScript, Python, Go, Kotlin, Java, and Rust. The gap is that “valid” is not the bar in a serious engineering organization. The bar is idiomatic, maintainable, secure, and locally aligned with how your system actually works.

That difference matters because software quality compounds.

Nicole Forsgren, Jez Humble, and Gene Kim made the case in Accelerate: software delivery performance and organizational performance correlate strongly with engineering practices that reduce rework, improve reliability, and shorten feedback loops. AI coding can improve throughput, but only if it reduces net cycle time. If it increases review burden and production risk, you are not getting leverage. You are buying queueing delay with better demos.

The operational symptom is easy to recognize.

A team enables AI coding tools across 40 to 120 engineers. Within two quarters, code review comments become strangely repetitive:

  • “We don’t throw errors like this.”
  • “Why is this using inheritance here?”
  • “This bypasses the service layer.”
  • “This test mocks internal details instead of behavior.”
  • “This endpoint shape does not match our API conventions.”
  • “This ignores tenant isolation.”

None of these are model failures in the abstract. They are alignment failures.

The AI is optimizing for the strongest pattern it can see in the prompt, surrounding file, retrieved context, and pretraining corpus. If your local standards are implicit, fragmented, or contradictory, the model will invent a plausible path through them. It will do this confidently and at scale.

That is the central tension senior engineering leaders have to manage right now.

The fastest path to broad AI-assisted coding adoption is permissive autonomy. The fastest path to maintainable systems is constrained generation. Those two goals are in conflict unless you build explicit guidance, retrieval, validation, and review loops around the model.

If you do not, your organization gets a new class of entropy generator: a high-speed contributor trained on everybody’s defaults and nobody’s architecture.

02 WHY IT HAPPENS

It happens because AI coding agents are pattern completers operating against incomplete local truth.

That sounds obvious, but most teams still behave as if the model has a robust internal notion of “best practice” that will naturally converge with their own. It will not.

“Idiomatic” has three layers, and teams regularly confuse them.

The first layer is language-level idiom: how competent engineers usually write modern Go, Python, TypeScript, or Kotlin.

The second layer is framework-level idiom: how Next.js apps structure data fetching, how FastAPI handles validation, how Spring teams wire services, how React teams manage state, how Terraform modules are composed.

The third layer is company-level idiom: your error taxonomy, test boundaries, migration process, logging shape, auth constraints, package boundaries, feature flagging strategy, and reliability expectations.

Models can often approximate layer one.

They can sometimes infer layer two from context.

They cannot reliably infer layer three unless you make it concrete.

This is why generic instructions like “write clean, scalable, maintainable code” underperform so badly. They describe outcomes, not constraints. They leave the model free to choose among multiple equally plausible conventions.

The Stack Overflow engineering guidance on coding guidelines for AI makes this point in a pragmatic way: if a guideline can be misread, the model will eventually misread it. Predictability beats elegance. Repeated, simple phrasing beats prose that a human reviewer finds sophisticated. That is not because models are dumb. It is because ambiguity is multiplicative in generative systems.

There is also an incentive mismatch inside engineering organizations.

Developers evaluate AI coding tools on immediate task speed. Staff engineers and managers evaluate them on long-term maintainability, operational risk, and review load. Security evaluates them on policy compliance. Platform teams evaluate them on standardization. These are not the same objective function.

So adoption tends to start with the easiest metric to observe: “I finished the task faster.”

That metric is dangerously incomplete.

DORA’s four key metrics—lead time for changes, deployment frequency, change failure rate, and time to restore service—remain a better executive-level lens because they force you to account for both speed and stability. If AI assistance improves local coding speed but increases change failure rate or slows review cycles, the system got worse, not better.

There is a second structural reason this happens: your codebase probably does not express its standards in a machine-consumable way.

Most teams have some combination of:

  • tribal norms in reviewers’ heads
  • scattered wiki pages
  • stale contribution docs
  • lint rules that cover formatting but not architecture
  • examples that conflict by vintage
  • framework migrations that are half-finished
  • generated code, hand-written code, and legacy modules all coexisting

Humans survive this mess because they ask clarifying questions and build intuition over months.

Models do not “join your company” in that way. They work from the evidence presented each time. If the evidence is inconsistent, they average it. Averaging is exactly how you get non-idiomatic code.

Real engineering organizations have spent years reducing this ambiguity for humans.

Stripe is a useful reference point because many of its public engineering writings emphasize strong internal abstractions, API consistency, and quality gates. Stripe’s API design discipline did not emerge from taste. It came from treating consistency as a product and operational concern. AI coding amplifies the same requirement internally: if you want consistent outputs, your standards must be codified as interfaces, rules, examples, and enforcement points.

GitHub’s own guidance on AI code generation also points to a practical truth: if there is an obvious security or idiomatic improvement, the agent should suggest it. That only works when “obvious” is grounded in explicit standards. Otherwise one engineer’s “idiomatic improvement” is another team’s forbidden pattern.

The final root cause is context window economics.

Even with large context windows, the model is not reading your entire engineering culture. It is reading the subset your tool retrieves and the prompt chooses to include. That means retrieval quality matters as much as model quality. If your AI tool surfaces an old service implementation from 2022 instead of the platform team’s current reference module from 2026, the model will faithfully produce yesterday’s architecture.

This is why teams often misdiagnose the issue as “the model is weak.”

Often the model is doing exactly what the surrounding system allowed.

03 WHAT MOST GET WRONG

Most teams reach for one of three bad solutions.

The first is to rely on vibe-based prompting.

This is the most common mistake because it feels natural to experienced engineers. They write prompts like they are giving a trusted colleague high-level intent: “Use best practices,” “Make it production-ready,” “Keep it clean and idiomatic,” “Use our conventions.”

Those instructions are nearly useless unless accompanied by explicit examples and hard constraints.

“Idiomatic” for a TypeScript backend could mean throwing exceptions or returning `Result` types. It could mean classes with dependency injection or plain functions with module scoping. It could mean Zod validation at the edge or schema validation in the service layer. Without examples, the model gets to decide.

The second bad solution is over-indexing on linters and formatting.

Linters matter. Formatters matter. Static analysis matters. But they solve the shallowest layer of alignment. They catch whitespace, obvious anti-patterns, unused code, import order, maybe some type or security issues. They do not encode architectural boundaries, domain language, migration rules, or what “modern” means for your stack this quarter.

You can have a repo with perfect ESLint, Prettier, and type checks and still ship AI-generated code that violates your tenancy model, bypasses your eventing contracts, or introduces invalid retry semantics.

The third bad solution is to ban autonomy after the first ugly incidents.

This usually happens after one or two high-visibility failures: an insecure generated query, a copied legacy pattern, a brittle test suite explosion, or a production issue tied to AI-assisted code. Leadership reacts by forcing all AI usage back into low-trust autocomplete mode.

That is understandable and usually wrong.

The lesson from a bad first rollout is not “AI coding does not work.” The lesson is “we deployed a high-variance code generator into a low-governance environment.”

The cost of this misdiagnosis is significant.

You either get silent architectural decay because the agent is too unconstrained, or you get negligible productivity gains because the organization is too afraid to let the tool do meaningful work.

There are real-world analogues for this pattern outside AI.

Netflix’s famous “paved road” platform thinking exists because giving every team total freedom produces inconsistent operational outcomes at scale. The platform creates a preferred path that is easier, safer, and faster than hand-rolled alternatives. The same principle applies to AI coding: if you want idiomatic outputs, the model must be steered onto the paved road.

Cloudflare’s engineering and reliability writing makes a similar operational point from a different angle: standardization is not bureaucracy for its own sake. It is what lets you move quickly under stress without re-deciding fundamentals. AI coding increases the rate at which decisions are made. If your fundamentals are not standardized, you simply generate inconsistency faster.

A more concrete failure pattern shows up in testing.

Teams tell AI to “write tests” and celebrate because coverage goes up. Then six weeks later they discover the tests are implementation-coupled, over-mocked, slow, and noisy. The team now has more green checks and less confidence. This is not hypothetical; it mirrors a long-standing issue in human-written test suites as well. Kent Beck and the broader testing community have argued for years that test quality is about signal, not count. AI amplifies the temptation to optimize the count because generating more test files is easy.

Another failure mode is legacy pattern reintroduction during migrations.

A company standardizes on React Server Components, or adopts async Python patterns, or moves from bespoke SQL access to a repository layer, or standardizes on OpenTelemetry tracing. The migration is 40% complete. The AI tool sees old and new patterns in the codebase and produces both. Reviewers now spend time policing historical inconsistency instead of shipping.

That is expensive in a very specific way: it consumes staff engineering attention.

Staff+ engineers should be solving system bottlenecks, design risks, and roadmap-critical decisions. In poorly governed AI coding rollouts, they become human compatibility layers for model output. That is a terrible use of scarce technical leadership.

04 THE FRAMEWORK

The approach that works is not “better prompting.” It is a layered operating model: codify standards, narrow the generation space, retrieve the right examples, validate aggressively, and measure net engineering throughput.

Here is the framework.

1. Define “idiomatic” at three levels

Do not create one giant “AI coding guidelines” document.

Create three compact layers:

  1. Language rules
  2. Framework rules
  3. Repo or domain rules

Each layer should answer specific questions the model cannot safely guess.

For language rules, define things like:

  • error handling style
  • nullability conventions
  • concurrency model
  • preferred abstractions
  • testing style
  • logging and observability hooks

For framework rules, define:

  • file structure
  • request/response validation
  • state management
  • data access paths
  • side-effect boundaries
  • performance constraints

For repo or domain rules, define:

  • auth and permissions checks
  • multitenancy boundaries
  • event schemas
  • migration process
  • API compatibility rules
  • prohibited shortcuts

Keep each rule short, imperative, and paired with one “good” and one “bad” example.

This mirrors what the JetBrains guidance gets right: communicate intent clearly to avoid assumptions. In practice, the winning move is not longer prose. It is lower ambiguity.

A useful benchmark: if a new senior engineer could not follow the rule correctly on day two, the AI will not either.

2. Make standards machine-retrievable, not just human-readable

A Notion page no one retrieves at generation time is governance theater.

Put standards where tools can reliably access them:

  • `CONTRIBUTING.md` with task-specific sections
  • framework-specific `AGENTS.md` or equivalent tool instruction files
  • reference implementations in a `/examples` or `/golden-path` directory
  • architecture decision records with short summaries
  • lint and static analysis configs linked to written rationale
  • codeowners mapped to critical architectural areas

The key is proximity.

The most effective AI coding guidance is attached to the repo, package, or directory where the decision matters. A top-level 4,000-word policy document is less useful than a 200-line local instruction file sitting next to the service it governs.

GitHub, Cursor, JetBrains, and similar tools are all converging on repository-scoped instruction patterns for this reason. The model needs local truth at generation time, not a company handbook hidden behind search.

A strong pattern is to create golden path modules.

If your team wants all new queue consumers, HTTP handlers, React forms, or data migrations to look a certain way, keep one intentionally pristine example and point the tool at it. “Follow the same conventions” works when there is a canonical convention to follow.

Linear is a useful company example here. Although Linear is not publishing “AI coding golden path” playbooks publicly, their product and engineering philosophy consistently emphasize reducing decision overhead through opinionated defaults. That same product instinct applies well to internal engineering systems: make the best path the easiest path.

3. Constrain generation before you try to evaluate it after the fact

Post-generation review is expensive.

The cheaper move is to narrow the output space up front.

Constrain with:

  • exact function signatures
  • expected error shapes
  • required libraries
  • banned libraries or patterns
  • test boundaries
  • performance ceilings
  • security constraints
  • file locations and naming conventions

For example, instead of saying:

“Write a TypeScript service to fetch account data.”

Say:

“Implement `getAccount(id: AccountId): Result<Account, DomainError>`. Do not throw exceptions. Validate external payloads with Zod. Use the `accountsRepo` interface only; do not issue direct SQL. Follow `services/examples/get-invoice.ts` for error mapping and logging. Add behavior tests only; do not mock private helpers.”

That level of specificity is not micromanagement. It is how you reduce variance.

The practical rule is simple: every convention you leave unspecified becomes a model decision. If you do not want the model making that decision, specify it.

4. Encode non-negotiables into automation

If a rule matters, automate it.

Humans should not be the primary enforcement mechanism for repeatable standards.

Use:

  • formatters and linters for style
  • type checking for interface conformance
  • Semgrep or CodeQL for security policies
  • secret scanning
  • schema validators
  • API contract tests
  • architecture tests for import boundaries
  • CI checks for migration or feature-flag patterns

OWASP’s guidance on secure coding and dependency hygiene is directly relevant here. If your AI tool can emit vulnerable patterns faster, your scanning and policy enforcement need to keep pace. Security guidance that lives only in reviewer memory is too slow.

One practical threshold: if a review comment appears more than three times in a month across different pull requests, try to turn it into either a machine-enforced rule or a retrievable generation instruction.

That threshold is not from a published standard. It is an operator heuristic. It works because repeated review comments are evidence of latent policy.

Shopify’s engineering culture has long favored guardrails and platform conventions that let many teams move independently without re-solving common infrastructure decisions. AI coding pushes organizations toward the same posture. The scale might be smaller, but the governance logic is the same.

5. Separate low-risk autonomy from high-risk autonomy

Not all code deserves the same freedom.

Create explicit autonomy tiers.

A simple four-tier model works:

  • Tier 0: autocomplete and single-function edits
  • Tier 1: isolated tests, docs, refactors, glue code
  • Tier 2: service endpoints, internal tooling, non-critical product logic
  • Tier 3: auth, billing, infra, migrations, data deletion, security-sensitive paths

At Tiers 0 and 1, allow broad AI generation with lightweight review.

At Tier 2, require repository instructions, reference examples, and stronger CI gates.

At Tier 3, require human-authored design intent, mandatory codeowner review, and in many cases generation limits to scaffolding rather than full implementation.

This is how adults operate production systems: by blast radius, not ideology.

Google’s SRE book institutionalized this thinking around risk, guardrails, and error budgets. AI coding should be governed the same way. The question is not “Do we trust the model?” The question is “What is the blast radius if this pattern is wrong?”

6. Measure net effect with engineering and operational metrics

If you only measure acceptance or usage, you will fool yourself.

Track at least six metrics for AI-assisted code paths:

  1. review iterations per PR
  2. time from first PR to merge
  3. post-merge defect rate
  4. rollback or hotfix rate
  5. test flake rate introduced
  6. percentage of comments tied to conventions vs logic

Anchor this to DORA where possible:

  • lead time for changes
  • change failure rate
  • time to restore service

If AI coding adoption increases code output by 25% but change failure rate rises materially, the system is worse.

Use a 6- to 12-week window per team. Shorter than that and novelty effects dominate. Longer than that and you lose the ability to tie changes to interventions.

A practical benchmark from DORA and Accelerate thinking: optimizing speed without guarding reliability usually backfires. High performers do not trade one permanently for the other. They improve both through better systems.

This is where many pilot programs fail. They report prompt count, lines generated, or self-reported developer satisfaction. Those are weak proxies. CTOs should care about merged throughput and production stability, not token volume.

7. Invest in reference implementations more than prose

The highest-leverage artifact is not a policy document. It is a small set of excellent examples.

Create canonical examples for:

  • a new endpoint
  • a background job
  • a migration
  • an integration test
  • a frontend form
  • a repository or data access object
  • an event publisher/consumer

For each, include:

  • directory structure
  • imports
  • validation
  • error handling
  • telemetry
  • test shape
  • comments on tradeoffs

Figma, Vercel, and HashiCorp have all published engineering content over the years that reflects a strong preference for clear, composable patterns and tooling conventions. That matters because examples teach architecture faster than prose. AI models respond the same way. Show the desired shape in code and you reduce ambiguity dramatically.

A useful internal standard is: every major platform pattern should have one canonical example updated within the last quarter.

If your examples are older than your current architecture, they become liabilities.

8. Use migration maps during transitional periods

Most codebases are in-between states.

That is where AI generates the most inconsistency.

During migrations, create explicit maps:

  • old pattern
  • new pattern
  • when old is still allowed
  • when old is forbidden
  • how to upgrade old call sites
  • what examples to follow

Without this, the model sees both patterns and treats both as valid.

This matters especially during framework transitions:

  • REST to typed RPC
  • class components to function components
  • synchronous Python to async
  • custom metrics to OpenTelemetry
  • direct SQL to a data access layer
  • ad hoc retries to a resilience library

Cloudflare and GitHub both operate at scales where migrations require codified compatibility periods and tooling support. You do not need their scale to copy the discipline. You need it because AI will happily resurrect deprecated patterns forever unless told otherwise.

9. Build reviewer checklists that focus on what machines miss

If your reviewers are still spending most of their time on syntax, style, and obvious framework misuse, your pipeline is under-automated.

Review checklists for AI-assisted code should focus on:

  • domain correctness
  • failure behavior
  • authorization boundaries
  • observability completeness
  • backward compatibility
  • operational safety
  • abuse and edge-case handling

That is where humans add the most value.

This shift is important organizationally. It changes review from line-editing to risk assessment. That is a better use of senior engineering time and a more scalable operating model.

10. Treat prompt and instruction quality as production assets

The highest-performing teams will end up with maintainers for internal AI coding guidance.

Not because prompts are magical, but because instruction sets, examples, retrieval sources, and policy hooks become part of your software delivery system.

Version them.

Review changes to them.

Measure their effect.

Retire stale instructions aggressively.

If a guideline changes behavior in 80 pull requests per week, it is not “just documentation.” It is production infrastructure for code generation.

05 STRATEGIC TAKEAWAY

The strategic move is to stop treating AI coding as an individual productivity tool and start treating it as a software supply chain input. If you make that shift this quarter, you can increase delivery speed without accepting uncontrolled architectural drift. If you do not, the likely outcome over the next two quarters is familiar: local gains in coding speed, rising review friction, more inconsistency during migrations, and staff engineers pulled into janitorial alignment work. The CTO decision is not whether to allow AI coding. It is whether to invest 4 to 8 weeks now in standards, examples, and enforcement so the next 12 months of generated code compound in your direction instead of against it.

06 IMPLEMENTATION ANGLE

Start with one repo, one language, and one medium-risk workflow.

A strong first candidate is an internal service in TypeScript, Go, or Python where the team already has decent tests and active maintainers. Spend two weeks building a minimal control plane: repo-scoped instructions, five canonical examples, CI checks for non-negotiables, and a reviewer checklist focused on domain and operational risk. Then compare AI-assisted pull requests against a prior baseline on merge time, review iterations, and convention-related comments.

Do not begin with your most critical systems. Do not begin with a company-wide policy memo. Begin where you can produce a visible before-and-after and learn what your actual ambiguity looks like. In practice, teams discover that 60% of the friction comes from just a handful of unclear conventions: error handling, tests, data access, and auth boundaries. Fix those first. related topic

If you are scaling from 30 to 150 engineers, this becomes part of engineering enablement, not just developer tooling. One brief but practical org note: Amplify helps engineering teams scale, but the important point is broader than any vendor—growing teams need codified standards that survive onboarding, reorgs, and tool changes. AI coding simply makes the cost of not having those standards show up faster.

07 FAQ

Q: How do you get AI coding tools to produce idiomatic code consistently? A: You constrain the generation space with explicit conventions, canonical examples, and machine-enforced rules. Generic prompts like “write clean, idiomatic code” underperform because models choose among multiple valid conventions. JetBrains’ guidance on AI coding guidelines makes this explicit: clear intent reduces assumptions, and repository-local instructions work better than abstract style guidance. Q: What is the biggest reason AI-generated code feels wrong even when it works? A: The biggest reason is missing company-specific context. Models can often approximate language idioms, but they cannot infer your local decisions about error handling, auth boundaries, logging, migrations, or test shape unless those are documented and retrievable. Stack Overflow’s 2026 guidance on coding guidelines for AI argues for simple, repeated, low-ambiguity rules for exactly this reason. Q: Should engineering teams rely on linters and code review to control AI-generated code quality? A: No. Linters and formatting catch surface-level issues, but they do not enforce architecture, domain rules, or operational safety. The better model is layered control: static analysis, contract tests, security scanning aligned with OWASP guidance, and reviewer focus on logic, risk, and system behavior rather than style corrections. Q: What metrics should a CTO track to know whether AI coding is helping or hurting? A: Track lead time for changes, change failure rate, and time to restore service using DORA’s framework, then add review iterations per pull request and post-merge defect rate for AI-assisted changes. If coding feels faster but review cycles lengthen or change failure rate rises, the rollout is not working. Usage volume and lines of code generated are weak metrics because they do not measure net engineering throughput. Q: Which code should never be left to high-autonomy AI generation? A: High-blast-radius code should never be generated with loose autonomy: authentication, billing, infrastructure changes, destructive migrations, permission checks, and deletion workflows. The Google SRE book’s risk-based approach applies here: govern by blast radius, not enthusiasm. For these paths, require human-authored intent, stronger codeowner review, and tighter generation constraints or scaffolding-only use.

Enjoyed this article?

Share it with your network

LatAm Engineering Insights

Stay ahead of the curve

Weekly insights on hiring LatAm developers, salary trends, tech stack analysis, and exclusive job opportunities.

No spam, unsubscribe anytime. We respect your privacy.

Salary Insights

Real market data on LatAm developer salaries

Hiring Tips

Best practices for remote LatAm teams

Exclusive Roles

Early access to new job opportunities

Join 2,500+ CTOs, Engineering Managers, and Developers