.NET Tips and Tricks

Blog archive

Keep Methods Focused to Support Re-use

You may have seen a method that has two or three required parameters and half-a-dozen optional Boolean parameters. On investigation, you discover that the optional parameters each turn off some processing that the method would normally perform (typically, these parameters have names like NoUpdate, SkipAudit). This is evidence of a failure in designing the method.

What's happened here is that a developer originally wrote the method to do 13 things -- but then all the other developers who used that method asked for the ability to turn off some of those 13 things. So one by one, those Boolean parameters got added. And, with each new option, the code in the method became more complicated and harder to debug (or test).

It may seem like a good idea to create one method that takes care of 13 things. For instance, a method for purchasing a product might have all the code to check that the product is in stock, to decrement the quantity of the product on hand, to create a new line on an order (and create the order if it doesn't already exist), to write a log record to the audit trail, and so on. But what if a developer wants to call your method and only wants to do 12 of those 13 things? For instance, when the customer is buying a service (rather than a physical product), there's no stock to check or inventory to decrement. A developer supporting buying services will want to turn that functionality off in the purchase product method.

The "single responsibility principle" is usually discussed in terms of objects, but it's actually more obvious in methods. A method that does exactly one thing (that has a single responsibility) is probably easier to write and understand (and certainly easier to test) than a method that does many things. More importantly, that method is more useful: Developers can mix and match whatever "single responsibility" methods they need to get the result they want. So, instead of building one big method, you're better off building 13 more focused methods: A method to check stock, a method to decrement inventory, a method to create a line on the order, and so on.

But, you may say, the typical activity is to do those 13 things. If that's the case, then there's nothing stopping you from creating a new method that calls the 13 individual methods in the right order to do the "typical" thing. Developers doing the "typical" thing can call your new method (which is, by the way, an example of the Façade pattern). But developers still have the ability to mix and match the other 13 methods when they want to do something "un-typical."

Posted by Peter Vogel on 02/19/2013 at 1:16 PM


comments powered by Disqus

Reader Comments:

Thu, Feb 21, 2013 Peter Vogel Canada

Kelvin: Good points! No, I wouldn't want global variables that are shared among the methods. What I would expect is that each method would accept the parameters that it requires to do its job. And I hear your cry: That could be oodles of parameters on each method with a different combination of parameters required for each of the 13 methods--it would be a nightmare for the developer to coordinate. The right thing to do is to boil those parameters down to properties on two or three objects so that most of the methods would require one of those objects to be passed as a parameter (some methods would require two of the object and, perhaps, one or two standalone parameters). Someone using a large number of the methods (but not all 13 or they'd use the facade) would only need to instantiate and populate one or two objects and then pass them, as required, to the methods. Logging is, as you point out, a more difficult problem--logging is what's known as a "cross cutting concern." There are some environments you may be able to use aspect programming to address this (see Eric Vogel's great article at http://visualstudiomagazine.com/articles/2011/05/12/wccsp_aspect-oriented-programming.aspx). ASP.NET MVC, for instance, lets you just add an attribute to methods where you want logging to occur. There are a couple of other solutions. First, the logging method may not be broken out--instead, the methods that require logging may just create and use a Log object as needed. If the Log object is expensive to create that could be inefficient. It also would prevent methods from coordinating their use of the Log object if that's required (for instance, each method just adds an entry to the Log object which doesn't write out the entries until processing is complete). If those are issues, then the methods that require logging might require a Log object to be passed as a parameter to them. A developer calling the methods would instantiate a Log object once and pass it to the methods that require it (and the facade method would do that for the user automatically).

Wed, Feb 20, 2013 Kelvin Pennsylvania

Nice in theory, but scope considerations could make this difficult to implement in some cases. Do you really want all the variables that handle the intermediate steps between the 13 methods to be declared at the global or module level, rather than inside the method? You're potentially increasing one kind of complexity while reducing another. Or you may have an optional feature that weaves in and out of other work, such as a logger that's used sometimes, but not other times. To break up the method so that the logger can be called one level up, then work starts again, is, IMHO, making the code more difficult to read and more prone to problems.

Wed, Feb 20, 2013 Peter Vogel Canada

Igor: I have a different vision of the problem than you"re using: not 13 variations on the same method but 13 different things to do. Rather than having a single method called BuyProduct I'm suggesting that we have several methods called UpdateInventory, another method called WriteAuditLog, etc.

Tue, Feb 19, 2013 Igor Rozenberg Melbourne, Australia

Method overload could address this scenario - you could have 13 methods with the same name as long as they have different signature (i.e. set of method arguments). Another idea - wrap multiple arguments in a single class.

Tue, Feb 19, 2013 Peter Vogel Canada

I like the Curly reference! I'll have to use that the next time I talk about this topic.

Tue, Feb 19, 2013 Carl Perkins Texas

Like Curly in "City Slickers 2" said - That One Thing. :)

Tue, Feb 19, 2013 Jason

Great article!!!. I see this time and time again.

Add Your Comments Now:

Your Name:(optional)
Your Email:(optional)
Your Location:(optional)
Comment:
Please type the letters/numbers you see above

.NET Insight

Sign up for our newsletter.

I agree to this site's Privacy Policy.