简体   繁体   中英

how many classes per package? methods per class? lines per method?

I have to give a general note to some huge Java project for which I have but little visibility and I was wondering if there were any guidelines for determining:

  • what number of classes per package can be considered right, to low, or to high (this project has 3.89 classes per package, which seems a bit too small for me),
  • number of methods per class? (this project has 6.54 methods per class...
  • number of lines per method? (this project has about 7 lines per method (seems pretty good to me, maybe a bit low))

I should note that this question is only dealing with volumetry. I have a bunch of reports from quality tools (checkstyle, jdepend, cpd, pmd, ncss) that give me more vision about code redundancy, classes usage, bugs, etc.

Steve McConnell in his book Code Complete recommends about 7 methods per class and no more lines in a method then can be viewed in a single screen without scrolling.

I'm not sure about classes per package.

I would highly recommend reading Code Complete for more information on such topics.

I think stats like that are pretty useless, how does knowing the lines per method show whether its any use to the project or not; i think you should be looking more along the lines of:

  1. Do your packages encompass like classes?
  2. Do your classes work as an entity on their own?
  3. Do the methods within the classes function correctly and efficiently?

Surely other than memory usage, it doesn't matter whether the method is large or not? the other thing to look for in very protracted methods is whether the stack trace is going to be bigger than adding that functionality to a parent method. I'd be wary of measuring a projects success based on the lines of code.

Robert C. Martin, who recently released the book "Clean Code", states that the number of lines per method should be the absolutely smallest possible. Between 1-7 lines is a good rule of thumb.

There's also a good point being made in the book The ThoughtWorks Anthology, in the essay “Object Calisthenics” by Jeff Bay. He suggests 9 pretty hardcore constraints that will make you a better OO developer in the long run. Read more about them here.

To answer your specific questions, these are the constraints specifically to you: - No more than 10 classes per package - A maximum of 50 lines per class

These constraints might not be ideal for all of your real projects, but using them in a small (hobby?) project will force you into a better practice.

Unfortunately, there's no absolute (objective) notion of quality in software. Thus, there's no "right" value for these. However, here are a two (personal) obsevations:

3.89 classes/package is very low. It means you'll be battling through a complicated tree of packages.

7 Lines per method: Indeed sounds good. However, if these number was arrived at as a result of an intentional effort to reduce the line count of methods then you might have ended up with a single logical task being spread around several private methods which will make it more difficult to understand the class (in certain cases). Actually in CodeComplete-2, the author cites a research which discovered that method length is much less importance than its cyclomatic complexity and its nesting level.

A useful design guideline says that each class should only do one thing and do it well. This will not give you a fixed number of methods per class, but it will limit the number and make the class easier to comprehend and maintain.

For methods you can adopt a similar view and aim for methods that are as small as possible, but no smaller. Think of it this way: if you can split the method into two or more distinct parts it is obviously not as small as it could be. Small methods are easy to understand and by splitting the code like this you will get a better overview in high level methods and push details to low level methods.

(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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM