Skip to main content
Laravel, shipping fast.
Chapter 14 · Developer Experience

Conventions a Newcomer Can Infer

Julian Beaujardin

A convention counts only if a newcomer can guess it correctly without asking. If they have to ask, it is a secret, however well it is documented.

This is the strongest practical argument for staying close to Laravel. A developer who has worked on any Laravel application already knows where a FormRequest lives, what index and store do, and how a job is dispatched. Every convention you take from the framework is one your newcomer arrives knowing.

For the few that are your own, there are two ways to make them impossible to miss.

Generate them. php artisan stub:publish copies the templates behind every make: command into a stubs/ directory in your project. Edit them once, to add declare(strict_types=1) or a docblock your team always writes, and every class anyone generates from then on starts out following the rule. (Laravel documentation: Artisan Console › Stub Customization.)

Enforce them. The architecture test from Chapter 12 turns “controllers never call the provider directly” into a failing build. A comment that says the same thing goes stale the moment someone stops reading comments. A failing build doesn’t.

Documentation That Survives the Code Changing

Hand-written documentation is accurate on the day you write it and wrong on some day after that, and nobody can tell you which day.

Most teams answer this by scheduling documentation reviews. That doesn’t work. The review happens on a calendar, the code changes on a deploy pipeline, and the two schedules never line up. More discipline won’t fix that. Make documentation something you generate, or something that fails when it is wrong.

  • Tests are the documentation of behavior. “A 404 on delete is treated as success” is written down in Chapter 12 as a test. It can’t drift, because it runs.
  • Architecture tests are the documentation of structure.
  • Guidelines for coding agents can be generated too. Laravel Boost produces them from the packages actually installed in the project, so php artisan boost:update replaces hunting for a paragraph to fix.

What is left for prose is the part only a human can write: why. Why the delete is queued, why the driver binding is scoped. Keep those notes short and keep them next to the code they explain, in the same pull request as the change. That is the only place a documentation update reliably survives.

Errors That Tell You What to Do Next

An error message that only states the problem has done half its job. The other half is telling the person reading it what happens next.

Consumers of this API already get that: a 429 says slow down and retry, a 422 names the fields that failed, a 504 with provider_unavailable says it wasn’t your fault and retrying is reasonable.

Your own developers deserve the same from the exceptions they will meet. Compare:

Malformed provider response.
Malformed provider response: key, created_at

The second is what License::fromProvider() throws. It names the fields that failed, so whoever reads the log at night knows what the provider left out without reproducing anything, and it does so without copying the provider’s data into the log. When you write an exception message, write it for the person who will read it with no other context.

The audio could not be loaded. Try again in a moment.