(note: tl;dr available at the very bottom for my real opinion)
I'm not going to quote any big name and say that's the right answer because it's always very case dependant how you do all this stuff. For example the number of methods: If you're making a control software for modern HD LCD TV's remote controller which has about 40-50 buttons, how can you break that down into classes coherently so that you only have like, say, 7 methods per class?
Personally I like to keep all the methods of one accessor level in one class which means some utility classes may end up having hundreds of methods but in my opinions it's easier to do something like StringUtil.escapeXMLspecialCharacters(someString)
than StringUtil.XML.escapeSpecialCharacters(someString)
or XMLUtil.escapeSpecialCharacters(someString)
. While these all are seemingly OK solutions, the first one thrives (at least in my mind, that is!) because it's simple and very easy way to access that method: You don't have to think if the string you're handling contains XML or XHTML or JSON or whatever, you'll just pick one method from the general group of methods and that's it.
Keeping on the previous TV remote analogy, lets assume you do split them to various classes anyway. If we allow ourselves to have 7 of such methods per class on average and manage to group the buttons on the remote to sensical groups like MenuButtons
, AdjustmentButtons
and 'NumberSelectorButtons', we end up with 8 or so classes. That's not a bad thing actually, but it gets slightly confusing easily especially if they're not divided to sensical groups with great care. Just imagine the rants around your TVRemotes'R'Us Inc. office: "Who says the power on/off button is a control button?" "Who's the joker who put volume +/- to menu buttons? PRE/CH (the button which switches between current and previous channel and/or image source) button isn't a number button!" "The guide button opens both tv guide AND navigational menu depending on context, what are we going to do with it!?"
So as you can hopefully see from this example, using some arbitrary number to limit yourself could introduce some unneeded complexity and break the logical flow of the application.
Before I throw in my last two cents, one thing about the number of lines per method: Think code as blocks. Each loop is a block, each conditional is a block and so on and so forth. What is the minimum amount of these blocks needed for a unit of code which has a single responsibility? That should be your limiter, not the desire to have "Seven everywhere." from number of classes in package, methods in classes and lines of code in methods.
And here's the TL;DR:
So, my real opinion is actually this: The number of classes in package should be fairly low. I've been lately starting to do the following but I'm not sure if I'll keep up to it:
- Package
foo
contains interfaces and other common classes for implementations.
- Package
foo.bar
contains implementation of said interfaces for function bar
- Package
foo.baz
contains implementation of said interfaces for function baz
This usually means my whole structure has a coherent (and most likely low) number of classes and by reading the top level class interfaces (and their comments) I should be able to understand the other packages too.
Methods per class: All which are needed as I explained above. If your class can't live without 170 methods, then let it have them. Refactoring is a virtue, not something that can be applied all the time.
Lines per method: As low as possible, I usually end up with 10 to 25 lines per method and 25 is a bit high for me so I'd say 10 is a good balance point for that.