Why your class must be final

fredbouchery

Frédéric Bouchery

Posted on April 1, 2023

Why your class must be final

(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.
Image description
Using the 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.
Image description
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.
Image description
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.

In conclusion, making all classes final by default can save time for future generations of developers who will maintain the code.
Image description
(source of photos: pexels.com)

💖 💪 🙅 🚩
fredbouchery
Frédéric Bouchery

Posted on April 1, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related