Laravel, Namespaces, and Code Smells

Namespaces offer some interesting code smells that I’ve noticed after trying out a few different organization methods, particularly with Laravel. In this article I’ll cover the following points:

Let’s look at the default namespace structure for a stock Laravel app. Say we’re writing a wep app for Acme Corp, which needs to sell Anvils. (We are using PSR-0, of course.)

+---app
   +---Events
       \---AnvilOrdered.php
   +---Http
       \---Controllers
           \---AnvilController.php
   +---Listeners
       \---AnvilOrderedListener.php
   +---Models
       \---AnvilModel.php
   +---Providers
       +---AppServiceProvider.php
       +---EventServiceProvider.php
       \---AuthServiceProvider.php
   \---Services
       \---AnvilService.php (this is a IoC bound service)

I think this structure is perfectly fine for small to medium applications. But let’s look what happens when we try to scale the application. Acme Corp wants to start selling Dynamite. We need to add code for a new CRUD lifecycle.

By CRUD lifecycle I’m referring to all the code that is required to ultimately make DB changes, like routes, controllers, validation, business logic, and queries.

@@
app
  Events
    AnvilOrdered.php
+   DynamiteOrdered.php
  Exceptions
  Http
    Middleware
    Requests
    Controllers
      AnvilController.php
+     DynamiteController.php
  Listeners
      AnvilOrderedListener.php
+     DynamiteOrderedListener.php
  Models
    AnvilModel.php
+   DynamiteModel.php
  Providers
    AppServiceProvider.php
    EventServiceProvider.php
    AuthServiceProvider.php
  Services
    AnvilService.php
+   DynamiteService.php

Adding a Dynamite CRUD lifecycle creates code that is scattered across our entire application! What if Acme Corp wants to start selling signs, concrete, wrecking balls, and rail. Will we continue to just spread logic across the entire app ad nauseam?

I have an alternative method, but first, take a look at the redundancy in the above filenames. Controllers\AnvilController is redundant; we know that everything in the Controllers namespace is a controller. Let’s just make it Controllers\Anvil. Applying this concept across all namespaces, we get the following changes:

@@
app
  Events
    AnvilOrdered.php
    DynamiteOrdered.php
  Http
      Controllers
-       AnvilController.php
+       Anvil.php
-       DynamiteController.php
+       Dynamite.php
  Listeners
-     AnvilOrderedListener.php
+     AnvilOrdered.php
-     DynamiteOrderedListener.php
+     DynamiteOrdered.php
  Models
-     AnvilModel.php
+     Anvil.php
-     DynamiteModel.php
+     Dynamite.php
  Providers
-     AppServiceProvider.php
+     App.php
-     EventServiceProvider.php
+     Event.php
-     AuthServiceProvider.php
+     Auth.php
  Services
-     AnvilService.php
+     Anvil.php
-     DynamiteService.php
+     Dynamite.php
@@
app
  Events
    AnvilOrdered.php
    DynamiteOrdered.php
  Http
    Controllers
      Anvil.php
      Dynamite.php
  Listeners
    AnvilOrdered.php
    DynamiteOrdered.php
  Models
    Anvil.php
    Dynamite.php
  Providers
    App.php
    Event.php
    Auth.php
  Services
    Anvil.php
    Dynamite.php

And it might be a personal preference, but I also prefer namespaces without plurality (App\Model vs App\Models). This is because whenever you instantiate or typehint an object, you’re always doing it singularly (new Model\Anvil vs new Models\Anvil). So let’s make the following changes:

@@
app
-  Events
+  Event
    AnvilOrdered.php
    DynamiteOrdered.php
  Http
-    Controllers
+    Controller
         Anvil.php
         Dynamite.php
-  Listeners
+  Listener
      AnvilOrdered.php
      DynamiteOrdered.php
-  Models
+  Model
       Anvil.php
       Dynamite.php
-  Provider
+  Providers
       App.php
       Event.php
       Auth.php
-  Services
+  Service
       Anvil.php
       Dynamite.php
@@
app
   Event
    AnvilOrdered.php
    DynamiteOrdered.php
  Http
    Controller
      Anvil.php
      Dynamite.php
   Listener
      AnvilOrdered.php
      DynamiteOrdered.php
   Model
      Anvil.php
      Dynamite.php
   Providers
      App.php
      Event.php
      Auth.php
   Service
      Anvil.php
      Dynamite.php

You’ll also notice that Ordered becomes repetitive across 4 different files. We can remove this repitition by inverting the namespace.

@@
app
  Event
-   AnvilOrdered.php
-   DynamiteOrdered.php
+   Ordered
+     Anvil.php
+     Dynamite.php
  Http
     Controller
         Anvil.php
         Dynamite.php
   Listener
