(Version Française: Pourquoi il faut déclarer ses classes "final")
When coding with other developers, such as in peer or mob programming, they often ask me: "Why do you declare all your classes as
final?". My response has always been that it's a good practice for me, inherited from my far experience with Delphi, where all classes are "final" by default. However, when asked why it's a good practice, I realized I needed to be more specific.
final keyword can help avoid inheritance hell which refers to large and complex class hierarchies that are difficult to navigate and understand. Inheritance can make testing and debugging more difficult, especially when dealing with complex inheritance chains and dependencies. In other words, inheritance can lead to tight coupling, increased complexity, and code brittleness.
Another issue with inheritance is that it creates a strong coupling between the base class and the derived class, making it harder to change the base class without affecting the derived classes. This can make the code harder to maintain over time.
Recently, I was making changes to a PHP library that use database terminology master/slave and I wanted to make theses modifications:
- rename methods "master" to "primary" and "slave" to "replica"
- add deprecated methods "master" and "slave" that call "primary" and "replica" methods
- add a comment to the "slave" deprecated method to explain the reasons for the change (due to negative connotations).
However the class define a property called
$slaveConnection which was declared as
protected. I would have liked to change also its name, but couldn't do so because it could be used by a child class.
I considered declaring the property as
private and using magic getter and setter to allow child class to write and read the deprecated property name, but felt that this added unnecessary complexity to solve something I'm pretty sure it doesn't exists. Although this library is open-sourced, it's not very popular, and the probability that this class is overrided by someone, lonely in a dark place, is very close to zero.
To avoid introducing breaking changes to the code, I kept this offensive name, and added a comment explaining that it was being kept for compatibility reasons, but I didn't approve of the name.
As you understand, because the class is not
final, and even though I was sure that it wouldn't be overridden, I can't make my change.
If the developer who designed this class had wrote all his classes as
final by default, I wouldn't have encountered this issue, and it's safer to remove the
final keyword only when necessary to override a class.