Re: The wisdom of the object mentors (Was: Searching OO Associations with RDBMS Persistence Models)
Date: Thu, 1 Jun 2006 14:25:54 +0000 (UTC)
In article <1149165601.331313.237840_at_u72g2000cwu.googlegroups.com>,
>> For a trivial example, consider an application that needs to somehow
>> authenticate users (because different users have permission or not for
>> different parts of the functonality of the application. The user
>> information (name, password, etc) will have to be stored somewhere - a
>> relational database might be an excellent place, in particular if this
>> application is essentially a stand-alone one.
>> However, it might be that the application is intented to be integrated
>> into an existing infrastructure, that has user information stored in an
>> LDAP-accessible database; or for another example, the user information
>> might be stored in a Unix-style flat file (a la /etc/passwd).
>Yes, authentication data may be stored in older obsolete hierachial
>Using a pluggable solution is a good strategy here,
>like JAAS if you are using Java. But I have never seen any
>authentication solution were you actually get username and password
>from the store. Instead you ask a serverice if your username/password
>pair is correct or not. In this case, the interface sould not be
>between the application and the database, but between the application
>and a pluggable service.
The interface should indeed be between the application and a pluggable
service - but the database can be exactly such a pluggable service. SQL
itself is a shared, well-defined common interface that permits using many
different vendors' database implementationas as pluggable services.
In the case of authenticating a user, when using LDAP as a back-end there
might be a pre-existing 'authenticate this user in this LDAP database'
operation available, which could be used to almost directly implement out
'wrapped' user authentication service; when using a SQL RDBMS as the
back-end, we might store a one-way-encrypted version of the password in a
column of the user table, and perform authentication with a 'select name,
password from user where name = foo and encrypted_password = xh54k' query.
In the case of authenticating a user, when using LDAP as a back-end there might be a pre-existing 'authenticate this user in this LDAP database' operation available, which could be used to almost directly implement out 'wrapped' user authentication service; when using a SQL RDBMS as the back-end, we might store a one-way-encrypted version of the password in a column of the user table, and perform authentication with a 'select name, password from user where name = foo and encrypted_password = xh54k' query.Either way, we expose an interface of our own choosing to the application, which is thus insulated from the details of how we have implemented user authentication, including the type of user information database that we may or may not have available.
Consider also the case where there is additional per-user information that is in fact stored in the database (such as the location of the user's home sirectory), which we wish to retrieve and somehow use in the application. In my opinion, a good way to proceed would be to create an interface that exposes an operation to 'retrieve a given user's home directory', and to then implement that in a way that best uses the interface offered by the specific database we are using (whether by choice or by force).
>There might be other examples there some data by techical reasons need
>to be stored somewhere else but a SQL database, but that is still not
>an argument for separating all SQL statements by default.
The reason for separating SQL statements from the application code is the same reason as for generally writing functions/procedures/methods. The name of each function/procedure/method should reveal its intent, and its body should contain the implementation. The precise language or languages that the procedure is written in is fairly immaterial. I would much rather have a procedure to call named 'getUserHomeDirectory(...)' (or a method, '[user homeDirectory]' as an example in Objective-C syntax), than having to explicitly invoke whatever underlying code might be necessary; among other things, this then lets me change the body of the procedure as necessary, while keeping its interface the same. That way, I can, when I go to write application code that actually needs to authenticate a user, just use the appropriately named procedure/method/function, which leave my application code nice and readable while stating the intent of what is going on but hiding the details.
This doesn't just insulate us from having to replace SQL with something else (which might well be extremely unlikely witin the lifespan of the application and its data model), but it also insulates us from changes to the implementation details, such as, say, if someone imposed a different naming convention on tables and columns (such things have been known to happen), or the structure of the database needs to change for some other reason. (Yes, some of these things can probably be addressed using SQL Views, but the fact that a specific workaround exists doesn't invalidate the general technique.)
>Actually it would also be possible to write an own ODBC driver catching
>the SQL statements accesing the "user" table and call the LDAP database
... basically putting an SQL front-end on an LDAP database, in order to be able to use SQL as a common database interface? That's certainly one solution. My preferred solution is to define a higher-level interface that is then implemented using whatever each database's most appropriate interface is. The end result is essentially the same: There's a sihgle, well-defined interface through which we can work with the data as necessary from the point of view of the application. The main difference is that you appear to prefer putting a more generic interface in place, whereas I prefer a more specific one. There are good arguments on both sides.
> (I have done a similar solution while converting stored
>procedures to Java. The client still thinks it is calling a stored
>procedure in the database using "execute procedure abc()". But the ODBC
>realized that this is not a database call and calls the appropiate java
Cool. One could consider what you are doing as basically implementing an RDBMS with an SQL interface, which just happens to delegate a lot of its functionality to a second, pre-existing RDBMS with an SQL interface; not entirely unlike using the Facade design pattern.
// Christian Brunschen Received on Thu Jun 01 2006 - 16:25:54 CEST