Thread: Design Dilemma

    #1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Apr 2008
    Posts
    10
    Rep Power
    0

    Design Dilemma


    We're building an CRM type application that allows the user to add custom tabs to the user interface. These tabs each have a user defined filter so the user can specify a sub set of the data to be displayed in each tab.

    As an example if you're in the Clients area, you could create a tab and set its filter to "Country = US". Then another tab could be set to "Country = UK". This allows the user to quickly see clients in each country.

    Because of this, we have an entity in our Domain Model called CustomTab. This class contains the tab name, filter expression etc..

    Here is where the dilemma starts.. On the user interface we need to display the number of records contained in each tab. This is leading me to think we need a GetTabRecordCount() method in the CustomTab class that will calculate and return the value. The processing involved here would be executing (via the data access layer) some sql similar to SELECT COUNT(*) FROM clients WHERE...

    However, it has been my (perhaps misguided) opinion that the Domain Model should not initiate database operations (it should be persistence ignorant). And I certainly don't want to create a reference from the model assembly to the DAL assembly.

    Perhaps we need to rethink the model, or perhaps we need to compromise and do exactly as I've described above..

    Can anyone help with this problem?
  2. #2
  3. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2008
    Posts
    84
    Rep Power
    66
    Are you using some sort of tiered approach (I'm guessing you are based on concerns over which objects access persistent data)?

    If so, I'd imagine that you have some sort of scheme in which the data access tier queries your persistent data and returns business objects that model that data. If this is the case, then you can just access the number of objects in memory. For instance, here's a simple example (I'll use pseudo-code, since I don't know what you're using):

    Business object:
    Code:
    class Customer {
    
    int id; //With getter/setter
    string name; //With getter/setter
    Location location; //With getter setter
    
    }
    Data Access Object
    Code:
    class CustomerDAO {
      
      public List<Customer> GetCustomerByLocation(Location location) {
        //Some SQL here
        return List<Customer>
      }
    
    }
    And, somewhere in the "business logic"
    Code:
    class TabPopulator {
      
      CustomerDao theDao; //This is what provides data 
      List<Customer> theCustomers;
    
      public void GetTabData() {
      theCustomers   = theDao.GetCustomerByLocation(US);
      //Now, populate the GUI
      }
    
      public int GetCustomerCount() {
        return theCustomers.Count();
      }
    }
    Hopefully, that illustrates my point. The basic idea is that you have a layer that accesses the data and populates some sort of object or objects that you define, which model the data. From there, for direct data and meta-data (like a count), you query your in-memory object model until/unless you have reason to persist.

    And, that distinction is up to you. Whether you need the count to be updated in real-time if another user changes it is part of the requirements specification. If you are in a situation where the changes need to propagate immediately if another user modifies the data, you can implement some sort of polling where your business layer invokes the DAO to poll the count at some regular interval and updates on change.
    Last edited by drgoodtrips; May 4th, 2010 at 11:16 AM.
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Apr 2008
    Posts
    10
    Rep Power
    0
    Originally Posted by drgoodtrips
    *some good advice*
    Hi Dr,

    Thanks for getting back to me so quickly. Yes you have described our architecture fairly accurately.

    The problem is that the objects aren't loaded into memory at this point..

    A user may have 10 tabs along the top of their screen. It isn't really an option to load the entire contents of all the entities on all the tabs into memory just to get a count. In this example it would require 10 (potentially large) SQL queries, plus the processing overhead to build the entities, plus the memory requirements (we could be talking 10,000 records here). As you can see, this is a fair amount of overhead just to get some integers to display on the tabs.

    We're building a rich web application that will be accessed concurrently by 500+ people. So performance is critical to prevent the web server and database grinding to a halt.

    We're using ASP.NET with some grid controls and data-binding (to DataTables) to build the contents of the tabs, so even at that point, the individual entities aren't built in memory.

    So the option were looking at is to run a simple SELECT COUNT(*) query for each of the tabs. But what should initiate this? and where should the call to the data access layer come from? Is it the responsibility of the CustomTab class in a GetTabRecordCount() method? As stated previously, I didn't think domain object should be doing thinks like this.

    I understand that your suggestion is the ideal solution in a perfect world, perhaps I'm being too concerned about server performance.. Would it normally be considered acceptable to retrieve and build all the entities just to get a simple count?
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2008
    Posts
    84
    Rep Power
    66
    Ah, I see your predicament. This is how I would approach it, personally.

    In the same data access object that you use to pull the actual records, I'd stick a wrapper for SELECT COUNT(*) and just call it "GetCount" or some such thing. I would then call this from some kind of controller object. Most of the web design that I've done of any significance has made use of MVC (Model-View-Controller). I'm not very well versed in ASP.NET applications and architectural best practices, but the general gist is that you're going to have a series of classes that are DAO's (model), a series of classes that marshal raw domain data into presentable formats (the view) and a series of classes that govern user interactions and HTTP transactions (the controller).

    So, I'd call the DAO's count function from the controller, and then populate the CustomTab class with it as a mutator. CustomTab sounds like a view object, so if I were designing it, I'd want a controller object (i.e. "CustomPageLoader" or something) to query the DAO's and then populate the CustomTab accordingly.
  8. #5
  9. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Apr 2008
    Posts
    10
    Rep Power
    0
    Yes I guess that some kind of external controller that is responsible for loading the CustomTab with its data makes sense.

    I'm still not 100% sure how to think about the CustomTab class. It is a business entity that has some meaning to the end user, but not in the same way as Customer, Order etc.. It is an entity that relates to the application and not the business domain. This seems to be something fairly common in this application.. Perhaps we should consider splitting the Model into two separate packages / namespaces i.e. BusinessEntities and Application Entities. Is this something that other people have previously considered?
  10. #6
  11. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2008
    Posts
    84
    Rep Power
    66
    I'm certain this comes up frequently, and I think your idea of separating these types of classes is a sound one. I know there's a lot of boilerplate tiered/MVC approaches out there, but I think it's important to be flexible given your own needs, developer skill sets, and various requirements.

    I've found that having a set of dumb business objects containing only data fields and accessors/mutators (i.e. "Beans" in the Java world) makes development pretty intuitive. These become the currency, if you will, passed around by the functional layers and modules of your application. Something like "CustomTab" is more of a control than a business object. That is, in and of itself, it's meaningless in terms of the domain. It's just a means for the presentation of the data that you care about, in terms of which data and how it's presented. This specialized approach tends to make for better extensibility and easier unit testing. If later, you want to change what is presented in the Custom Tab or how it is presented, nothing about the data layer or business objects needs to change - just your requests from those parts of the application.

    Depending on how far along you are, I'd encourage a refactoring effort like that. My own experience is that if I spend a few late nights during development on what appears to be a daunting refactoring task, it starts to fall into place pretty quickly as you get into a rhythm. And, when you're done, you start to feel more confident in the code base and design.
  12. #7
  13. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Apr 2008
    Posts
    10
    Rep Power
    0
    Thanks for your good advice, there's plenty to think about there.

    Unfortunately, it is a legacy application that we're updating so trying to find a acceptable solution is a bit like trying to fit a square peg in a round hole.
  14. #8
  15. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2008
    Posts
    84
    Rep Power
    66
    I can sympathize. At my last job, I was frequently tossed things that where "legacy" was a pleasant euphemism for "my God, the Humanity". I found that a good approach was to go in and do things right each time I had to touch the code, no more, and no less. So, if there was a problem in module A which interfaced with modules B and C, I would rewrite A and the parts of B and C that were relevant.

    As the months dragged by I had a product that while not exactly extensible, was at least less horrific to modify.

    Good luck!
  16. #9
  17. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    May 2010
    Posts
    12
    Rep Power
    0
    I am not actually deep regarding this post, but however much i am thinking it may be a fault in domain system.

IMN logo majestic logo threadwatch logo seochat tools logo