-    AnvilOrdered.php
-    DynamiteOrdered.php
+    Ordered
+      Anvil.php
+      Dynamite.php
   Model
       Anvil.php
       Dynamite.php
   Providers
       App.php
       Event.php
       Auth.php
   Service
       Anvil.php
       Dynamite.php
@@
app
  Event
    Ordered
      Anvil.php
      Dynamite.php
  Http
     Controller
         Anvil.php
         Dynamite.php
   Listener
     Ordered
       Anvil.php
       Dynamite.php
   Model
       Anvil.php
       Dynamite.php
   Providers
       App.php
       Event.php
       Auth.php
   Service
       Anvil.php
       Dynamite.php

If you’re creating a large application, you’re going to have a lot of IoC bindings. The AppServiceProvider will become unmaintainable if it’s your only service provider, so it makes sense to split the bindings for our Services Anvil and Dynamite into their own providers.

What’s more is that by having these new service providers extend EventServiceProvider, they can also absorb the code in the existing events service provider.

@@
app
  Providers
-    App.php
-    Event.php
+    Anvil.php
     Auth.php
+    Dynamite.php
@@
app
  Providers
    Anvil.php
    Auth.php
    Dynamite.php

Yielding the following directory tree:

+---app
   +---Event
       \---Ordered
           +---Anvil.php
           \---Dynamite.php
   +---Http
       \---Controller
           +---Anvil.php
           \---Dynamite.php
   +---Listener
       \---Ordered
           +---Anvil.php
           \---Dynamite.php
   +---Model
       +---Anvil.php
       \---Dynamite.php
   +---Provider
       +---Anvil.php
       +---Auth.php
       \---Dynamite.php
   \---Service
       +---Anvil.php
       \---Dynamite.php

By removing all this redundancy, you can see that we have a new pattern: every filename is either Anvil or Dynamite. All of the logic for our CRUD lifecycles is spread equally across every directory, terminating with the exact same class names. This makes imports really difficult!

<?php
namespace Acme\App\Http\Controller;

use Acme\App\Service\Anvil as AnvilService;

class Anvil
{
...

So far, we’ve just made our lives harder! We have to alias every single import because the class names are the same! But here’s where we turn it around in our favor: if we invert the namespaces around Anvil and Dynamite- similar to what we did for the Ordered namespace above- we can reorganize the app so we not only get rid of those nasty imports, but centralize the logic for each abstraction/CRUD lifecycle!

+---app
   +---Anvil
       +---Controller.php
       +---Event
           \---Ordered.php
       +---Listener
           \---Ordered.php
       +---Model.php
       +---Provider.php
       \---Service.php
   +---Auth
       \---Provider.php
   \---Dynamite
       +---Controller.php
       +---Event
           \---Ordered.php
       +---Listener
           \---Ordered.php
       +---Model.php
       +---Provider.php
       \---Service.php

What’s more, is that classes’ use statements only import from within its own namespace. As a result, we can remove almost all of the use Acme\* statements from our application. If a class still requires a use statement to work correctly, it is a clearly visible dependency from a separate dependecy “tree”.

Here is an example of an improvement, going from Acme\App\Http\Controllers\DynamiteController to Acme\App\Dynamite\Controller

<?php // BEFORE
namespace Acme\App\Http\Controllers;

use Acme\App\Services; // boo!
// this line stinks! It's not *really* an external dependecy,
// it just lives in a separate folder!

class DynamiteController {
    private $service;

    public function __construct(Services\DynamiteService $service)
    {
        $this->service = $service;
    }
}
<?php // AFTER
namespace Acme\App\Dynamite;

// removed! this class is external dependency free!
// confidence level increased!

class Controller {
    private $service;

    /*
    */
    public function __construct(Service $service)
    {
        $this->service = $service;
    }
}

Above, we implicitly know that “Service” is the Dynamite Service because we’re in the Dynamite namespace! Any other imported services will be forced to be named explicitly in a use statement, indicating an external dependency! Let’s see what that would look like:

<?php
namespace Acme\App\Dynamite;

use Acme\App\Anvil; // clearly marked external dependency!

class Controller {
    private $dynamite;
    private $anvils;

    public function __construct(
      Service $dynamite,
      Anvil\Service $anvils
    ) {
        $this->dynamite = $dynamite;
        $this->anvils = $anvils;
    }
}

The effect probably seems minimal in this trivial example, but multiply it by the size or your application and you’ll see how far-reaching the effect can be.

At the very least, I hope you can see that rotating the orgazination of your classes can be a boon to the visibility of dependecies on a per class basis.