Command All the Things
You may not realize it but behind your beautiful website there are 100’s and sometimes 1,000’s of PHP classes working together within the software to make it happen. Most of this comes from the CMS but sometimes as developers we need to write some custom logic in a class specific to your website.
When we need to make custom stuff we write a class like Form
to do whatever it is we need. Then we write some functional methods for the class like Form::doSomething()
and stuff all of the logic we need into that doSomething
method. It’s a pretty fundamental way of handling things.
The problem is that as the web evolves and projects become more sophisticated you end up with class methods that are 1,000+ lines long. And if you have even a measly three equally sinful methods in the same class you now have a class that’s an unholy 3,000+ lines long! How are you supposed to debug that? Maintain it? How is a new developer supposed to fix your code a year later? It’s a terrible thing to do to people making them go through stuff like that. But it used to be we didn’t have a better way of doing it. It stems from ancient practices of procedural code.
Commands along with single responsibility principles (SRP) eliminates this problem. While Laravel didn’t create the concept of commands it certainly popularized it within the PHP community. After a decade of procedural-style colossal walls of code we finally have elegant commands in a popular framework!
While the 1,000 line monster mentioned above may be a bit over the top on average (though I’ve seen it on too many occasions) 100+ lines is certainly not (And 100 lines is at least 90 lines too much).
Commands let developers break up the components of the class method into smaller chunks that can be dispatched
from within the method.
public function doSomething($stuff) { $this->dispatch(new MakeTheStuffBetter($stuff); $this->dispatch(new FinishMakingTheStuff($stuff); }
Isn’t that example better than sifting through tons of code? The more you break up logic into these commands the better the readability and the easier it is to maintain this code. Each command in principle should only have one responsibility and as few lines as possible.
An inherited benefit of structuring things like this is that if you need to MakeTheStuffBetter
elsewhere you can easily dispatch the same command and reuse your existing code. If not for commands the code would be unreachable within a huge greedy function.
Naming conventions as you can see are very important. I’ll bet that developers and non-developers alike can guess what each step of the following example does:
class PostForm { use DispatchesJobs; public function handle($builder) { $this->dispatch(new LoadFormValues($builder)); $this->dispatch(new ValidateForm($builder)); $this->dispatch(new RemoveSkippedFields($builder)); $this->dispatch(new HandleForm($builder)); $this->dispatch(new SetSuccessMessage($builder)); $this->dispatch(new SetActionResponse($builder)); if ($builder->isAjax() && !$builder->getFormResponse()) { $this->dispatch(new SetJsonResponse($builder)); } $events->fire(new FormWasPosted($builder)); } }
The above example is para-coded slightly to emphasize the commands but taken from a real class in PyroCMS.
Because the naming of the commands is so humanized it’s easy to at least follow the gist of what the handle
method does in this example.
Note that the PostForm
class is also a command! It’s a command that is dispatching more commands. And if we follow the breadcrumbs of these commands you will see that there are commands, dispatching commands, which in turn dispatch more commands. Each command handles its single task and that’s it! If all the code within the above example’s commands were stuffed the handle method it would actually be closer to 2,000+ lines long!
You can split logic into its own classes too and I suggest that route before writing a command if possible. After you get into the habit of using commands and breaking logic into smaller chunks you can start delegating logic to classes and the implementation of those classes to commands:
class ReadFieldDefinitions { public function __construct(FormBuilder $builder) { $this->builder = $builder; } /** * Read the form input. * * @param FormBuilder $builder */ public function handle( FieldFiller $filler, FieldParser $parser, FieldGuesser $guesser, FieldDefaults $defaults, FieldResolver $resolver, FieldEvaluator $evaluator, FieldPopulator $populator, FieldNormalizer $normalizer, FieldTranslator $translator ) { $resolver->resolve($this->builder); $normalizer->normalize($this->builder); $evaluator->evaluate($this->builder); $defaults->defaults($this->builder); $filler->fill($this->builder); $normalizer->normalize($this->builder); //Yes, again. $guesser->guess($this->builder); $parser->parse($this->builder); $translator->translate($this->builder); $populator->populate($this->builder); } }
This is another modified example from PyroCMS and again if all the code was stuffed into the handle
method it would be massive. It’s a very complex procedure. Instead, logic is delegated to smaller classes that the ReadFieldDefinitions
command uses to do its job.
Functions from 20 lines to 10,000+ can all greatly benefit from commands. Your app will be healthier for it. You will be happier for it. The internet will be a better place for it.
Command all the things!