Posted on under Laravel by Owen Conti.
This article will go over a new naming pattern you can use for files in your web applications. While we'll mainly reference Laravel terminology, the patterns can be applied to any web framework.
Before we begin, please review and confirm you agree with the following points. If you don't agree with these points, this article may not be for you.
CRUD stands for Create, Read, Update, Delete. It was coined by James Martin in 1983. Think back to 1983, what types of applications were being built back then? I would argue that applications we build today look and function nothing like the ones built in 1983. Sure, there's some similarities, but most of the applications being built today are much more advanced than they were back then.
We can expand on CRUD to make naming in our application simple.
Let's start by reviewing a typical web request to create a new user:
web.php
routes fileOutside the flow of the request, you ideally have feature tests written for the endpoint as well.
Counting the files involved, specifically for the endpoint, we have:
Out of those 4 files, the only one that would normally be reused across endpoints is the resource/view, ie: you may have a
UserResource
returned from an endpoint that creates a user, and returned from an endpoint that lists users.
So we have 3, maybe 4 files, all related to the same request. The traditional approach to structuring these files would be:
UserController@store
StoreUserRequest
UserResource
or
users.edit
viewUserTests
There's a pattern there, but it's not very specific:
{Action}{Resource}
The devs on your team could manage their way around this. They'd need to use search and scroll techniques to find what they're looking for, but that's fine.
But life can be better.
Let's run through some hypotheticals using the above example request:
UserTests
class. Again, good luck finding what you're looking for.UserController
? We could, but now our controllers are breaking their CRUD pattern.SyncUsersController
. This feels weird because now we have a single controller breaking the CRUD pattern and what would we name the method in the controller?We can fix all of these problems by using two patterns which allow us to never think about a naming decision again:
These patterns will solve the points made in the beginning of the article:
I'm going to start with single action controllers. The premise is simple: you have one controller per endpoint. No exceptions.
Laravel has built-in support for single action controllers, I'll defer to the Laravel documentation for you to review. In short, you make a new controller like normal, but instead of worrying about what to name the method, you use PHP's magic
__invoke
method. When registering the route, you pass the controller class without defining a method and Laravel automatically calls the
__invoke
method on the controller for you.
Right away, we've taken away a naming decision for the developer. No more worrying about what to name methods in the controller.
In combination with Single Action Controllers, we also define a new naming convention for our files. This includes controllers, requests, tests, and views (both Blade and JavaScript frontend views). They key to this approach is that the naming method you choose remains consistent across all of your files. Do not flip the naming pattern for tests, for example!
The naming pattern I recommend is:
{Verb}{Subject}{Type}
, where:
Verb
: action being performedSubject
: resource being modified/accessedType
: type of file (controller, request, view, test, etc)It works well for a couple reasons:
StoreUserController
,
DeleteServerRequest
. The opposite way also works, but it doesn't read as nicely to me:
UserStoreController
,
ServerDeleteRequest
. Another argument for the
{Subject}{Verb}{Type}
approacbh is that it makes your file structure more organized, however, I think that argument is lost when you've namespaced your files by the
{Subject}
(which you should being doing!).{Verb}{Subject}{Type}
naming pattern, the
Verb
is the action, the
Subject
is the resource or collection of resources. This means we always have an action and we always have a resource.The one remaining wildcard of this approach is that you need to decide on naming patterns for your actions. For example, when you need to return a list of resources, do you call that "indexing" or "listing"? I'll leave those decisions up to you and your team, but my recommendations are to follow the default conventions of:
If you have other actions your app performs such as "syncing users" or "provisioning servers", you can just use those verbs! (Mind blowing, right??)
This is the key to this naming pattern. *You- (or your team) are in control. You decide on your set of actions/verbs that your app has to perform, and you name your files around those actions/verbs.
Let's run this approach through a bunch of different endpoints:
CreateUserController
: shows the form to create a new userCreateUserTest
: tests that assert the form is displayed correctlyStoreUserController
: stores the new user data in the databaseStoreUserRequest
: request class to validate the user sent when storing a new userStoreUserTest
: tests to ensure a new user can be saved, validation is correct, authorization/permissions are correctSyncPostsController
: syncs the posts to the 3rd partySyncPostsRequest
: validates the input to sync the posts is correctSyncPostsTest
: tests to ensure the posts sync correctly, the input data is validated, authorization/permissions are correctStarting to see the pattern? What about the ease of the naming? The names make sense, don't they? Because they're named the *exact- thing they do.
TLDR; Use single action controllers and name your files via a naming pattern of:
{Verb}{Subject}{Type}
, which corresponds to the single responsibility of the file.
After reading this article, I hope you're ready to re-consider how you structure/name your Laravel (or other web framework) files. It took Jeff Sagal months to convince me on this pattern, but once I adopted it, I've never looked back.
Hopefully you found this article useful! If you did, share it on X!
Found an issue with the article? Submit your edits against the repository.