Good C++ interface doesn't spell "interface"
Naming? Really?
Naming is one of Two Hard Things.
How would one name an interface in C++?
Very frequent pattern is to add a suffix to an interface name like this:
class PaymentServiceInterface {
public:
virtual ~PaymentServiceInterface() = default;
virtual void Pay(int employee_id) = 0;
};One of the perspective on this is, the name is excessive since from declaration anybody can see that the class is an interface since it has no fields, and contains only pure virtual member function declaration. The most frequent argument for such kind of naming is the client side make the fact invisible and prefix interface is more readable from the client code:
void example1(PaymentServiceInterface& payment_service) { ... }
void example2(PaymentServiceInterface* payment_service) { ... }
void example3(std::unique_ptr<PaymentServiceInterface> payment_service) { ... }As anybody clearly can see the name reflect the fact the class is an interface and should be treated as such. But, what does it mean for us? How do we have to treat the interface? Why should it be any different from any other classes?
There is nothing special about such class, it is pure abstract class and we can't make a copy of it or move it simply because we can't declare a variable of the abstract class (a.k.a. interface).
Hold on, but the client side clearly shows: All calls to the interface are polymorphic and without suffix "interface" readers wouldn't be able to understand it and that's absolutely correct:
void example4(PaymentServiceInterface& payment_service) {
constexpr int kKentBeckEmployeeId = 1
payment_service.Pay(/*employee_id=*/kKentBeckEmployeeId);
}But, is it important? I think, this is a place where naming became very important. Let's consider some practical examples of names which might be a value?
"ID" - sounds like a great wrapper for some value type with likely utility functions and invariant validations.
"string" - we all know the what the string is and it is clearly a value type.
"Options" - Would you expect to see a shared pointer to a polymorphic class in such place? I hope, not. But, things happen. Bad things.
On the other hand, we can consider the following my-guts-say-it-is-abstract kind of names:
"Service" - whether it's a network service, or client to some database, or maybe some in-process implementation of some long-running job, I am very confident, it's something abstract.
"Repository" - I don't want my class to be copied a bunch of time in such case, and I defiantly want to have some stub implementation for testing.
"Delegate" - Clearly abstract reference type.
So, when naming can give us a good hint about how to use a specific class, wouldn't it still make sense to keep "interface" prefix? It is up to you to make this decision, but here are my 2 cents on why it shouldn't be the case.
After sometime of using interfaces, people tend to ignore the prefix "interface" and it became more annoying clutter which only states very obvious things. Do the people use that interface suffix in their vocabulary ever? "Now, we are passing Extension Service Interface into this function.", Likely, the word "Interface" became redundant.
The client code spells the interface name more frequently, just because we design the systems around the abstraction and do not declare an abstraction to just ignore it later. Extra clutter to express obvious thing.
Consider the following example:
class PaymentService {
public:
virtual ~PaymentService() = default;
virtual void Pay(int employee_id) = 0;
};The interface doesn't have "interface" suffix and the name clearly states abstract behavior. Now, let's consider some client code:
class PaymentScheduler {
public:
explicit PaymentScheduler(
std::unique_ptr<PaymentService> payment_service,
std::unique_ptr<EmployeeRepository> employee_repository):
payment_service_(ABSL_DIE_IF_NULL(payment_service)),
employee_repository_(ABSL_DIE_IF_NULL(employee_repository)) {}
void Execute() {
// ...
}
private:
std::unique_ptr<PaymentService> payment_service_;
std::unique_ptr<EmployeeRepository> employee_repository_;
}and here's another version where all of the abstractions are suffixed with word "interface":
class PaymentScheduler {
public:
explicit PaymentScheduler(
std::unique_ptr<PaymentServiceInterface> payment_service,
std::unique_ptr<EmployeeRepositoryInterface> employee_repository):
payment_service_(ABSL_DIE_IF_NULL(payment_service)),
employee_repository_(ABSL_DIE_IF_NULL(employee_repository)) {}
void Execute() {
// ...
}
private:
std::unique_ptr<PaymentServiceInterface> payment_service_;
std::unique_ptr<EmployeeRepositoryInterface> employee_repository_;
}And when you successful application grows, the number of abstractions and layers where those abstractions have to pass through grows as well. And the only thin the suffix adds is a clutter.
What are the other properties of a good interface would you define?



In lot of source code in last time i see something ass:
class I_PaymentScheduler {
}
class I_Shape {
}
and soo on.