Have as many methods as you need. I would try to keep down the number of public methods to that 5-8 rule if possible. Honestly, most people have the opposite problem where they have crazy super-methods that need to be broken out more, not less. It really does not matter how many private helper methods you have. In fact, if you stayed below 8 methods in Java you could hit the limit with a class that only had a constructor, a toString, and the getter/setter for 3 properties...which is not exactly a robust class. The bottom line is, do not worry about how many methods your class is. Worry about making sure your class does not take on unrelated concerns, and that you have a reasonable public interface that has easy to understand methods.
Don't think of it as principles vs best practices. In the process of writing my book on MVVM (I would say it was a shameless plug but it's not out yet), I've come up with an analogy. Just like in art there were various movements throughout the ages, there are certain movements within software engineering. Just like you can identify a Gothic Cathedral via the flying buttresses and rose windows or a impressionist painting via its visible brushstrokes and open composition, so you can identify code that follows a certain software movement by looking for certain elements.
The MVVM movement has the View Model as its centerpiece with minimal code behind, functions encapsulated in commands, and decoupled messaging via an event aggregator. There is a beauty to the way these components are structured.
Those who follow Domain Driven Design create rich domain objects with persistence ignorance and logic embedded in the core of the objects.
CQRS proponents separate their domain models into a Query and Command model also referred to as a Read Model and a Write model. They like to use asynchronous calls via a message bus that updates the transactional store and the query store at the same time. And prefer a concept called eventual consistency.
The "best practices" of these movements aren't globally applicable, but more or less attributes that are consistent with the movement. As new movements rise to dominance and old movements fade, they won't be as prominent but that doesn't mean the techniques of one movement won't be useful with a subsequent one.
So What's a Principle
Principles, like the article said, are globally applicable no matter what movement. Think of Uncle Bob's SOLID principles. Or the Gang of Four's Composition over Inheritance. These principles are applicable almost anywhere. Almost being the keyword.
Naturally, you can't apply OO principles to Functional Programming. Well you can but they take on different forms. And once you have enough experience, you'll know when a principle doesn't apply. (You'll know if you have enough experience if you don't have to ask "Does it apply here" you'll just know that it doesn't look at the Dreyfus Model of Skill Acquisition at the Expert level, you don't need the principles...they're there but you don't rely on them for decision making).
In the same way, once you have achieved expertise using a certain approach or style of programming, you start adding your own touch to that style. For example, I and a few other MVVM pioneers simultaneously and independently "discovered" the DelegateCommand pattern (and we all called it the same thing except Josh Smith who called his RelayCommand which is practically a synonym for Delegate).
In Summary
Principles are guidance for less experienced developers to help them make decisions via rules.
"Best practices" or Code Styles are approaches to development that provide consistency and familiarity for those who follow that Style
You'll know when it's appropriate to ignore each when you "know without knowing".
Best Answer
One way of looking at cohesion in terms of OO is if the methods in the class are using any of the private attributes. Using metrics such as LCOM4 (Lack of Cohesive Methods), as pointed out by gnat in this answer here, you can identify classes that could be refactored. The reason you want to refactor methods or classes to be more cohesive is that it makes the code design simpler for others to use it. Trust me; most tech leads and maintenance programmers will love you when you fix these issues.
You can use tools in your build process such as Sonar to identify low cohesion in the code base. There are a couple of very common cases that I can think of where methods are low in "cohesiveness":
Case 1: Method is not related to the class at all
Consider the following example:
One of the methods,
Discharge()
, lacks cohesion because it doesn't touch any of the class's private members. In this case there is only one private member:_foodValue
. If it doesn't do anything with the class internals, then does it really belong there? The method could be moved to another class that could be named e.g.FoodDischarger
.In you're doing it in Javascript, since functions are first-class objects, the discharge can be a free function:
Case 2: Utility Class
This is actually a common case that breaks cohesion. Everyone loves utility classes, but these usually indicate design flaws and most of the time makes the codebase trickier to maintain (because of the high dependency associated with utility classes). Consider the following classes:
Here we can see that the utility class needs to access a property in the class
Food
. The methods in the utility class has no cohesion at all in this case because it needs outside resources to do it's work. In this case, wouldn't it be better to have the methods in the class they're working with itself (much like in the first case)?Case 2b: Hidden objects in Utility Classes
There is another case of utility classes where there are unrealized domain objects. The first knee-jerk reaction a programmer has when programming string manipulation is to write a utility class for it. Like the one here that validates a couple of common string representations:
What most don't realize here is that a zip code, a phone number, or any other string repesentation can be an object itself:
The notion that you shouldn't "handle strings" directly is detailed in this blogpost by @codemonkeyism, but is closely related to cohesion because the way programmers use strings by putting logic in utility classes.