Engine or Library Programming

This is my third blog.  For some reason, I seem to be counting.  Anyways, I'm not going to discuss math today because truthfully it really scares me.  I'm going to discuss Engine/Library Programming. 

A Common practice of mine is to abstract the core functionality of something into its own assembly.  Sometimes this means something as simple as me taking the core business logic for a given project, putting it elegantly (or not so elegantly) into a Class Library project in VS.NET.  Recently though, I've started to really see the benefit of having a "core" or "system" assembly that contains things like configuration functions, database wrappers, encryption etc..  Base, Core Services that the entire application no matter what it is will most likely need.  I usually have a few namespaces in here, Kernel for instance  would have the database wrappers, the Encryption and the IO Wrappers (if needed).  

You may ask, why wrap the database access, two reasons.  One to simplify it a tad, and to support multiple databases (Oracle, SQL Server, Etc..) at runtime.  This is going to be important because eventually i'll sell the product this is all going into (i'll blog about this in a few months) and become very very rich.  I don't want to pass up lots of customers that wanna use different databases.

Back from the side track.  Another common namespace that would occur in my Core/Base/Engine assembly would be security.  This namespace provides the application built on top of it a single api to access security data.  Security Data is stuff like users/acls/groups/etc.. As of now this just gets stored in the database.  But having a single api to do this also allows me the flexiblity in the future of having mulitple security providers.  I could (at runtime) choose to use AD, or a DB or perhaps a file based system.  Again, flexiblity == more customers == bigger private jet.   In this security section in particular, i'm torn.  In code that's fairly low level like this it seems like there's multiple approaches regarding errors/return conditions.

You can take the Exceptions approach, and for all returns that are not a success return throw an exception of differing types.  Then its just upto the client to swallow that exception if he/she doesn't care about it.  This seems like it would be a more .net way of doing things.  The other way it can be handled is much like the Win32API does, return a status code that tells the calling application what happenend.  Let's take our security example, say the function is CreateUser(username,password,email); We could have one return code for Invalid username, another for Invalid Password, and yet a third for Invalid email.  

One benefit of doing things the API way, its faster.  There's no exception that needs to be handled here, and the exceptions can be reserved for things like Can't Connect to Database or Insufficient Priviledges etc.. One negative is that you add yet another way of checking to see if functions succeeded.  The user can't just rely on exception handling. 

This is probably the classic question of speed vs ease of use.  Here's what I'm wondering, what would the performance impact be of just going the exception route?  Going the exception route it seems would lend to a better overall design.  You'd not have to keep track of mounds and mounds of different return codes or enums.  Thoughts? 

Comments

# Darrell said:

A third reason to wrap your DB access is for security reasons. Since an assembly is the unit of security, using Code Access Security you can run a web application in a trust level other than FULL trust (i.e., medium trust) and just keep the DB access wrapper assembly as FULL trust. The SqlClient namespace actually will run in a medium trust environment, but OLEDB, Oracle, and ODBC will not, and you said you wanted to use those.

Monday, July 28, 2003 9:36 PM
# Frans Bouma said:

Having a 'full trust' element in the call chain makes every object in the call chain 'full trust'. This is because a non-full trust object can call a full trust object and therefore execute actions as if it had full trust. :) Nice huh, those 'race conditions ;)'.

Exceptions vs error codes is an old debate. I think you should look at it this way: if the method fails but shouldn't interrupt execution, report an errorcode. If the method fails and it should have an impact on the caller, throw an exception.

Also, to create fully extensible assemblies, it's probably wise to read 'Design patterns', (the 1994 version, not the C# version!) by the gang of four (GoF).

Tuesday, July 29, 2003 4:33 AM

Leave a Comment

(required) 
(required) 
(optional)
(required)