How Much Cohesion Is Enough?
Which one is better: books.del(42)
or books.book(42).del()
? I do both and I rarely can tell which one is better. The first option is shorter, while the second one is more object-oriented. The first option is more difficult to extend, while the second one is more verbose and requires more lines of code, which means a higher chance of making mistakes. Which one do you prefer?
Either one will work, of course, but the question is which design is more object-oriented? It seems to depend on the size of the object books
. If it’s small, there’s no need to get the book first, we can just delete it right there:
1 2 3 4 5 | interface Books { void create(String title); void delete( int id); void rename( int id, String title); } |
However, if it’s larger, it’s better to get the book
first:
01 02 03 04 05 06 07 08 09 10 11 | interface Book { void delete(); // Here! void rename(String title); } interface Books { void create(String title); int total(); Iterable<Book> all(); Book all(String query); Book book( int id); // Here! } |
Is there an explicit hard line between these two? Is there a strict rule or maybe the ambiguous question “Is this class large enough already?” should be answered every time by a vote?
Let’s try to give two extreme answers: 1) never large enough, and 2) always large enough.
- If a class is never ready for extracting any parts of it and turning them into new objects, we will end up with a very big class, with many attributes, methods, and long lists of arguments in almost all of them.
- If a class is always good enough for extractions, we will end up with many small classes, methods with almost no arguments, and … a better object-oriented design.
The common denominator is cohesion.
Highly cohesive classes include attributes and methods that are related to each other, while non-cohesive classes include whatever their developers decided to add, even though some elements may not really belong together. The first answer will give us a class with a very low cohesion, while the second one will produce a large amount of highly cohesive small classes.
Thus, the second option is better? Yes, it is. Smaller classes, higher cohesion, … but more opportunities to lose focus and spread functionality around too many places. “All methods in one object” is a much more popular design, even though it’s less cohesive, exactly because it’s easier to create: just put everything in one place and call it a day. Later, of course, maintainability problems will show up.
The bottom line is that there is no exact distinction between the right and the wrong design in this case. We just have to do our best to keep classes highly cohesive by decreasing the amount of methods in each of them. If there are just a few methods, no need to extract the Book
, but once the amount of methods gets bigger, the Book
is a perfect candidate for a new entity to define.
How many methods is OK?
Nobody knows, but I would suggest you question the cohesion of your class once you see more than seven methods or more than four attributes. Also, start thinking about refactoring when any of your methods (except constructors) accepts more than two arguments.
Published on Java Code Geeks with permission by Yegor Bugayenko, partner at our JCG program. See the original article here: How Much Cohesion Is Enough? Opinions expressed by Java Code Geeks contributors are their own. |