OOPing my code
I built a quick and dirty app to iron out the DCOM issues. Now I've got to make it readable, maintainable and bug-proof.
1] Currently, all database access is through a class - I'm not sure how to name this class - it doesn't seem right to simply name it 'Database'. At the moment I'm calling it 'DBAccess'.
It's not that naming it is any big deal, it's just that I've learned that OOP is so elegant, particularly at facilitating self-documenting code, that, when I have trouble naming something, it causes me to wonder if I have a conceptually cloudy understanding of the object.
So, I'm *pretty sure* that the entire database and its access procedures should be wrapped and hidden away in a class. Yes?
2] I've got an odd class, called 'SQLQuery', that came out of not wanting to keep creating SQL strings on-the-fly every time I wanted to add/delete/update. So, I create an instance of this SQLQuery object, use VB's 'With' to pass it a pile of properties, and then, when I call for it, it returns to me a well-formed SQL 'SELECT' string.
I'm just not sure this is how I'm supposed to build this object (i.e. as a class, as opposed to, say, a structure/type). Also, should it be a *subset* of the DBAccess class?
3a] I have a whole pile of procedures that read and write to/from the 'Datagrid' control on the webpage. Should all my procedures on this control be a separate class? Or are these procedures intimately tied with the form that the control is on? In other words, are the control (AND the asp webpage it sits on) AND the procedures for the control - all part of one class?
3b] And if they *are* all part of one class, then that class should not be the first code hit on launch. I should be starting in a separate module configured as the start page, from which I subsequently open the form and its control and procedures. i.e, I treat the entire interface as just a single, minor component of the overall app. Correct?
I tried adding Module1.vb (the .NET equivalent of the old VB6 Module1.bas), but I cannot set Module1.vb as the start page. If I'm running some initial code that *calls* the webpage, where would I put the initial code?
Dave,
I'll try and address your questions from the top-down.
1]
This is a big question, with many potential answers, and is largely contextual.
The class name usually describes what the class represents, or what its purpose is in the system. There is no real hard-and-fast rule for class naming. Often times, the choice of a name comes down to the context in which you are developing.
For example, if you need to support multiple databases, then "Database" would be a good name for a base class that handles interaction with a database of some kind. Using inheritance, you can create subclasses to handle specific DBMS vendors. You might have "SQLServerDatabase" and "OracleDatabase" classes that derive from "Database".
On the other hand, if your situation does not require such complexity, then "Database" would be a perfectly good name for a class that encapsulates data access. It might only support one DBMS vendor, and could be responsible for constructing SQL strings, managing connections, issuing commands, and so on.
However, you could just as easily call the class "DataAccess" without losing anyone on what the purpose of the class might be.
I'm not sure exactly what you're after for this class, but you might want to take a look at the "Enterprise Library" which can be found from Microsoft's "Patterns and Practices" web site (http://msdn.microsoft.com/practices/). I know that there is a "Database" class in there that wraps a lot of common functionality if you're using ADO.NET for data access. The code for the library is freely available, and might serve you well as a point of reference.
2]
Microsoft's documented guidelines for whether to use a reference type (class) or value type (structure) state that you should only use a structure if your type supports the following cases:
-
It logically represents a single value, similar to primitive types (integer, double, and so on).
-
It has an instance size smaller than 16 bytes.
-
It is immutable.
-
It will not have to be boxed frequently.
Since writing SQL is not that painful, I'm assuming that you're writing the same SQL statements in multiple places in your code? That could be painful, but a "SQLQuery" class doesn't seem like it'd fit the bill in that case. If it's a case of writing the same SQL code in multiple places, then create a separate class to encapsulate the different SQL statements. It might then pass the SQL code on to an instance of your "Database" class for processing. In this case, I don't think "SQLQuery" would be a good name. If you choose "Database" for the name of your class from (1) above, then "DataAccess" would be a well-suited name for this query-encapsulating class (or set of classes, if you have logical groupings of SQL queries).
I'm guessing that your problem might also be that you've got SQL code scattered throughout your application that does very similar things. One thing you should try to do to consolidate some of the query logic is return back a consistent set of results from database queries. For example, if you've got a table in the database called "Employee", with fields called "FirstName", "LastName", and "UserID", stay away from creating separate queries to return "FirstName" and "LastName" for one part of the application and "UserID' for another part. Instead, write one set of queries that return the same fields, but differ in their selection criteria in the "WHERE" clause. You could then create a DataAccess derived class called "EmployeeDataAccess". This class could return a strongly-typed DataSet that holds the employee query result set. Examples of this kind of thing can also be found on the "Patterns and Practices" web site.
I'm running short on time, so I will try and address 3a and 3b at a later time if you're interested. Also, if you'd like some general guidelines on developing software in .NET, check out these URLs:
Application Architecture Guidance:
http://msdn.microsoft.com/practices/apptype/distapps/default.aspx?pull=/library/en-us/dnbda/html/distapp.asp
Enterprise Library:
http://msdn.microsoft.com/practices/apptype/distapps/default.aspx?pull=/library/en-us/dnpag2/html/entlib.asp
Enterprise Software:
http://msdn.microsoft.com/practices/apptype/distapps/default.aspx?pull=/library/en-us/dnpatterns/html/esp.asp
Some excellent information on OO design in general can be found at:
OO Design Principles (read the design principles [PDF]):
http://www.objectmentor.com/courses/pood
Design Patterns (book):
http://www.amazon.com/gp/product/0201633612/103-9442038-6299007?v=glance&n=283155&n=507846&s=books&v=glance
Refactoring (book):
http://www.amazon.com/gp/product/0201485672/ref=bxgy_cc_img_b/103-9442038-6299007?%5Fencoding=UTF8
Ryan Kinderman wrote: |
| On the other hand, if your situation does not require such complexity, then "Database" would be a perfectly good name for a class that encapsulates data access. It might only support one DBMS vendor, and could be responsible for constructing SQL strings, managing connections, issuing commands, and so on. However, you could just as easily call the class "DataAccess" without losing anyone on what the purpose of the class might be.
|
|
Yeah, I think I'm OK here
Ryan Kinderman wrote: |
Since writing SQL is not that painful, I'm assuming that you're writing the same SQL statements in multiple places in your code? That could be painful, but a "SQLQuery" class doesn't seem like it'd fit the bill in that case. If it's a case of writing the same SQL code in multiple places, then create a separate class to encapsulate the different SQL statements. It might then pass the SQL code on to an instance of your "Database" class for processing. In this case, I don't think "SQLQuery" would be a good name. If you choose "Database" for the name of your class from (1) above, then "DataAccess" would be a well-suited name for this query-encapsulating class (or set of classes, if you have logical groupings of SQL queries).
|
|
Let's see, I'm continually pulling from the same db, in fact, for the most part, from the same table. I usually return one or all columns, I filter on a value in a single columns and I order. I got tired of typing SQL hardcode, single quote, double quote, VB variable, double quote, single quote, so I decided to just write it once.
In my DBAccess class, I have this function:
Public Function GetData(ByVal sTable As String, Optional ByVal sColumn As String = "*", Optional ByVal sFiltCol As String = Nothing, Optional ByVal sFiltVal As String = Nothing, Optional ByVal bFiltOut As Boolean = False, Optional ByVal sSortCol As String = Nothing, Optional ByVal sSortDir As String = Nothing) As ArrayList
which I call from my code like this (filter on a value):
servers = DB.GetData("Servers", "URL", "Role", "edge")
or this (return all data in table):
PubPtFamilies = DB.GetData("PubPt_Families", , , , , "Creation_Date", "DESC")
My SQLQuery class contains a bunch of properties
(Table,FilterCol, FilterVal, FilterIn/Out, OrderCol,ASC/DESC,...)
and a function called
Assembled()
I use it like this:
With SQLStr
.setReturnColumn = sColumn
.setTable = sTable
.setFilter(sFiltCol, sFiltVal, bFiltOut)
.setOrder(sSortCol, sSortDir)
End With
dbCommand.CommandText = SQLStr.Assembled
This just doesn't feel right.
Ryan Kinderman wrote: |
|
I went looking for this but found no PDF there.
You could possibly call you class something like DataAccessLayer, DataAccessLayerComponent or dalc.
| I went looking for this but found no PDF there. |
|
Under the "Articles" header on that page, the following links are available:
The Dependency Inversion Principle
Granularity -- Packaging Principles
The Interface Segregation Principle
The Liskov Substitution Principle
The Open Closed Principle
Stability -- Package Dependency Principles
| This just doesn't feel right. |
|
Seriously, read the Microsoft link on software architecture, and pay attention to how they utilize data access classes and strongly-typed DataSet classes to encapsulate queries to the database. It doesn't seem like you need a class like SQLQuery. All you're doing with that class is accounting for unorganized data access by minimizing the work required to write queries. Your data access is still unorganized -- SQLQuery does nothing to fix that, just saves you on some typing.I will agree with you, however, that writing string literals in VB is a pain. It's probably the most painful language to do string literals in that I've ever used. You could always switch over to C#, string literals are a breeze with that. This pain in typing string literals should not be a motivation for your design, however. It has caused you to concentrate on designing to account for the things that annoy you about the language you're coding in, as opposed to designing for things that will help your system be more maintainable.
Let me know if you have any further questions.
Regards,
Ryan Kinderman