tags:

views:

130

answers:

5

I need to derive an important value given 7 potential inputs. Uncle Bob urges me to avoid functions with that many parameters, so I've extracted the class. All parameters now being properties, I'm left with a calculation method with no arguments.

“That”, I think, “could be a property, but I'm not sure if that's idiomatic C#.”

Should I expose the final result as a property, or as a method with no arguments? Would the average C# programmer find properties confusing or offensive? What about the Alt.Net crowd?

decimal consumption = calculator.GetConsumption(); // obviously derived
decimal consumption = calculator.Consumption; // not so obvious

If the latter: should I declare interim results as [private] properties, also? Thanks to heavy method extraction, I have several interim results. Many of these shouldn't be part of the public API. Some of them could be interesting, though, and my expressions would look cleaner if I could access them as properties:

decimal interim2 = this.ImportantInterimValue * otherval;

Happy Experiment Dept.:

While debugging my code in VS2008, I noticed that I kept hovering my mouse over the method calls that compute interim results, expecting a hover-over with their return value. After turning all methods into properties, I found that exposing interim results as properties greatly assisted debugging. I'm well pleased with that, but have lingering concerns about readability.

The interim value declarations look messier. The expressions, however, are easier to read without the brackets. I no longer feel compelled to start the method name with a verb. To contrast:

// Clean method declaration; compulsive verby name; callers need
// parenthesis despite lack of any arguments.
decimal DetermineImportantInterimValue() {
    return this.DetermineOtherInterimValue() * this.SomeProperty;
}

// Messier property declaration; clean name; clean access syntax
decimal ImportantInterimValue {
    get {
        return this.OtherInterimValue * this.SomeProperty;
    }
}

I should perhaps explain that I've been coding in Python for a decade. I've been left with a tendency to spend extra time making my code easier to call than to write. I'm not sure the Python community would regard this property-oriented style as acceptably “Pythonic”, however:

def determineImportantInterimValue(self):
    "The usual way of doing it."
    return self.determineOtherInterimValue() * self.someAttribute

importantInterimValue = property(
    lambda self => self.otherInterimValue * self.someAttribute, 
    doc = "I'm not sure if this is Pythonic...")
+3  A: 

Personally, I would prefer if you make your public API as a method instead of property. Properties are supposed to be as 'fast' as possible in C#. More details on this discussion: http://stackoverflow.com/questions/601621/properties-vs-methods

Internally, GetConsumption can use any number of private properties to arrive at the result, choice is yours.

SolutionYogi
I think I get it: private properties to make my debugging and maintenance easier, but a public method to make consumption easier and more obvious. Cute.
Garth T Kidd
+1  A: 

I usually go by what the method or property will do. If it is something that is going to take a little time, I'll use a method. If it's very quick or has a very small number of operations going on behind the scenes, I'll make it a property.

Jason Down
Fortunately, all the calculations are quick. It's all trivial logic and arithmetic. It's just that there's a lot of it. As a single expression, it'd be a nightmare.
Garth T Kidd
+4  A: 

The important question here seems to be this:

Which one produces more legible, maintainable code for you in the long run?

In my personal opinion, isolating the individual calculations as properties has a couple of distinct advantages over a single monolothic method call:

  • You can see the calculations as they're performed in the debugger, regardless of the class method you're in. This is a boon to productivity while you're debugging the class.

  • If the calculations are discrete, the properties will execute very quickly, which means (in my opinion), they observe the rules for property design. It's absurd to think that a guideline for design should be treated as a straightjacket. Remember: There is no silver bullet.

  • If the calculations are marked private or internal, they do not add unnecessary complexity to consumers of the class.

  • If all of the properties are discrete enough, compiler inlining may resolve the performance issues for you.

  • Finally, if the final method that returns your final calculation is far and away easier to maintain and understand because you can read it, that is an utterly compelling argument in and of itself.

One of the best things you can do is think for yourself and dare to challenge the preconceived One Size Fits All notions of our peers and predecessors. There are exceptions to every rule. This case may very well be one of them.

Postscript: I do not believe that we should abandon standard property design in the vast majority of cases. But there are cases where deviating from The Standard(TM) is called for, because it makes sense to do so.

Mike Hofer
I'm thrilled with the debugger's behaviour with properties, particularly your top bullet: all derived values can be inspected at any time. I was shocked by how much quicker I was solving this problem. It paid off the property-ization effort 10X or more.
Garth T Kidd
A: 

I use to use methods to denote any action on the object or which changes the state of an object. so, in this case I would name the function as CalculateConsumption() which computes the values from other properties.

Ramesh
CalculateConsumption() doesn't change any state. Would you use a property in that case?
Garth T Kidd
No because its still an action on the object. while properties are used for setting / getting an object members and performing validation on them.
Ramesh
A: 

You say you are deriving a value from seven inputs, you have implemented seven properties, one for each input, and you have a property getter for the result. Some things you might want to consider are:

  • What happens if the caller fails to set one or more of the seven "input" properties? Does the result still make sense? Will an exception be thrown (e.g. divide by zero)?

  • In some cases the API may be less discoverable. If I must call a method that takes seven parameters, I know that I must supply all seven parameters to get the result. And if some of the parameters are optional, different overloads of the method make it clear which ones.

    In contrast, it may not be so clear that I have to set seven properties before accessing the "result" property, and could be easy to forget one.

  • When you have a method with several parameters, you can more easily have richer validation. For example, you could throw an ArgumentException if "parameter A and parameter B are both null".

    If you use properties for your inputs, each property will be set independently, so you can't perform the validation when the inputs are being set - only when the result property is being dereferenced, which may be less intuitive.

Joe
I provide reasonable defaults for the seven values. I could break out three into one class and four into another so the calculator only takes two arguments, but the caller would still have to supply — or at least leave alone — seven values.
Garth T Kidd