Stop Vibe Coding and Start Coding Wisely

Wendell Adriel

About Me

Wendell Adriel

🇧🇷 🇵🇹
PHP and JavaScript since 2009
Laravel since 2015
Laravel Open Source Team since January

Thesis

Same tools. Two very different engineering outcomes.

Vibe Coding

  • Prompt first, think later
  • Architecture discovered while shipping
  • Fast local wins, expensive global mistakes
  • Feels productive because code appears quickly

Agentic Engineering

  • Define requirements before generation
  • Plan, sequence, implement, validate, review
  • Optimizes for reliable change, not just output
  • Turns agents into tools inside an engineering workflow

Vibe coding usually starts like this

What It Looks Like

1

Big prompt

Build me a billing retry system with retries, emails, admin UI, and tests.

2

Fast generation

The agent generates models, jobs, notifications, migrations, and some happy-path tests.

3

Requirements move

Midway through, requirements change: different retry rules per plan, no duplicate emails, and finance wants auditability.

4

Reality catches up

Now the code technically exists, but the design no longer matches the real problem.

Concrete Failure Mode

What breaks in the real world

Ops

"Why did we retry twice in 10 minutes?"

Support

"Customer email says attempt #3, admin still shows attempt #2."

Engineering

"We have tests, but only for the happy path we generated first."

To Be Fair

Vibe coding is not evil. It just has a safe operating zone.

Prototype a screen in 20 minutes
Validate if an API can support an idea
Learn a new SDK or framework capability
Explore throwaway experiments you will delete
The problem starts when prototype mode quietly becomes production mode.

Definition

Agentic engineering means the agent is not the process. The agent is a tool inside the process.

Input

Requirements, constraints, architecture, order of work, validation rules.

Execution

Scoped prompts, clean context, bounded tasks, explicit expectations.

Output

Reliable change you can review, test, ship, and maintain with confidence.

Workflow

My 7-step agentic workflow

1. Write a `REQS.md` with business rules, technical direction, and constraints.
2. Ask an agent for a plan, not for code.
3. Refine the plan for 2 or 3 rounds until the sequencing is safe.
4. Start a clean-context execution agent that follows the approved plan.
5. Start another clean-context agent to validate requirements, plan, and code.
6. Do your own code review for maintainability, conventions, and naming.
7. Only then commit, create the PR, and move into delivery operations.

Real-World Example

Subscription billing retry system

Feature Must

  • Detect failed renewals
  • Retry using configurable backoff rules
  • Notify customers after each failed retry
  • Show retry state in the admin panel
  • Stay tested and observable

Hidden Complexity

Backoff rules may depend on plan tier, gateway, or previous failure reason.
Jobs must be idempotent or retries can create duplicate charges or duplicated notifications.
Support needs a trustworthy state machine, not a pile of inferred timestamps.
Finance and compliance need a durable audit trail for every payment attempt.

Step 1

Start with `REQS.md`

# REQS

Feature:
Implement subscription payment retry flow for failed renewals.

Core Requirements:
- Failed renewals must create a retry record.
- Retry attempts must follow configured backoff intervals.
- Customers must receive an email after each failed retry.
- Admins must see retry state and next scheduled attempt.

Design:
- Subscription
- PaymentAttempt
- RetrySchedule
- RetryPaymentAction
- NotifyCustomerAboutFailedPaymentAction
- RetryPaymentJob
- BillingRetryService

Validation:
- Feature tests for scheduling and notifications
- Unit tests for backoff calculation
- Integration tests for queue orchestration

Steps 2 and 3

Ask for the plan. Refine the plan. Then trust the plan.

Planning Prompt

Given REQS.md, produce a step-by-step implementation plan.

Do not write code.
The plan should cover implementation steps and the test suite needed.
Prefer a TDD flow: define strong happy and unhappy path tests first,
then implement the smallest, simplest solution that makes them pass.
Use the available MCP tools and relevant skills, and follow the
project's established standards and conventions.

Call out:
- sequencing dependencies
- risk areas
- validation checkpoints
- data model and state transitions
- what should be tested before notifications or UI

What I Challenge in Review Rounds

State transitions

Are the transitions explicit and durable?

Retries

Are retries idempotent and safe under replays?

Admin UI

Does the UI depend on state we have not modeled yet?

Tests first

Are tests placed before risky integrations and side effects?

Job timing

Did the agent introduce jobs or orchestration too early?

Step 4

Execution becomes faster because the boundaries are already decided

final readonly class BillingRetryService
{
    public function __construct(
        private CalculateRetryBackoff $backoff,
        private RetryPaymentAction $retryPayment,
        private NotifyCustomerAboutFailedPaymentAction $notifyCustomer,
    ) {}

    public function handle(PaymentAttempt $attempt): void
    {
        $schedule = $this->backoff->for($attempt);

        RetryPaymentJob::dispatch($attempt->id, $schedule->nextAttemptAt);
    }
}

final readonly class RetryPaymentJob implements ShouldQueue
{
    public function handle(
        LoadPaymentAttempt $loadAttempt,
        RetryPaymentAction $retryPayment,
        PersistRetryState $persistState,
        NotifyCustomerAboutFailedPaymentAction $notifyCustomer,
    ): void {
        $attempt = $loadAttempt->handle($this->paymentAttemptId);
        $result = $retryPayment->handle($attempt);

        $persistState->handle($attempt, $result);

        if ($result->failed()) {
            $notifyCustomer->handle($attempt, $result);
        }
    }
}

Step 5

Ask a fresh agent to review requirements, plan, and changed files together

Review Prompt

Do a deep review of the changed files in git.

Use REQS.md and PLAN.md as the reference for what should exist.
Check for code quality issues, project standards violations,
and edge cases missing in the implementation or test suite.

Use the available MCP tools and relevant skills, and follow the
project's established standards and conventions.

Step 6

Then I still do my own review before the code earns production

Naming and boundaries

Are class responsibilities clean, readable, and maintainable a month from now?

Framework conventions

Does it feel native to the codebase, or does it look generated and slightly off?

Real confidence

Do the tests prove the risky paths, and would I actually be happy to keep this in production?

Agents help me move faster, but engineering judgment is still the final gate.

Production Readiness

Reliable change is more than passing tests

it('schedules the next retry using the configured backoff', function () {
    Carbon::setTestNow('2026-04-10 10:00:00');

    $attempt = PaymentAttempt::factory()->failedRenewal()->create();

    app(BillingRetryService::class)->handle($attempt);

    expect($attempt->fresh()->retrySchedule)
        ->next_attempt_at
        ->toEqual(Carbon::parse('2026-04-13 10:00:00'));
});

You also need observability

Structured logs

Log every retry attempt and gateway response with enough context for support and ops.

Metrics

Track retry success rate by gateway, plan, and failure reason.

Alerts

Trigger alerts when customers exceed a threshold of terminal failures.

Admin timeline

Make the admin timeline match exactly what happened in the queue.

Adoption

Which mode should you use?

Vibe Coding Is Fine When

  • You are exploring an idea, not committing to a design.
  • You can delete the output tomorrow with no business pain.
  • You are explicitly optimizing for learning speed.

Use Agentic Engineering When

  • The feature will be reviewed, tested, maintained, and extended.
  • Multiple people or systems depend on the result being correct.
  • The blast radius of bad design is larger than the time saved.

Takeaway

Stop asking AI to build the thing. Start asking it to help you engineer the change.

Write requirements
Plan before code
Execute in clean context
Review independently
Keep the human accountable for the system

Thank you

Hvala

Laravel Serbia