It's great to be here at Los Techies!

This being my first blog post at Los Techies, I want first say how excited I am to be part of a vibrant community of developers. For some time now, I have been "going it alone" with my blog efforts. I believe that when afforded an opportunity to add to an ecosystem that has such a positive effect on the development community at large - you don't let that opportunity pass.  You can find my former blog at www.johnvpetersen.com.

A little about me...I have been a professional software developer for about 20 years. Currently, my development focus is in the ASP MVC space - and I love it. I have also been dabbling into Ruby on Rails. I have a forthcoming article in Code Magazine where I discuss my efforts at porting Nerd Dinner to Rails. Most recently, I have been making the rounds to local Code Camps (Philadelphia, Harrisburg and New York City) giving talks on the BI Stack, NHibernate and ASP MVC.  Over the years, the community has provided me with many opportunities. In that regard, I appreciate the opportunity, whenever possible, to give back. Of particular interest, I enjoy the opportunity to help new developers learn the ropes. To that end, I have been working with the Philadelphia Microsoft Developer Evangelist Dani Diaz in building up a new site called http://www.devready.net/. Should you have the desire to give back, I encourage you to contribute a 20-40 minute screen cast on a topic of your choosing. As of this blog post, the site is still in the ramp-up phase.

Until next time, happy coding!!

 

< JVP >

 

 

 

 

 

Kick It on DotNetKicks.com



Categories: Computers | CSharp | Dot Net | Los Techies | Programming | Technology
Article :: LINQ and the .NET Compact Framework 3.5

.NET 3.5 introduces LINQ, a mechanism for manipulating collections of objects. This chapter shows how you can use LINQ capabilities such as selecting, ordering, filtering, and aggregating to simplify the retrieval, display, modification, and persistence of data.

Categories: Computers | CSharp | Dot Net | InformIT | InformIT Dot Net and Windows Programming | Programming | Technology | Windows Programming
Article :: Root Causes of Technical Debt

Aaron Erickson discusses how our attitudes toward risk affect technical debt in software development organizations.

Categories: Computers | CSharp | Dot Net | InformIT | InformIT Dot Net and Windows Programming | Programming | Technology | Windows Programming
Strengthening your domain: Encapsulated collections

Previous posts in this series:

One of the common themes throughout the DDD book is that much of the nuts and bolts of structural domain-driven design is just plain good use of object-oriented programming.  This is certainly true, but DDD adds some direction to OOP, along with roles, stereotypes and patterns.  Much of the direction for building entities at the class level can, and should, come from test-driven development.  TDD is a great tool for building OO systems, as we incrementally build our design with only the behavior that is needed to pass the test.  Our big challenge then is to write good tests.

To fully harness TDD, we need to be highly attuned to the design that comes out of our tests.  For example, suppose we have our traditional Customer and Order objects.  In our world, an Order has a Customer, and a Customer can have many Orders.  We have this directionality because we can navigate this relationship from both directions in our application.  In the last post, we worked to satisfy invariants to prevent an unsupported and nonsensical state for our objects.

We can start with a fairly simple test:

[Test]
public void Should_add_the_order_to_the_customers_order_lists_when_an_order_is_created()
{
    var customer = new Customer();
    var order = new Order(customer);

    customer.Orders.ShouldContain(order);
}

At first, this test does not compile, as Customer does not yet contain an Orders member.  To make this test compile (and subsequently fail), we add an Orders list to Customer:

public class Customer
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Province { get; set; }
    public List<Order> Orders { get; set; }

    public string GetFullName()
    {
        return LastName + ", " + FirstName;
    }
}

With the Orders now exposed on Customer, we can make our test pass from the Order constructor:

public class Order
{
    public Order(Customer customer)
    {
        Customer = customer;
        customer.Orders.Add(this);
    }

And all is well in our development world, right?  Not quite.  This design exposes quite a bit of functionality that I don't think our domain experts need, or want.  The design above allows some very interesting and very wrong scenarios:

[Test]
public void Not_supported_situations()
{
    // Removing orders?
    var customer1 = new Customer();
    var order1 = new Order(customer1);

    customer1.Orders.Remove(order1);

    // Clearing orders?
    var customer2 = new Customer();
    var order2 = new Order(customer1);

    customer2.Orders.Clear();

    // Duplicate orders?
    var customer3 = new Customer();
    var customer4 = new Customer();
    var order3 = new Order(customer3);

    customer4.Orders.Add(order3);
}

With the API I just created, I allow a number of rather bizarre scenarios, most of which make absolutely no sense to the domain experts:

