Test of the Week
It's time to take a look at the test results, but let's take a quick look at the remoting end point first. As usual, I have a service-layer (business facadelayer) class for the test (and it's used in the test within a single AppDomain, too). In Figure 2, you can see the service-layer class.
Figure 2 The service-layer class of the week.
As you saw in Figure 2, the interface of the service-layer class is more granular compared to earlier approaches. Here, Order is returned if that is what is needed, or OrderLines is returned if that is what is needed, and so on.
Result of the Tests
Let's add the tests of the custom classes to the results tables.
Once again, I will use the DataReader as a baseline. Therefore, I have recalculated all the values so that I get a value of 1 for the DataReader and so that the rest of the data containers have a value that is relative to the DataReader value. That makes it easy to compare. The higher the value is, the better.
Table 1: Results for the First Test Case: Reading One Row
|
1 User, in AppDomain |
5 Users, in AppDomain |
1 User, Cross-Machines |
5 Users, Cross-Machines |
DataReader |
1 |
1 |
1 |
1 |
Untyped DataSet |
0.6 |
0.6 |
1.4 |
1.7 |
Typed DataSet |
0.4 |
0.5 |
1 |
1.1 |
Wrapped DataSet |
0.5 |
0.6 |
1.3 |
1.7 |
Hashtable |
0.9 |
1 |
3.5 |
3.9 |
Custom Classes |
1 |
1 |
4 |
4.2 |
Table 2: Results for the Second Test Case: Reading Many Rows
|
1 User, in AppDomain |
5 Users, in AppDomain |
1 User, Cross-Machines |
5 Users, Cross-Machines |
DataReader |
1 |
1 |
1 |
1 |
Untyped DataSet |
0.5 |
0.6 |
6.9 |
9.7 |
Typed DataSet |
0.5 |
0.5 |
6 |
8.6 |
Wrapped DataSet |
0.5 |
0.6 |
6.6 |
9.6 |
Hashtable |
0.8 |
0.9 |
17 |
23.5 |
Custom Classes |
1 |
1 |
15.9 |
22.1 |
Table 3: Results for the Third Test Case: Reading One Master Row and Many Detail Rows
|
1 User, in AppDomain |
5 Users, in AppDomain |
1 User, Cross- Machines |
5 Users, Cross- Machines |
DataReader |
1 |
1 |
1 |
1 |
Untyped DataSet |
0.5 |
0.5 |
6.1 |
8.5 |
Typed DataSet |
0.4 |
0.4 |
5.1 |
6.9 |
Wrapped DataSet |
0.5 |
0.5 |
5.8 |
8 |
Hashtable |
0.8 |
0.9 |
16.2 |
19.6 |
Custom Classes |
0.9 |
1 |
16 |
19.2 |
As you saw above in the result tables, the custom classes are very close to the Hashtable in performance. For the tests in an AppDomain, the custom classes are almost too close to the DataReader. This is sort of a rounding error. The DataReader is actually a little faster, which is to be expected because there is less work to do in that case. There are no intermediate objects to instantiate and no extra movement of data.
Highly Subjective Results
My "highly subjective results" table needs to be expanded with the last option. In Table 4, you will find that I have assigned some grades according to the qualities discussed in the first part of this series. A score of 5 is excellent, and a score of 1 is poor.
Table 4: Grades According to Qualities
|
Performance in AppDomain/Cross- Machines |
Scalability in AppDomain/Cross- Machines |
Productivity |
Maintainability |
Interoperability |
DataReader DataSet |
5/1 |
4/1 |
2 |
1 |
1 |
|
3/3 |
3/3 |
4 |
3 |
4 |
Typed DataSet |
2/2 |
2/2 |
5 |
4 |
5 |
Wrapped DataSet |
3/3 |
3/3 |
3 |
5 |
4 |
Hashtable |
5/5 |
5/5 |
2 |
2 |
2 |
Custom Classes |
5/5 |
5/5 |
2 |
5 |
3 |
As usual, I'd like to say a few words about each quality grade.
Performance
In the first article of this series, I told you about Microsoft's warnings that custom classes might give bad performance compared to DataSets. Because of that, the test results of today might be very surprising because the performance of custom classes seems to be just fine.
NOTE
I'm pretty sure that what Microsoft meant is that because it's hard to create a solution based on custom classes, the performance might be the opposite of what I have shown above. I can understand that, but I also dislike it. You can get bad performance out of misuse of everything.
Am I too picky with Microsoft? Don't worryI like their work with .NET very much. Even so, I think I should tease them a little bit.
Scalability
Once again, I think that the scalability goes pretty much hand in hand with performance here. (This is in accordance with the definition of the scalability quality in Part 1.)
Productivity
If you decide to roll your own solution with custom classes, your short-term productivity will suffer. There are solutions for that, but out of the box, I have to give a low grade for productivity because of this.
Maintainability
My main reason for starting to again investigate a domain model is that I believe maintainability might gain a lot. In my opinion, the prime goal and effect of object orientation is increased maintainability. For example, it's a good way to deal with complexity.
NOTE
As you might have noticed, I wrote "once again" above. I have experimented with something like a domain model several times, but I've never been very happy with the result. For example, I mentioned some of the problems I had with a domain model in VB6 and COM at the beginning of this article.
Interoperability
Interoperability is okay because you will automatically get XML serialization. On the other hand, it will take some extra work to get the XML structure that you want, and you have to take extra precautions that sent and received XML follows the XML schema that you have agreed upon with the heterogeneous client.
Before this round of tests, the wrapped DataSet was the best if you just added the grades (and chose in AppDomain or cross machines). Now custom classes take over the lead.