XMLpitstop.com   |  VBnetexpert.com   |  Community Credit  
 
 
Pitstop Search:  
in
 
Sign in | Join | Help
 
 
  Blog
    Home  
 
  Entries By Date
 
<February 2008>
SunMonTueWedThuFriSat
272829303112
3456789
10111213141516
17181920212223
2425262728291
2345678
 
 
  Blog Categories
   
 
  Archives
    December 2008 (1)  
    November 2008 (3)  
    September 2008 (3)  
    August 2008 (3)  
    June 2008 (4)  
    May 2008 (2)  
    April 2008 (3)  
    March 2008 (3)  
    February 2008 (5)  
    December 2007 (4)  
    November 2007 (1)  
    October 2007 (3)  
 
  Syndication
    RSS  
    Atom  
    Comments RSS  

Friday, February 01, 2008 - Posts

  .NET Flea Market  
 

Objective Awareness

I mentioned self-aware objects in my previous post and that got me thinking. And like usual, it's not a new concept, but it's something that I do often and take for granted.

If you have an class and you create a new instance of it, you should assume it has everything it needs to operate. You should not have to tell a Customer object to load the customer's orders, it should know enough to do it on its own. And it should be smart enough to not do it if it doesn't need to. Like, what is up with this code?

Dim c As New Customer
c.Load(customerNumber:=10)
c.LoadOrders()
For Each o As Order In c.Orders
    Debug.WriteLine(o.OrderDate.Tostring("d"))
Next

If you were a new programmer and you didn't know about the LoadOrders method, you'd get nothing. So instead the Customer object should be smart enough to get the orders on its own. Why shouldn't it? It has all the needed data. But it shouldn't get the orders unless asked. Like why load the orders when the code is:

Dim c As New Customer
c.Load(customerNumber:=10)
Debug.WriteLine(c.CustomerName)

So you should have the LoadOrders() method in the Orders property:

Public ReadOnly Property Orders() As CustomerOrders
Get
    If _CustomerOrders Is Nothing Then
    	_CustomerOrders=new CustomerOrders(Me)
	LoadOrders()
    End If

    Return _CustomerOrders
End Get
End Property

First off, notice the property is readonly. You are never going to create the CustomerOrders object and assign it to the Customer object. The Customer object controls the life of the CustomerOrders object. Then, notice there is a private variable holding the customer orders: _CustomerOrders. This variable is scoped at the class level. If you never ask for orders, it remains as Nothing and never gets loaded. Once you ask for orders, it's loaded. The next time you ask for orders, they're already loaded and you have them right away.

I actually keep an isNew variable in my classes so if the object is new, it doesn't even try loading anything, it just creates the new object for me to populate.

That's one example of an object controlling its destiny.

 
 
 
 

Pseudo-code Design

In extremely formal programming environments, early design is done with UML diagrams. The intent is to discuss processes and steps independent of any programming language or final structure. There comes a time, though, that a programming style begins to become evident in the models. Usually this happens at around the design of the sequence diagrams.

In the sequence diagrams, the designer is indicating the objects and the calls that need to be made between objects. Again, this is supposed to be at a higher level than code, but many times it is taken pretty literally.

I'm as guilty as the worst. I try to make the sequence diagram show everything I want done to accomplish a task. It's like writing a code outline. In fact, I write pseudocode before I write the sequence diagram.

Why would I want to write the code before explaining to others how to write the code via diagram? The answer is Microsoft. Well, Microsoft is the inspiration. There isn't much doubt that when Microsoft gives you an API, it typically does a lot for you. One popular example would be the Application Blocks. The data application block compresses many lines of data access code into a single statement. Once you use it, you wonder how you got by without it.

So that's what I strive for in the design of objects. I want them to be simple and clear. I want them to do as much work as possible for the next programmer that comes along. None of this is new. But when you're coding an app, do you ever think about what another programmer would think of your objects? Would they be intuitive enough to use without generating a runtime error?

Sometimes, designing this way breaks the proper design cycle.

For example, you have a use case stating "User looks up customer record and sets user to Inactive." As the programmer, what kind of code would you like to write? I can think of a few different ways:

Dim c As Objects.Customer
c = Objects.Customer.Search("John", "Smith")
If c IsNot Nothing Then
    c.Active = False
    c.save()
End If

Or maybe:

Dim search As New CustomerLookup
Dim results() As Customers
results = search.FindByCustomerNumber(custNum)
Select Case results.length
    Case 0
	Throw New Exception("Customer not found.")
    Case 1
	results(0).InactivateCustomer()
    Case Else
	Throw New Exception("Multiple customer found for customer number.")
End Select

But the point is, you are trying to make the code as easy for the developer as possible. Because change is here to stay. What if you didn't think ahead with something like this? What possible nightmare code could you end up with?

Dim searcher As New Search
Dim results As SearchResults
searcher.Database = My.Settings.dbConnectionString
searcher.Table = "dbo.Customer"
searcher.SearchField = "CustomerNumber"
searcher.ReturnObject = GetType(Customer)
searcher.MatchType = MatchTypes.Exact

results = searcher.DoSearch
If results.ItemCount = 1 Then
    Dim c As Customer = CType(results.ReturnObject(0), Customer)
    c.Active = False

    c.Save(My.Settings.dbConnectionString)
End If

And maybe the flexibility of the "Search" object is great, but there's no way a new programmer could figure out the initialization steps to create a search. Could this have been solved using code design? Maybe. Actually, that example was written spur of the moment and I'm not entirely sure it accurately illustartes my point. You'd have to assume that the Search object used to do one thing and it got enhanced over and over to do everything. That's for another story: objects should know only what they need to.

Here's a different example. Which code seems more logical?

Dim c As New Customer
c.load(customerNumber:=10)
For Each o As Order In c.Orders
    Debug.WriteLine(o.GrandTotal)
Next

or

Dim c As New Customer
Dim co As Orders
c.load(customerNumber:=10)
co = New Orders(c)
For Each o In co
    Debug.WriteLine(o.GrandTotal)
Next

In the first example, Orders is a property on the Customer object, where in the second example, Orders is a standalone object that has to be instantiated with a Customer object.

One of the drawbacks I would visualize is a new developer going straight to the Orders object even though they can't create it directly. The example isn't doing the problem justice. I'm thinking of a deeper object tree where it's not so straightforward to get to an object.

But anyway, I started by talking about design and ended up with a lot of code examples. So let's quickly try to wrap it up and ask: does a UML diagram illustrate these finer points? Can you end up with objects that will get coded like this if you purposely do not think of code while designing? Will your objects be self-aware or will they just be data containers with a bunch of methods to manipulate the data?

The answers lie with the developer.

 
 
 

 
Copyright © . All Rights Reserved.
Powered by Community Server (Commercial Edition), by Telligent Systems