A frequent question not only for beginners in writing object-orient code is about how big a class should be. How many lines, methods, members, class constants and so on make up a class definition. My short answer is always that classes should be as short as possible to keep them manageable and maintainble.

There is no absolute limit for methods or members, but there are a few rules of thumb I consider when writing new classes or refactor existing ones.

Single responsibility

A class should follow the single responsiblity principle. It is the first of the SOLID principles and it is the most important one. Robert C. Martin says this:

“There should never be more than one reason for a class to change.”

He defines responsiblities of a class in their reasons to change. You need to change them when you extend your software to support a new feature in your codebase. So what he means is that if a class is responsible for more than one business feature it needs to be split to separate those reasons to change it.

Consider the following BAD example:

class ReportWriter
{
    public function write(FormattedReport $report)
    {
        ...
    }

    public function format(RawReport $report): FormattedReport
    {
        ...
    }
}

One would have to change that class in the following scenarios:

  • the business wants the formatting of reports to be changed
  • the implementation of write() changes

To resolve this problem, one should build a ReportFormatter class that handles formatting of the report so when that has to change, the writer has to remain the same and not be changed.

Rule of thumb: classes should follow the Single Responsibility Principle

public methods define implicit interfaces

All the public methods of a class define it’s implicit interface to outside modules and code. Even if you don’t define explicit interfaces a client of your class could call those methods and interact with your class through them.

Once a client uses them, they can’t be changed or removed that easily, especially if you provide these classes in a library for other software developers to use. Be sure to keep them public methods at a minimum and provide a nice, clean and concise interface for the client code to use.

Also keep in mind, that those public methods define the behavior and how one can interact with that class. You should definitely write unit tests for the behaviors of your class.

Rule of thumb: the less public methods, the better.

Complicated tests = complicated classes

Another hint on too big and overly complex class implementations can be found in your tests folder. Tests are a good mirror for the code that is being tested and often reveals complex and hard to grasp classes. You should strongly consider to redesign and refactor them.

Tests should be as clean and concise as the implementation itself. While test code may not end up in production, it will definitely make you trust a lot more in the class performing correctly in production.

Rule of thumb: keep your tests clean and concise to build clean and concise classes

Conclusion

These are my three more or less simple rules of thumb that I find very helpful when writing software components. It’s not always easy to write short and clean classes without “over-architecturing” things (i.e. build too much small classes) but they give a good starting point to build robust and maintainable software.