  • Clearing orders
  • Removing orders
  • Adding an order from one customer to another
  • Inserting orders
  • Re-arranging orders
  • Adding an order without the Order's Customer property being correct

This is where we have to be a little more judicious in the API we expose for our system.  All of these scenarios are possible in the API we created, but now we have some confusion on whether we should support these scenarios or not.  If I'm working in a similar area of the system, and I see that I can do a Customer.Orders.Remove operation, it's not immediately clear that this is a scenario not actually coded for.  Worse, I don't have the ability to correctly handle these situations if the collection is exposed directly.

Suppose I want to clear a Customer's Orders.  It logically follows that each Order's Customer property would be null at that point.  But I can't hook in easily to the List<T> methods to handle these operations.  Instead of exposing the collection directly, I will expose only those operations which I support through my domain.

Moving towards intention-revealing interfaces

Let's fix the Customer object first.  It exposes a List<T> directly, and allows wholesale replacement of that collection.  This is the complete antithesis of intention-revealing interfaces.  I will now only expose the sequence of Orders on Customer:

public class Customer
{
    private readonly IList<Order> _orders = new List<Order>();

    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Province { get; set; }
    public IEnumerable<Order> Orders { get { return _orders; } }

    public string GetFullName()
    {
        return LastName + ", " + FirstName;
    }
}

This interface explicitly tells users of Customer two things:

  • Orders are readonly, and cannot be modified through this aggregate
  • Adding orders are done somewhere else

I now have the issue of the Order constructor needing to add itself to the Customer's Order collection.  I want to do this:

public class Order
{
    public Order(Customer customer)
    {
        Customer = customer;
        customer.AddOrder(this);
    }

Instead of exposing the Orders collection directly, I work through a specific method to add an order.  But, I don't want that AddOrder available everywhere, I want to only support the enforcement of the Order-Customer relationship through this explicitly defined interface.  I'll do this by exposing an AddOrder method, but exposing it as internal:

public class Customer
{
    private readonly IList<Order> _orders = new List<Order>();

    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Province { get; set; }
    public IEnumerable<Order> Orders { get { return _orders; } }

    internal void AddOrder(Order order)
    {
        _orders.Add(order);
    }

There are many different ways I could enforce this relationship, from exposing an AddOrder method publicly on Customer or through the approach above.  But either way, I'm moving towards an intention-revealing interface, and only exposing the operations I intend to support through my application.  Additionally, I'm ensuring that all invariants of my aggregates are satisfied at the completion of the Create Order operation.  When I create an Order, the domain model takes care of the relationship between Customer and Order without any additional manipulation.

If I publicly expose a collection class, I'm opening the doors for confusion and future bugs as I've now allowed my system to tinker with the implementation details of the relationship.  It's my belief that the API of my domain model should explicitly support the operations needed to fulfill the needs of the application and interaction of the UI, but nothing more.

Kick It on DotNetKicks.com



Categories: Computers | CSharp | Dot Net | Los Techies | Programming | Technology
Article :: Improving Software Economics, Part 1 of 7: From Software Development to Software Delivery

In part 1 of this series, Walker Royce discusses the economic changes inherent in moving from the software development model to the software delivery model.

Categories: Computers | CSharp | Dot Net | InformIT | InformIT Dot Net and Windows Programming | Programming | Technology | Windows Programming
Article :: Beyond HTML: Returning JSON and XML Data From Your MVC Endpoints

You adopted MVC to get better control over your URL structure. Then you're asked to provide REST access over the same data. Instead of developing a new API and set of endpoints that mirrors what you already have, you can augment the existing application to respond to requests for JSON and XML as well as handle data updates and deletes. Scott Seely shows you how.

Categories: Computers | CSharp | Dot Net | InformIT | InformIT Dot Net and Windows Programming | Programming | Technology | Windows Programming
Article :: Advanced .NET Debugging: Managed Heap and Garbage Collection

Mario Hewardt takes a look at the internals of the CLR heap manager and the GC and some common pitfalls that can wreak havoc in your application. He shows how to utilize the debuggers and a set of other tools to illustrate how to get to the bottom of the problems.

Categories: Computers | CSharp | Dot Net | InformIT | InformIT Dot Net and Windows Programming | Programming | Technology | Windows Programming
Don't Expose IList Just So You Can Assert Against Its Contents

Lately I've been trying to return IEnumerable<T> whenever I need a collection that will only be enumerated or databound to something. This prevents me from making changes to the collection outside the context of the collection's parent entity. The problem with doing this is that I might need to write a unit test that looks for a specific item in the collection, checks the count of the collection or otherwise needs to do something that the IEnumerable<T> interface doesn't provide.

With tools like Resharper, It's easy to change the return types of the methods that you're getting the collection from and use an IList<T> or some other collection type that allows you to get at the information I want. However, this can lead to broken encapsulation and other potential problems in code. After all, I wanted to keep the collection encapsulated within the parent entity which is why I chose to use the IEnumerable<T> in the first place.

The good news is that there's a super simple solution to this situation that does not require changing the IEnumerable<T> return type. Have your test code wrap the IEnumerable<T> in an IList<T>.

