1

I have a class with few methods - each one is setting some internal state, and usually requires some other method to be called first, to prepare stage. Typical invocation goes like this:

c = MyMysteryClass()
c.connectToServer()
c.downloadData()
c.computeResults()

In some cases only connectToServer() and downloadData() will be called (or even just connectToServer() alone).

The question is: how should those methods behave when they are called in wrong order (or, in other words, when the internal state is not yet ready for their task)?

I see two solutions:

  • They should throw an exception
  • They should call correct previous method internally

Currently I'm using second approach, as it allows me to write less code (I can just write c.computeResults() and know that two other methods will be called if necessary). Plus, when I call them multiple times, I don't have to keep track of what was already called and so I avoid multiple reconnecting or downloading.

On the other hand, first approach seems more predictable from the caller perspective, and possibly less error prone.

And of course, there is a possibility for a hybrid solution: throw and exception, and add another layer of methods with internal state detection and proper calling of previous ones. But that seems to be a bit of an overkill.

Your suggestions?

4
  • Since your suggestions focus on "explicit than implicit" theme, I'll try to point out the detail that you missed:The thing is - this is not exactly workaround and reaction to invalid call sequence. With internal chaining, this works like a cache - I call the method I want, and I know that only those methods that were not called before will run internally. It makes everything simpler on the outside. Commented Jul 22, 2014 at 11:11
  • Adding exceptions requires me to add another layer of code, to make sure I'm not reconnecting or redownloading data. For example: I have an object of my class passed somewhere, and don't know what state it is already. Right now, I can safely call computeResults() and everything will work. With exceptions I need to close it in try-except, call downloadData() on failure (which should itself be closed in try-except, to eventually call connectToServer()) Commented Jul 22, 2014 at 11:12
  • Maybe the solution is to have two classes: One "low level" doing the work and throwing exceptions, and another, a "cache wrapper" that keeps track of the state and what needs to be called in each case. But it's getting overcomplicated... Commented Jul 22, 2014 at 11:14
  • Or, maybe just two sets of methods? Like simpleDownloadData() and smartDownloadData() - first throws an exception, second chain-calls connectToServer() ? Commented Jul 22, 2014 at 11:17

3 Answers 3

1

They should throw an exception. As said in the Zen of Python: Explicit is better than implicit. And, for that matter, Errors should never pass silently. Unless explicitly silenced. If the methods are called out of order that's a programmer's mistake, and you shouldn't try to fix that by guessing what they mean. You might accidentally cover up an oversight in a way that looks like it works, but is not actually an accurate reflection of the programmer's intent. (That programmer may be future you.)

If these methods are usually called immediately one after another, you could consider collating them by adding a new method that simply calls them all in a row. That way you can use that method and not have to worry about getting it wrong.

Note that classes that handle internal state in this way are sometimes called for but are often not, in fact, necessary. Depending on your use case and the needs of the rest of your application, you may be better off doing this with functions and actually passing connection objects, etc. from one method to another, rather than using a class to store internal state. See for instance Stop Writing Classes. This is just something to consider and not an imperative; plenty of reasonable people disagree with the theory behind Stop Writing Classes.

Sign up to request clarification or add additional context in comments.

Comments

1

You should write exceptions. It is good programming practice to write Exceptions to make your code easier to understand for the following reasons:

  1. What you are describe fits the literal description of "exception" -- it is an exception to normal proceedings.
  2. If you build in some kind of work around, you will likely have "spaghetti code" = BAD.
  3. When you, or someone else goes back and reads this code later, it will be difficult to understand if you do not provide the hint that it is an exception to have these methods executed out of order.

Here's a good source: http://jeffknupp.com/blog/2013/02/06/write-cleaner-python-use-exceptions/

As my CS professor always said "Good programmers can write code that computers can read, but great programmers write code that humans and computers can read".

I hope this helps.

Comments

0

If it's possible, you should make the dependencies explicit.

For your example:

c = MyMysteryClass()
connection = c.connectToServer()
data = c.downloadData(connection)
results = c.computeResults(data)

This way, even if you don't know how the library works, there's only one order the methods could be called in.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.