Default to Programming Convention
- 2 minutes read - 382 wordsTrying to enforce unconventional coding preferences on a team is an uphill battle. When in doubt, default to convention.
Contrived Example
Consider this contrived example. Imagine that you don’t like Ruby on Rails delegators, which let you call a method on an instance through another instance. Here’s an example:
class Greeter < ActiveRecord::Base
def hello
'hello'
end
end
class General < ActiveRecord::Base
belongs_to :greeter
delegate :hello, to: :greeter
end
General.new.hello # => "hello"
.hello
is not defined on class General
, yet we can call it because it
is delegated to Greeter
. Pretty cool!
Perhaps you don’t like this abstraction and would prefer that anytime hello
is called, it’s done explicitly on the greeter
instance:
General.new.greeter.hello # => "hello"
Maybe you don’t like this abstraction, or you want each developer to “know”
where .hello
is defined by seeing the greeter
instance in the code.
So you make a rule: no delegators. You advocate for this more verbose style and ask for it in code reviews.
The Problem With Abandoning Convention
The problem with this preference is that delegators are a Ruby on Rails convention. They’ve been in the standard library for a long time. Everybody knows how they work. They’re uncontroversial.
And so, your programmers are going to use them, and your preference is inviting
inconsistency. Programmers may follow the desired pattern in existing code,
where examples of your preference exist, but they’ll forget to on new files.
Unless you’re watching every PR or have installed supervisory tooling,
delegate
will start to popping up in your code. Why? Because it’s a
convention.
Conventions exist for a reason. In this case, delegators support an idea that’s
at least worth considering: the Law of Demeter. A template or programmer
shouldn’t have to know that .hello
isn’t defined on General
; that’s an
implementation detail. Or maybe you move .hello
into General
. No calls to
.hello
have to change if you’ve used a delegator.
Forbidding delegators in your code is opting out of a solution that solves a real problem. Are you certain you want to say they are never allowed?
Conclusion
If you’re going to buck convention, you must:
- Have a great reason
- Be willing to continually fight that battle
- Accept the features and patterns you’re giving up
How does this advice align with your experience?