views:

180

answers:

7

This one has been puzzling my for some time now.

Let's imagine a class which represents a resource, and in order to be able to use this resource one needs to first call the 'Open' method on it, or an InvalidOperationException will be thrown.

Should my code also check whether someone tries to open an already open resource, or close an already closed one?

Should code prevent a logically invalid invocation even when no harm would be done?

I think that programming this way would help writing better code at the other side, but I feel that I might be taking too much responsibility and affect reusability.

What do you guys think?

Edit:

I don't think this could be called defensive programming because it won't let a possible bad use to slip either, and another InvalidOperationException will be thrown.

+6  A: 

This is called defensive programming. That's a good programming practice because you ensure that your application doesn't crash on misbehaviour.

That some method should be called first before another method is called, is not a good programming practice. It add's a lot of complexity, which is better handled by the class itself.

This is called sequential coupling. This wikipedia article says that it depends on the context if it's a bad practice, but it shouldn't crash when handled improperly. Sometimes it's necessary to throw an exception to make things clear.

Ikke
Well not really. You use defensive programming to prevent crash when you expect possible abuse (this means whenever you interface with unknwon (ab)user on the other side of interface). However OP asked if open should just handle abuse as nothing happened. I disagree - user should be informed about something being wrong with his code (be it error code, assertion or exception). In short: handle(using defensive programming), but inform. Swallow or crash and API users will hate you.
MaR
I didn't say anything about swallowing the error. The could should be aware the error happened and take appropiate action.
Ikke
Interesting, where can I find more info about it being a bad practice?
Trap
Couln't find it at first, but now I have found it.
Ikke
+2  A: 

If your example is really the case, then the Open functionality should probably be invoked by the class's constructor.

If you consider the C++ iostream library (which is very widely used and considered quite a good example) you can call any operation on a stream class, whether it is open or not. The called function will simply return a failure indicator of some sort if the operation could not be performed. The functions must of course test the stream state in order to do this.

What you must not do is allow your programs to silently accept any old input as parameters. For example, this would be a broken implementation of strlen()

int strlen( const char * s )
{
   if ( s == 0 )
   {
      return 0;     // bad
   }
   else
   {
      // calculate length not shown
   }
}

as it fields bad inputs without causing a fuss - it should instead throw an exception or use an assert(), depending on your exact development philosophy.

anon
The Open/Close functionality is there because you might want a resource to be registered and/or declared but not fully initialized until the moment it's consumed. I like the idea of lazy initialization though and just leave the Close function :)
Trap
This is in fact how a C++ file stream object works. You can open it at construct time, or later using its open() member. However, in either case, (open or not), the stream is always in a valid state.
anon
+1  A: 

There's no substitute for taste, talent and experience in figuring out exactly how many safety checks should be in your code for best cost/benefit ratio for your organization.

A good quality APIs are expected to be fool-proof, and to guide the user with proper amount of warnings.

Sometimes, safety precautions may impair performance. Performance is one of the most counter-intuitive things in programming. Optimize with care, only when performance really matters.

Pavel Radzivilovsky
+3  A: 

This really depends on what the class actually does. In some cases failing silently is a good idea (eg, you want your DVD player to continue working, not show an error message if it opens the DVD tray that is already open) and in other cases you want as much information as possible (eg, if an airplane tries to close a door that is reportedly already closed, then something is wrong and the pilot should be alerted).

In most cases throwing an error when a logically invalid action is performed is useful for developers, so implementing those exceptions depends on who will use the code. If it is used internally for one application, then it's not vital. But if it is used by many different projects or developers, then I would look into it.

Marius
+1  A: 

If this is part of a public SDK that you're releasing to the wild, then the exposed API calls should have strong validation. It will help your 'users' (who are developers) and ensure you aren't stuck supporting usage you never intended to support.

Otherwise, I would not add such checks. I think they make the code harder to read, and these checks are rarely tested. In the past I would add a lot of code like this to make sure my code doesn't do the wrong thing. Now I write unit tests to verify my code does the right thing. The difference? I think tests are more maintainable, more readable, and they don't clutter your production code.

Frank Schwieterman
+1  A: 

In the case of opening a file that is already open, it depends on knowing the effect of the request, will it reset the current read location for example.

In the case of closing a file that is already closed, think of it as a request for the file to be put in a known state. The code doesn't have to do anything but the desired state is acheived so the code can return a success condition. This is not true if there is some sort of file buffering that needs to be taken care of or maybe an interlinked resource to coordinate, like a modem/serial port or a printer/spooler.

Step back and think of the problem in terms of the desired outcome including any side-effects.

We once put a 'logout' link on an app menu that was displayed regardless of your login status. Why? Because it only took a simple (and very short) method to handle returning you to the login screen from the login screen and saved a large number of checks to handled tracking the login status just so the 'logout' menu-item was displayed only when you were logged in.

Kelly French
IMO, if as a user I try to close an already closed stream it could mean whether I'm being too lazy checking my own state or that there's something illogical in my code too. If I wanted to request a close operation I'd rather call RequestClose() and wait for an event to occur :)
Trap
+1  A: 

logical invalid invocations should always be reported to the user in debug mode..

When compiled in release mode, your code should not throw any unneeded exceptions or do anything else which could endanger the whole application. Personally i prefer having some kind of logfile, and logging such logically invalid invocations surely will do no harm (at least when performance is not important)

smerlin