   1: IEnumerable<MyObject> myEnumerator = someService.GetStuff();
   2: var myCollection = new List<MyObject>(myEnumerator);
   3:  
   4: [Test]
   5: public void my_test()
   6: {
   7:   myCollection.Count.ShouldBe(1);
   8:   myCollection[0].ShouldEqual(myObject);
   9:   //etc.
  10: }

 

If you're doing interaction testing with an interface and a mock object, where the interface receives an IEnumerable<T>, you can still use this trick. For example, if I have this method on an interface defintion:

   1: void ShowProductCodes(IEnumerable<Lookup> productCodes);

I can grab the output of this method via a stub and convert it to an IList<T>. Here's one way to do it via RhinoMocks:

   1: var view = Mock<IAssetClassificationView>();
   2: view.Stub(v => v.ShowProductCodes(Arg<IEnumerable<Lookup>>.Is.Anything))
   3:     .Callback((IEnumerable<Lookup> lookups) =>
   4:     {
   5:         DisplayedProductCodes = new List<Lookup>(lookups);
   6:         return true;
   7:     });
   8: return view;

Line 5 wraps up the IEnumerable<Lookup> into an IList<Lookup> object, letting me test the contents/count/etc on the collection.

Now you never need to worry about whether you can test the IEnumerable<T> when you are passing it around in your code. Just wrap it in an IList<T> at test time and call your tests the way you need to.

Kick It on DotNetKicks.com



Categories: Computers | CSharp | Dot Net | Los Techies | Programming | Technology
Article :: Design Patterns in C#: Singleton

The intent of the Singleton pattern is to ensure that a class has only one instance, and to provide a global point of access to it. Steven John Metsker explains the mechanics of this pattern.

Categories: Computers | CSharp | Dot Net | InformIT | InformIT Dot Net and Windows Programming | Programming | Technology | Windows Programming
I don't just code

I have an obscure, personal blog to which I fled back to recently. I posted the following entry:

Well whadaya know? I'm having existential doubts these days. There's a battle that rages inside of me every time I get a little bit of free time: what should I spend my precious little time on? Until recently, I had been trying to get an enterprise-y application going, but it filled me with dread. Every line of code had to be extracted from my body with forceps, put into place and tested. It was a fine equilibrium, a delicate balance that I maintained by making myself believe that this is what I wanted to do. It was more that just something to do on a rainy day; it was more than just a reason to go out and hang out in a coffee shop all afternoon on Sundays. It was what I wanted to do. But I hated it. Well, most of it.

Anyway, that balance tipped over when I lost control of the app. Slowly, I stopped unit testing features. Then I simply started hacking it without too much thought or process. I started drifting. Thoughts would come and distract me. What is the next big thing? How can I become hugely successful and never have to worry about money again? Should I remain a Windows developer, forever branded as a .Net guy, or should I venture to the free ecosystem that is Linux? What about Mono? Oh, I could write server apps with Mono! But what about Lisp? I've always wanted to learn Lisp! I could write a Command &amp; Query type application and start with the Login system and write it in Lisp. Or even better yet, I should write a .Net version of Common Lisp, just like that dude that wrote Clojure on top of the JVM. And of course, it would have to be done entirely by using the command line and VIM... Is there a book on Amazon for VIM?..

And on, and on, and on it would go. Every Sunday. Torture. I would power on my laptop and sit transfixed in front of the monitor, my hands calmly positioned over the keyboard. There would be a shell prompt and a VIM window open, waiting. Oh, the possibilities! And yet, I couldn't come up with anything to do. Eventually, I'd give up and log on to twitter, facebook, news.ycombinator, arstechica, slashdot, news.google, nytime, programmer-looking-for-a-problem-to-solve-that-wont-bore-him-to-death.com... I'd then slam shut the laptop lid and be in a funky mood all day. Hell, that's exactly what happened today. Again!

Except that today I decided it was all over. I would stop wasting the rest of my life pursuing something I'm starting to feel weak at. Focus on my strength. That's what I need to do! But then I read a blog post about using object databases and cracked open my Common Lisp book. Damn it! I feel excited about programming again. It makes me feel like getting my laptop down from the shelf where it's quietly sitting and hack on something.

Why?

I'm clearly passionate about something! I just can't put my finger on it. So here's what I'm going to do. I'm gonna blog about that until I figure out what it is. Yeah. Blogging. That's so 2005! It's so not the next big thing.... oh... here I go again!

It's only been a month, and already my mind is on something else. You guys have read my posts, or if you haven't, go check my post history. I'm all over the place! Why the hell did I want to learn Lisp? Why go away from what I know best? I think we all want to do something significant in life. We all want to get better. But in my case, I clearly need some focus. Instead of learning something new and obscure (and hard!), why not get better at what I already do? I'll admit it: I'm not a spare time or weekend coder. I can't do it. I don't pull the all nighters. I don't stay up until 2am at night. I actually try to get between 8 and 9 hours of sleep every night because that's what makes me feel great during the day. This sort of balance is what I need. When I try to focus too much on code, I end up developing this allergic reaction that causes the kind of posts I just showed you. It's not fun. Yet, I envy all of you who do code all the time. I feel that not doing it slows me down on my journey to become a better programmer.

I suppose the journey is what's important. The important thing is that we go forward. The pace doesn't matter. As for me, I'm not forcing myself to code anymore. I'm enjoying my time with my family and feel I'm a better developer at work because of it.

Kick It on DotNetKicks.com



Categories: Computers | CSharp | Dot Net | Los Techies | Programming | Technology
Why is CruiseControl.Net Hiding My Test Results?

Some time ago, I noticed a CruiseControl.Net build report with thousands of unit tests passed, zero failed and a dozen or so skipped, suddenly showing that no tests were run:

Partial screenshot of CCNET showing no tests run.

I immediately thought somebody did something really bad. After some digging, I found an error in the CCNET log file that indicated an error was thrown and swallowed during the parsing of the test results xml file. It was choking on an NUnit Row Test with a null character in a string. Here is the exception:

2010-03-02 13:45:25,567 [Project.Web:DEBUG] Exception: System.Xml.XmlException: '.', hexadecimal value 0x00, is an invalid character. Line 5901, position 160.
   at System.Xml.XmlTextReaderImpl.Throw(Exception e)
   at System.Xml.XmlTextReaderImpl.Throw(String res, String[] args)
   at System.Xml.XmlTextReaderImpl.Throw(Int32 pos, String res, String[] args)
   at System.Xml.XmlTextReaderImpl.ThrowInvalidChar(Int32 pos, Char invChar)
   at System.Xml.XmlTextReaderImpl.ParseNumericCharRefInline(Int32 startPos, Boolean expand, BufferBuilder internalSubsetBuilder, Int32& charCount, EntityType& entityType)
   at System.Xml.XmlTextReaderImpl.ParseNumericCharRef(Boolean expand, BufferBuilder internalSubsetBuilder, EntityType& entityType)
   at System.Xml.XmlTextReaderImpl.HandleEntityReference(Boolean isInAttributeValue, EntityExpandType expandType, Int32& charRefEndPos)
   at System.Xml.XmlTextReaderImpl.ParseAttributeValueSlow(Int32 curPos, Char quoteChar, NodeData attr)
   at System.Xml.XmlTextReaderImpl.ParseAttributes()
   at System.Xml.XmlTextReaderImpl.ParseElement()
   at System.Xml.XmlTextReaderImpl.ParseElementContent()
   at System.Xml.XmlTextReaderImpl.Read()
   at System.Xml.XmlWriter.WriteNode(XmlReader reader, Boolean defattr)
   at ThoughtWorks.CruiseControl.Core.Util.XmlFragmentWriter.WriteNode(XmlReader reader, Boolean defattr)
   at ThoughtWorks.CruiseControl.Core.Util.XmlFragmentWriter.WriteNode(String xml)

Here's an example that again broke our results output the other day.


 

This version of CruiseControl.Net isn't the newest, and is older than the version of NUnit that is running. This may be fixed by upgrading CCNet, I haven't tried yet though. This is just meant to be a "heads-up" in case you run into the same issue.

Unfortunately, my answer to getting the results to show back up was to remove both row tests.  If anybody can add more details to this (affected versions, fixes, workarounds, etc), it would be greatly appreciated by myself and hopefully somebody else.

Kick It on DotNetKicks.com



Categories: Computers | CSharp | Dot Net | Los Techies | Programming | Technology
Article :: WPF Control Development: The Diverse Visual Class Structure

WPF has a rich, diverse set of building blocks and tools that you can use to create amazing interfaces. Knowing which tool to use and when to use it is absolutely invaluable to creating next-generation applications. What follows is a brief overview of the most important classes in WPF.

Categories: Computers | CSharp | Dot Net | InformIT | InformIT Dot Net and Windows Programming | Programming | Technology | Windows Programming
Article :: C# 4.0 Features

What's so great about C# 4.0? Troy Magennis looks at the new features added into C# 4.0 that combine to improve code readability and extend your ability to leverage LINQ to Object queries over dynamic data sources.

Categories: Computers | CSharp | Dot Net | InformIT | InformIT Dot Net and Windows Programming | Programming | Technology | Windows Programming
When Do You Specify Expected Parameters In Stub Methods?

I'm writing a spec with a mock object that mock object returns data to the class under test. In these situations, I don't bother asserting that my mock object's method was called because I know that if it's not called the data I need in the class under test won't be there and I'll end up having other unexpected behavior. This falls under the general guideline of ‘test output and interactions, not input'.

In this specific situation, I am taking a value from user input and using that value to load up some data from a mock repository. I find myself wondering if I should specify the value that is being passed into the mock object's method so that the mock will only return the data I need if the method is called with the right value. To illustrate in code, here are the two different ways I could do this.

1. Always return the data from the stubbed method call:

