A Talk About Naming Things
A Talk About Naming Things, by Shawn McCool and Mitchell van Wijngaarden. Presented at the DPC Uncon in 2015.
Naming things is cultural.
WordPress names things differently to Drupal, which names things differently to the Java ecosystem. This is a good thing, as it means there’s scope to change things
On Interface
When the section on interfaces came up I knew what was coming. I’m totally sold on this already. It doesn’t matter that you’re working with an interface. All that matters is that you’re working with an object with certain public methods available. How it accomplishes the task is nothing to do with you - so long as your collaborator respects your contract (and you respect it’s public API e.g. don’t call public methods that aren’t in the interface) then everyone’s happy.
Instead of adding Interface
to differentiate your interface from your implementation, make your implementation more specificPaymentProcessor
and PaymentProcessorInterface
doesn’t tell me anything. StripePaymentProcessor
and PaymentProcessor
lets me infer that we’re processing payments via Stripe
On Exception
Although I’m totally on board with dropping Interface
, I’m not too sure about dropping Exception
. I think this is more about gut reaction than any educated decision.
We know that the thing we’re working with is an exception based on context
throw new MemberAlreadyRegistered
catch (MemberAlreadyRegistered $e)
class MemberAlreadyRegistered extends \Exception
This one will be a more difficult habit to shake, but I’m going to give it a go
Levels of cohesion
All code has to live alongside other code. Names help us understand how things relate to each other.
At the lowest level, all we have is a block of code. There's no context, just the raw facts about what it does. Take this code for example:
php
$i = -1;while ($i < 0){$callback($i);}
We have no idea why it loops forever, or if that's intended. It could be a bug for all we know.
That's why we have functions, which provide context
php
function loopForever() {$i = -1;while ($i < 0){$callback($i);}}function loopTwice() {$i = 2;while ($i > 0){$callback($i);$i--;}}
Related functions are generally grouped in to a class, which indicate that they're related to each other
php
class Order {public function getItemCount(){}public function markAsImportant(){}public function markAsShipped(){}}
Usually I'd expect the next level of cohesion to be a namespace, but Shawn makes a good point that it's actually the file containing the code. It's a convention in the PHP world that each file only contains one class (due to PSR-0 and PSR-4
) but this is just a convention. In other languages there's no such convention. Shawn mentions C# and Scala as examples of when you place exceptions relating to a class in the class itself.
Finally, we group things by namespace. Some projects namespace by type e.g. Repositories\PolicyRepository
, Repository\MemberRepository
etc. I've been guilty of doing this in the past. Do we really think about everything in categories?
Instead, group things by domain - Policies\PolicyRepository
, Members\MemberRepository
etc. This allows us to have Policies/Policy
, Policies\PolicyValidator
etc. You can easily view everything related to Policies in the Policies
namespace. As an added bonus, it's easier to refactor this functionality - rename namespace or extract in to another package
Conclusion
Programming is about zooming in on what’s actually happening. Removing artefacts such as Interface
and Exception
help focus on the name of things. Grouping code by domain rather than purpose helps us build a model of the real world system that we're trying to emulate.
PS
As it was an uncon talk, Shawn mentioned a few board games to break things up. I’ve played Formula D and Dead of Winter and enjoyed them both a lot. Ca$h 'n Guns has been on my list for a while (and who can say no to a game where Rafael always dies?)