The AI coding pattern spreading through engineering teams

Plan. Context. Execute. Review: Why structure beats vibe coding every time

Most developers approach AI coding tools like magic wands, throwing vague instructions at them and hoping for optimal results. However, developers who consistently achieve excellent outcomes from AI follow a structured methodology.

The difference between vibe coding and structured AI development

  • Providing unclear instructions like "Hey Claude, can you make this payment flow better?"

  • Accepting whatever the AI suggests without proper context

  • Iterating through random solutions until something appears to work

  • Fighting the AI when it fails to understand your architecture

This pattern doesn’t scale. It increases PR churn, breaks layered ownership and confuses reviewers.

Structured AI Development on the other hand follows the Plan, Context, Execute, Review pattern

Structured AI development

Lets walkthrough the 4 step process mentioned above with a refactoring example: “Refactor PaymentStrategy to support a new StripeV2Strategy, behind a feature flag.“

Step 1: Plan your approach

Before touching any AI tool, spend 5 minutes defining these three elements:

Specific goal

Bad: "Hey Claude, can you make this payment flow better?"
Good: "Refactor payment validation to use the new StripeV2 API while maintaining backward compatibility"

Success criteria

Bad: Vague hopes that "it works better"
Good: "All existing tests pass, new validation rules applied, error handling improved"

Clear constraints

Bad: No boundaries mentioned
Good: "Cannot modify the PaymentController interface, must support both old and new webhook formats"

Copy this planning template:

=== PLANNING TEMPLATE ===

Objective:
- [Specific technical goal in one sentence]

Success Criteria:
- [Measurable outcome 1]
- [Measurable outcome 2] 
- [Measurable outcome 3]

Constraints:
- [Technical limitation 1]
- [Integration requirement 1]
- [Performance/security requirement 1]

This 5 minute investment prevents the “AI slop” iterating through random solutions.

Step 2: Engineer your context

This is where most developers fail spectacularly.

The wrong way: Dumping your entire codebase into the AI
The right way: Providing strategic, targeted context

Context engineering formula

Instead of overwhelming the AI with everything, use this structure:

=== CONTEXT TEMPLATE ===

Files to Include:
- [file-path] (specific line numbers if relevant)
- [related-file] (reference for context)
- [new-file] (if creating something new)

Domain Notes:
- [Business logic constraint 1]
- [Technical dependency 1]
- [Integration requirement 1]

Security/Performance Constraints:
- [Security requirement]
- [Performance requirement]
- [Logging/monitoring requirement]

Example for our PaymentStrategy refactor

Current architecture:
- PaymentService handles validation (src/services/payment.ts:45-120)
- StripeAdapter wraps API calls (src/adapters/stripe.ts)
- Validation rules in PaymentValidator (src/validators/payment.ts:30-85)

Domain Notes:
- StripeV2Strategy must support async webhook payload verification
- Retry policies configured globally in retryConfig.ts
- Customer object includes nested billing metadata requiring flattening

Security Constraints:
- Stripe secret keys injected via Vault-backed config
- Payment logs must redact PII using logger.redactFields utility

Pro tip: Point to specific functions and line numbers instead of entire files. Quality beats quantity every time.

Step 3: Execute with checkpoints

Never attempt large refactors in one shot. Break them into stages with verification points.

The Staged execution pattern

Stage 1: Add new components alongside existing ones
Stage 2: Update core logic with feature flags
Stage 3: Migrate dependent systems
Stage 4: Remove legacy code after verification

Example prompts for our refactor (Copy and amend these)

Prompt 1: Generate New Strategy

Create a new StripeV2Strategy class implementing the PaymentStrategy interface. It should:
- Initialize using config-driven credentials from configManager.getStripeV2Config()
- Implement validatePayment() using the new Stripe v2 /verify endpoint  
- Log validation events via structuredLogger.payment.v2.validate
- Support fallback error modes for transient Stripe outages (400 vs 500 handling)

Prompt 2: Feature gate Integration

Update PaymentStrategyFactory to:
- Read enable_stripe_v2_strategy from featureFlags.ts
- Return StripeV2Strategy if flag is true, else fallback to StripeV1Adapter
- Include metrics instrumentation via metrics.increment('payment.strategy.selected', { version: 'v2' })

Prompt 3: Test coverage

Extend paymentStrategy.test.ts with new tests:
- Ensure StripeV2Strategy returns valid PaymentResult
- Mock network errors to test resilience/fallback  
- Validate that toggling enable_stripe_v2_strategy routes traffic correctly

Each prompt is laser-focused on one specific outcome. No ambiguity, no room for misinterpretation.

Step 4: Review systematically (Your quality gate)

This is where you’d spend most of your time reviewing for security, business logic, validation, error handling, logging, etc

Why this framework works?

Repeatable - Any engineer can follow the same pattern
Auditable - Easier to reason about diffs and test coverage
Safe - Interfaces, metrics, logs and rollback are all considered
Reusable - Turn these into prompt libraries and templates across teams

👀 What devs should look out for.

🎧️ Listen to this while you commute.

💬 Quick question: What's the most time consuming part of your development workflow? Reply and I’ll build a tutorial to automate it.

📱 Stay connected: Follow me on LinkedIn and Twitter/X for daily AI tool breakdowns and quick wins

Thanks for reading
- Sanket