   1: private IAssetGroupRepository GetAssetGroupRepository()
   2: {
   3:     var repo = Mock<IAssetGroupRepository>();
   4:     AssetGroups = new List<Lookup>();
   5:     repo.Stub(r => r.GetGroupLookups(Arg<int>.Is.Anything)).Return(AssetGroups);
   6:     return repo;
   7: }

2. Only return the data from the stubbed method when the right argument is found:

   1: protected override IAssetGroupRepository GetAssetGroupRepository()
   2: {
   3:     var repo = Mock<IAssetGroupRepository>();
   4:     AssetGroups = new List<Lookup>();
   5:     repo.Stub(r => r.GetGroupLookups(1)).Return(AssetGroups);
   6:     return repo;
   7: }

The difference is on line 5 – the use of Is.Anything vs. a literal value of 1. It seems that the arguments should be specified when it matters what the arguments are... when the arguments are going to determine whether or not the right thing is being done. In this situation, it seems to me that the argument is important. If I'm not specifying the value that was selected when calling the GetGroupLookups, then my code has failed to account for the user's input and it will likely produce the wrong behavior. The counterpoint to this is that the test where this stub definition lives becomes a little more brittle.

So the question is when should I return the data no matter what arguments are used vs. when should I only return the data when the right arguments are used? I know the answer is "it depends", as that's the only valid answer to any code question. :) But I'm looking for some input from the rest of the world on when they do / don't require the right arguments and why.

Kick It on DotNetKicks.com



Categories: Computers | CSharp | Dot Net | Los Techies | Programming | Technology
No silver domain modeling bullets

This past week, I attended a presentation on Object-Role Modeling (with the unfortunate acronym ORM) and its application to DDD modeling".  The talk itself was interesting, but more interesting were some of the questions from the audience.  The gist of the tool is to provide a better modeling tool for domain modeling than traditional ERM tools or UML class diagrams.  ORM is a tool for fact-based analysis of informational models, information being data plus semantics.  I'm not an ORM expert, but there are plenty of resources on the web.

One of the outputs of this tool could be a complete database, with all constraints, relationships, tables, columns and whatnot built and enforced.  However, the speaker, Josh Arnold, mentioned repeatedly that it was not a good idea to do so, or at least it doesn't scale at all.  It could be used as a starting point, but that's about it.

Several times at the end of the talk, the question came up, "can I use this to generate my domain model" or "database".  Tool-generated applications are a lofty, but extremely flawed goal.  Code generation is interesting as a one-time, one-way affair.  But beyond that, code generation does not work.  We've seen it time and time again.  Even though the tools get better, the underlying invalid assumption does not change.

The fundamental problem is that visual code design tools can never and will never be as expressive, flexible and powerful as actual code.  There will always be a mismatch here, and it is a fool's errand to try to build anything more.  Instead, the ORM tool looked quite useful as a modeling tool for generating conversation and validating assumptions about their domain, rather than a domain model builder.

Ultimately, the only validation that our domain is correct is the working code.  There is no silver bullet for writing code, as there is always some level of complexity in our applications that requires customization.  And there's nothing that codegen tools hate more than modification of the generated code  However, I'm open to the idea that I'm wrong here, and I would love to be shown otherwise.

Kick It on DotNetKicks.com



Categories: Computers | CSharp | Dot Net | Los Techies | Programming | Technology
Article :: C# 4.0 How-To: Creating Versatile Types

This chapter is all about making your own objects as useful and versatile as possible. In many cases, this means implementing the standard interfaces that .NET provides or simply overriding base class methods.

Categories: Computers | CSharp | Dot Net | InformIT | InformIT Dot Net and Windows Programming | Programming | Technology | Windows Programming
CQRS Performance Engineering: Read vs Read/Write Models

I've used a lot of different architectures, patterns and implementations that revolve around the core concept of command-query separation (CQS) and the more recent label of command-query responsibility separation (CQRS). The ideas behind these principles help us create code that targeted to a single purpose, generally side-effect free and easier to work with and maintain. In the last few days, though, I've begun to see how CQRS can be used for performance engineering as well.

Performance Problems With A Common Pattern

A few weeks ago, our product owner reported a performance problem with a control that is used on two screens in our handheld / Compact Framework application. This control is not terribly complicated – it has 4 drop down lists, each one loaded based on the data selected in the previous one. I'm pretty sure every developer has created a series of drop down lists like this at some point in their career. It's not difficult... it just takes a little time and effort to handle all the cases of no items found, auto-selecting if there's only a single item in the list, having a "Select One" or other default option, etc.

After digging into the offending control, I found that it was doing the following for every drop down list on the control:

Data Load / Display:

