The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

Null, exception or something else?

I'm looking for an advise for better ways of designing some classes.

Lets say, we need to interact with an external system. We create a connection class (either directly or through a factory, depending on a path selected below) giving username and password as parameters. Now, there realistically can be a number of outcomes:

  1) Authorisation succeeds.
  2) Authorisation fails.
  3) Non-authorisation related problem (network or external system is down, firewall, timeout etc).

In the first scenario we just return our connection object, the other two situations are slightly trickier.

Could anyone help me with the other two, please? The connection object is going to be used extensively throughout the system and likely to be "lazily initialised". Cheers!
Ivan the Immigrant Send private email
Friday, January 25, 2008
Generally exceptions should be used for exceptional circumstances.

So, item 2 on your list is not a candidate for exception, as failure of authentication is expected, and should be trivial to deal with.

OTOH, item 3 is an exceptional condition (e.g. loss of connectivity), so an exception is appropriate here.

Corollary: Lots of people seem to have lots of different ideas about this stuff, so rather than sparking another religious war, I will simply say that the above describes my approach. YMMV.
Odysseus Send private email
Friday, January 25, 2008
Odysseus, thanks, in general I totally agree, but devil is in details.

Guys, some code samples would be useful as well (C++, C#, Java, ECMAScript - whatever).

P.S. Meanwhile I have found a discussion that took place on this board over a year ago on the same topic. The discussion is excellent, but I'd rather not post the link here, since it could put an end to this one.
Ivan the Immigrant Send private email
Friday, January 25, 2008
For situation one and two I would return the connection object but have the connection contain a flag ie.

FogConnection conn = CreateConn("User","Pass")


Then you can throw an exception when an attempt is made to use a connection that failed authentication.

For situation 3 just throw an exception.
Graeme Bradbury Send private email
Friday, January 25, 2008

what happens if connection not authorised and someone attempts to use it, i.e.:

Connection conn = new Connection("","qwerty");
// not checking if (conn.IsAuthorised())...
Query q = new Query ("Can I have a beer?",conn);
Beer beer = (Beer) q.execute();

Shall it throw an exception on q.execute()?
Ivan the Immigrant Send private email
Friday, January 25, 2008
I'd say yes... if you attempt to use a non-authorised connection, throw an exception.

If you're testing, that case should only happen once, and then you'd update your code to check for authorisation first.
Eric D. Burdo Send private email
Friday, January 25, 2008
Another approach, that comes to mind is:

Connection conn = new Connection("","qwerty");

if (!conn.connect()) return;

Query q = new Query ("Can I have a beer?",conn);
Beer beer = (Beer) q.execute();
Ivan the Immigrant Send private email
Friday, January 25, 2008
You could do worse than copying the SqlConnection behavior from .Net.  It has an Open() method that throws on any failure (including authentication).  If you try to use it without Open()ing, it complains about not being open (throws).
The only thing I would add is that its use case is slightly different than yours - failed logins in sql connections (usually middleware) are less common than in your situation.  So that's a case for your Open() just returning false for failed authentication.
Brian McKeever Send private email
Friday, January 25, 2008
Cheers, guys.

BTW, the previous discussion on the programming by contract, exceptions, status codes etc:
Ivan the Immigrant Send private email
Friday, January 25, 2008
There are two design decisions that are not 100% compatible:
- "Authentication failure is expected"
- "Connection object can be lazy initialized"

In the first case you have a good idea how to handle a situation when connection was refused, e.g. retry, ask user to change credentials, work in disconnected mode, exit application etc.

In the case of lazy initialization your consuming code will expect the connection object to be available no matter what. You don't want to put null connection object check and some extra handling for that all the time it's used in the consuming code, right? So, when this expectation proves to be wrong, and connection object was not created by it's "lazy initializer",  the outcome is a NullReferenceException. If it comes to this point, a custom exception thrown from initializer would be much more informative, but in any case, the operation, which relies on a valid connection object should be interrupted.

Naturally, (almost) all the handling for the "expected authentication failure" can be placed in lazy initializer with throwing an exception as the "last line of defence".

Another solution is to have some kind of validation to make sure user can perform operation X before actually going for it. If operation X requires a connection, its validation will simply fail along with a failed attempt to create a connection. This way the number of exceptions you have to work with can be reduced to bare minimum.

Keep in mind, though, that each failed connection already means one exception ;)
Friday, January 25, 2008
...more than one orpho bug per post :( need more coffee.
Friday, January 25, 2008
connection = GetConnection()

If (connection is nothing) then

  handle the error (i.e tell users the db is down, please try    again later)



End If
No Name Send private email
Thursday, January 31, 2008

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
Powered by FogBugz