A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.
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!
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, 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.
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.
Friday, January 25, 2008
what happens if connection not authorised and someone attempts to use it, i.e.:
Connection conn = new Connection("firstname.lastname@example.org","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()?
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.
BTW, the previous discussion on the programming by contract, exceptions, status codes etc:
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
This topic is archived. No further replies will be accepted.Other recent topics
Powered by FogBugz