  1. Load all data from the database into a DataTable
  2. Convert each row of data into the full object it represents
  3. Convert each object into a simple Name/Value Lookup object
  4. Bind the Lookup objects to the drop down list

Data Select / Use (on selected index changed):

  1. Get Value (ID) of the selected lookup item and load the full object for that ID
  2. Run the Data Load / Display for the next drop down list based on the ID of the object
  3. Publish the selected object on an event so the parent form could respond to it as needed

This is a pattern that I see a lot of – whether it's WinForms or WebForms development. It's especially common in a WebForms environment, though, where there is not state on the view implementation. Unfortunately, this pattern and implementation is very problematic when it comes to performance. The actual performance on the control in question was so bad that we resorted to using asynchronous commands to retrieve the data for the drop down lists. This let us keep the UI "responsive" to the user – it prevented the screen from locking up with strange artifacts for the 3 to 5 seconds that it took to load any given drop down list.

 

Separation Of Concerns

Why would I want to load the entire set of data from the database and deserialize that into the full object model just so I can bind the name and id of the objects to a drop down list and then re-load the same object from the database again? That doesn't make much sense to me – even in a web environment where I should bind nothing more than the name and id in the form. In a WinForms environment, though, I guess I can see "the easy way out" by loading up the objects with my existing data access infrastructure... but that just doesn't make any sense other than being lazy.

Here's the crux of a read-only or view model in this situation: if I'm only going to display the name and id of the objects, then that's all I should load.

 

Load View Model, Lazy Load Full Object When Its Needed

To solve the performance problems in this control, I decided to use the basic CQRS tenants of separating my view model, which is a read-only representation of my data, from the object model which is a read/write representation. Here's the new approach I took to solve the performance problems, with each of the drop down lists:

Data Load / Display

