A comment made by Udi Dehan on my most recent article (the Benefits of a Service-Oriented Architecture) got me thinking. In the comment and on his blog he has been contemplating the differences between OO and SOA and, more importantly, how programmers can adjust.
First of all, I believe that the idea that the debate is an either/or proposition is wrong. Not everything should be represented as a service. Nor should everything be represented as an object. There are times when the interface represented by a service layer is the better way to go. However, even for the more devout SOA believers, that idea that the implementation of a service won't contain objects is ludicrous.
That having been said, I believe that designing using SOA is more of a mindset than a programming style. And the trick to becoming proficient is to be aware of the differences between OO and SOA, at the conceptual level. At first glance, it might seem that the main difference devolves into an argument about Remote Procedure Calls (RPC) versus document-based method calls. However, I believe that the distinguishing characteristic is actually more likely to be statefulness than the calling technique.
In a traditional object-oriented application, the typical sequence of steps to invoke a method is as follows:
- Instantiate an object
- Optionally set some property values
- Call the method, including any necessary parameters
- Wait for a response
Inherently, these steps are stateful. An instance of the object must exist before the method can be called. Properties in the object can be set, either through the constructor or by direct assignment. The fact that these properties are available for use within a method means that the object maintains state.
But what about static methods. It is possible to define a method on a class that doesn't require an instantiated object to be used. The methods don't have access to the instance-level properties and methods. How could they? No instance has been created.
However, even static methods can be stateful. Classes can also define static properties. Static properties can be assigned values, values that can be used by static methods. Therefore the mere inclusion of static methods is not a sufficient condition for statelessness.
“But wait a second”, you say. “What if the static method didn't use any static properties? What if all of the external values required by the method are included in the parameter list? Surely that's not stateful!”
Of course, you'd be right. If all of the required information is available to a method through the parameter list at the time of the call, it is no longer a stateful operation. But here's the real kicker. Convert the parameter list into an XML document. Pass the document into the static method and you have just created the skeleton of a service. A message (the XML document) is passed into a service provider (the static method) which intrinsically knows how to process it.
And therein lies the difference between OO and SOA. It's not that the two aren't related. It's that SOA is much more demanding about how programmers interact with it. Kinda nice when knowledge sneaks up like that, isn't it?
Dave gives an in-depth look at the next release of .NET: Visual Studio .NET 2.0 (code-named "Whidbey"). This release of Visual Studio and the .NET framework will offer innovations and enhancements to the class libraries, CLR, programming languages and the Integrated Development Environment (IDE). He will share the latest material from the Microsoft PDC in L.A. and from the Bigger Better Basic tour. Attend this free event and learn how you can architect your applications today to ensure a smooth transition to the next version of .NET. More information and registration can be found at the Canadian Technology Triangle web site
Well I've done it. They warned me not to but I did it anyway.
I installed Whidbey on my machine along side 2002 and 2003.
I'll post any trouble I have right here.
I'm spending this week in Los Angeles. Not the vacation from the cold that you'd be thinking I on, however. I'm at the L.A. County Coroner installing some software that has been a while in coming. To put it into perspective, the app is in VB6 and I have SQL Server 7 on my development environment to support it. Which means that I'm unlikely to have anything blogworth based on my experiences here.
What is interesting, if you have a sense of humor about death, is the the Coroner's online store. Called Skeletons in the Closet, it offers a wide selection of Coroner emblemmed merchandise, as well as some shirts, cups, hats, key chains and mouse pads decorated with the requisite chalk body outline. Honestly, I can't accurately convey just how cool this stuff looks. Do yourself a favor and check it out at http://www.lacoroner.com. It'll knock you dead.
I just noticed that the dates for the VSLive converence in Toronto are now available. May 4-7, 2004. Mark it on your calendar, book your flights and get ready to rock. And, for those who are wondering, temperatures in Toronto are usually above freezing by that time of the year. ;)
For all those who are interested, I have just posted the latest article in my series on service-oriented architecture, called Jumping the Hurdle: Moving from OO to SOA. Read, learn, be amused, be bored. Feel free to let me know where on that spectrum you fall.
I have an issue with the DataTable object. Although I think it's a cultural thing. Some people I talk to don't seem to bothered by it. I find it very annoying, mostly because it would have been so easily avoided.
So whats the problem? When a DataRow is flagged for deletion it's still part of the row collection in the DataTable. So you may now be wondering what the big deal is.
You see I spent 10 years in the PowerBuilder world. In a PowerBuilder DataWindow (Similar to the objects in ADO.NET) when a row is flagged for deletion it's stored in a separate collection. Therefore when you are processing the rows The Deleted rows are not in the collection of current rows. If you want to access the deleted rows you can do that also. Also when you get a count of rows it's the count of rows not including the deleted rows.
In a DataTable when you delete a row it remains in the rows Collection and you have to deal with them. This also means that DataTable.Rows.Count or DataTable.Count is a count of all the rows including deleted rows.
Why do I say it's cultural? My esteemed colleague Bruce Johnson and I had a brief discussion and he almost convinced me this is how it should be. Bruce said "It's only flagged as deleted why shouldn't it be in the Rows collection?" I have to say this is a fair statement. However it would make life easier for the developer if there was a DeletedRows collection. Therefore a corresponding DeletedRows.Count. This feels more natural to me.
When do you ever want to iterate through all the rows in a DataTable both deleted and not and preform the same action on them? I could make something up but it would be bogus. I have never wanted to do this. Even if you can come up with a good reason it's not going the be the common scenario. When you write a framework you should take into account the 80/20 rule. Make it easier for 80 percent of the cases and let the 20 percent do extra work.
This means that when you iterate through a collection of rows in a table you have to be sensitive to the fact that some of them may have been deleted.
There are ways to make life easier, and when .net 2.0 (Whidbey) comes along there will be even more.
What can you do about it?
You could check the row state inside your iterator like this.
For each row as dataRow in DataTable
if Datarow.RowState <> dataRowState.Delete then
Or you could get a subset of the collection like this.
For each row as dataRow in dataTable.Select("", "", DataViewRowState.CurrentRows)
Keep in mind with this solution if you are using a typed DataSet you will have to cast the select for the typed row.
For each row as OrderRow in Ctype(OrderTable.Select("","",DataViewRowState.CurrentRows), OrderRow())
I recommend wrapping up the select in a DataSetHelper method, so it looks like this.
For each row as OrderRow in Ctype(DataSetHelper.GetCurrentRows( OrderTable ), OrderRow())
What about getting the count of Current rows in the DataTable. You could wrap this little code segment up in a method in your DataSetHelper also. Just pass in a DataTable.
Public Function GetRowCount( dt as DataTable ) as integer
Dim dataView As New dataView
dataView.Table = dt
dataView.RowStateFilter = DataViewRowState.CurrentRows
return = dataView.Count
I mentioned above .net 2.0 (Whidbey) will help. How is that you ask.
There are a couple of solutions.
Using Partial types you could extend the DataSet Class to include a method that returns a collection of Current Rows. This way it's more natural to the developer. OrderTable.CurrentOrderRows
Using Iterators you could write your own iterator that only iterates thought the current rows.
Continuing on the trend of trying to produce a constant stream of articles, I have just published an article on some of the benefits of using SOA in a production development environment. The idea is to help programmers provide justification to the powers that be regarding the benefits of SOA so that, just maybe, it might become part of a small pilot program.
Let me know if it serves its purpose for anyone. ;)
Just to let everyone know, I have just posted my first article of the new year, A Spoonful of Web Service's Alphabet Soup
. It is the first in a series that intends to delve into the details of creating a commercial-grade services-oriented architecture.
This post is as much about making a mental note as it is about anything new. As part of the project that is creating an RSS feed from a VSS database, I wanted to to perfrom some caching of the feed. If you haven't worked with the ActiveX component that provides the API to VSS, trust me when I say that it's slow. And because the retrieval of the history is recursive, the slowness can be magnified by an order of magnitude. So given the lack of volitility of the data, caching seemed in order.
Now there is a fair bit of information about how to add items to the ASP.NET Cache object. The Insert method is used, followed by a number of parameters. And because there are different combinations of criteria that can be used to identify when the cached item expires, the Insert method has a number of different overloads. The one that I'm interested in is
Cache.Insert(string, object, CacheDependency, DateTime, TimeSpan)
This particular overload is used to specify a cache dependency and either an absolute or a sliding expiration time. Ignore the cache dependency, as it is not germaine to the discussion. The issue arises when trying to specify either an absolute expiration time or the sliding time span. Since these choices are mutually exclusive, my problem was how to correctly provide a null value for the unimportant parameter. In my case, it was how to define a 'null' TimeSpan, as I wanted to use an absolute expiration. It took a little bit of searching before I found the answer (which, by the way, is the reason for this post...future documentation).
To define an absolute expiration, use TimeSpan.Zero as the last value. For example:
Cache.Insert(”key”, value, null, DateTime.Now.AddMinutes(15), TimeSpan.Zero)
To define a sliding expiration, use DateTime.Now as the fourth parameter. For example:
Cache.Insert(”key”, value, null, DateTime.Now, new TimeSpan(0, 15, 0))
My instinct (although I have nothing to back it up) is that under the covers the Insert method uses both parmaeter values to determine when the expiration should take place. But regardless, I'm left wondering why this particular overload exists. Why is there not one overload for absolute expiration and another for sliding? The signatures would be different, so that's not the reason. It wouldn't conflict with one of the other signatures. I'm left scratching my head. Hopefully someone out there in the blogsphere who's reading this post will have an answer.