  1. Load the name and id only, from the database using a DataReader
  2. Populate a generic Lookup object with the name / id of each record
  3. Bind the drop down list to the Lookup objects

Data Select / Use

  1. Get the the id of the selected item in the drop down list
  2. Run the Data Load / Display for the next drop down list based on the id of the selected item

Data Collection

  1. After the entire selection process has been performed, then and only then load the full object that was selected and publish it to the parent form

There are a couple of key things to note in this solution... namely, I'm only loading the name and id for the drop down lists. I only need that information for the drop down list to work, so I'm not going to bother loading anything else. And I'm not loading the full object model until I'm actually ready to use it. If the user is constantly switching the drop down lists to figure out what they need, then loading the full object model after each individual selection will just use up a bunch of time and resources for no good reason. I'm waiting until some level of confidence in the selection can be established and the code is ready to use the object model before loading the full model.

 

The Performance Improvements

I don't have any scientific performance metrics for this, yet. I'm not sure if I'll need to do that, actually. I do have first hand experience with the existing performance and the new performance, though.

The original code tended to take anywhere from 3 to 5 seconds, on average, to load any given drop down list. The worst performance, though, was one particular query that returned nearly a thousand items for the drop list to display. This would take closer to 6 or 8 seconds to load. ... again, these are all based on my experiences, not actual timers... I can say with certainty, though, that I was never able to use keypad up/down arrows to select items in the drop down list. The control was simply too slow in responding so I would sit there and wait for it to finish loading before clicking the down arrow again.

With the new implementation in place, the control's performance is significantly enhanced. The average time it takes to load the drop down list has dropped to far below a second. Again, I haven't done any real timer / performance testing with this... but I can say with certainty that I can now use the up/down arrow keys on the keypad and the control keeps up with me no matter how fast I'm able to click the keys. Furthermore, the performance is good enough that I have not yet needed to use any asynchronous processing to load or display any data. Even with the one query that returns nearly a thousand records to the drop list, the time to load is less than a second – a barely noticeable stutter in the list being available for selection.

 

Conclusions And Other Considerations

The principles and patterns that comprise CQRS can be used for a number of different reasons – not the least of which is performance improvements in your code. Whether you are working on Winforms, Webforms, Compact Framework or another system or platform that has read vs. read/write needs, keeping CQRS in mind at all levels of the system can have a significant impact in many different ways.

Of course, this does not come free. There is an increase in the amount of code you have to maintain when you go down this path. You may end up writing two or more different types of data access code and you will have the same data represented in multiple objects and queries in your system. These costs are not to be taken lightly. However, when used judiciously and understood by the entire team the impact of these costs can be mitigated. Keep your data access methods simple and have a clean separation between your full object model and your read only models. Constantly communication with team members and work on well named and organized code. Its your team's communication, collaboration and standards that will help to cut the costs, keep your system clean and maintain it's performance over time.

Kick It on DotNetKicks.com



Categories: Computers | CSharp | Dot Net | Los Techies | Programming | Technology