Deciding which design strategy to use for n-tier applications
I'll use a typical, simplified ERP system as an example. Most ERP will contain the following 3 basic features:
Data maintenance
Ad hoc search/reporting
Business processing
These three features differ in their nature and it affects the design chosen in architecture. Just wondering how should we deal with these problems?
Data maintenance: This area contains highly repetitive CRUD plumping works. ORM is suitable for this task.
Ad hoc search/reporting: This area is hardly "object-oriented". The main concern would be performance. Dynamic SQL query may be a good choice.
Business processing: This includes business process such as processing/tracking workflow, matching payment with invoice and others. They are customized in nature so we need tailor-made business objects to handle them.
It seems like there is no one size fit all solution to solve the problems. This will lead to the question:
I wonder if it is a good idea if we can keep the technology at the place they perform well, such as using ORM to solve data maintenance and dynamic query to build ad hoc search. But this will lead to scattered business rules, since each area will have their own rules to enforce and there is no central place to control them. Is there any better solution to deal with them?
Thanks.
[2630 byte] By [
Im_Sam] at [2007-12-25]
I would agree that using the best solution for each scenario is the best approach. With some careful design, you should be able to encode your business rules into managed assemblies that can be used in Object oriented applications, workflows, and even CLR stored procedures or triggers to ensure consistent enforcement. When it makes sense, it's often best to do data related rules enforcement in the database so that the rules are enforced consistently no matter where the changes come from. The Windows Workflow Foundation to be released shortly might be a good way to expose flexible workflows using actions that incorporate the same business rules that are used in the transactional system.
LINQ/DLINQ will solve part of your dilemma when it ships with Orcas. With LINQ you can map objects to a datastore, handle updates, as well as take advantage of an extremely flexibly querying layer that is strongly typed as opposed to having adhoc SQL. There are other ORM tools available as well. The issue of OLTP vs OLAP is a tricky one as they are both competing requirements. Reporting usually requires fast retrieval and aggregation of data which means adding indexes, etc. Updating on the other hand requires that you can process many transactions in a timely manner which runs head to head with having many indexes as indexes slow down update operations. Depending on your needed level of reporting, you may want to look to a data warehousing solution such as SQL Server Analysis Services which will allow you to have a dedicated database with aggregated information designed to deliver highly efficient reporting.
You've opened up a pretty big topic here :)! I work for an ERP systems builder, which doesn't mean I know everything. But I thought I would pass along some thoughts.
I'll probably get flamed for saying this, but in 20 years and over 6 major product lines, we never adopted an ORM mechanism to bind code to the database. The reason is that the ORM model, while useful and convenient for many coding situations, doesn't tend to work well when large collections of records are involved or where there are heavily nested tables. There will be situations where you wind up fighting the ORM framework to keep performance up or add the features you need -- like search support. The other issue is all the serialization necessary to build object collections for large and nested data structures like orders->lines->releases, etc. We never found the gain outweighed the pain when it comes to ORM. We prefer views and data containers.
Dynamic queries -- other than security, which isn't a trivial subject -- hopefully wouldn't require any code to "cook" data on the way out. In other words, make sure the physical data model is clear and approachable for others. A little denormalization and/or storing "derivable" fields (like total order value as a summation of line values) makes dynamic queries simpler to produce. There might cost some overhead when data changes, but it's better to take the hit there rather than when people query, which tends to be more frequent. Don't force callers to go through a strongly-typed object model to get data -- you'll never get all of the data exposed in all of the ways people will want.
I'm a big fan of Inversion of Control (IoC) engines like Windows Workflow as a core part of an application runtime. But you need to think about your programming model quite a bit and do things differently to get the most benefit. A big issue is how to build an application that supports others to insert steps in a workflow sequence without having to write lots of code to somehow fool the rest of the system into accepting the augmentation. Rather than the classic "push" model where components build data and call other components, you need more of a pull model where components get the data they need based on references (keys, etc.) passed in via a context.
Anyway, I hope these points help a little. Of course this is all just my opinion, and I sure others will chime in.
- Erik
IMHO the issues raised here are completely valid. I just left an ERP software company where we spent a long time trying to crack this nut with a framework that addresses many of the issues you raised. The down side of not having an ORM model is that the maintenance costs are usually very high. Simple changes to the structure of logical entities require a slew of changes in the code / database. Often the same query is replicated over and over in adhoc SQL statements that have no compile time checking. Making changes to all of these different areas can become an arduous task, especially when many developers are involved. Also without having the business logic encapsualted in reusable objects, that logic gets reproduced time and time again. Some of this can be mitigated as long as there are libraries where the common code is stored and referenced. But more often than not this does not happen.
LINQ and other similar tools solve many dilemmas without which you are forced to handle yourself.
1. Complex retrievals / updates across deep relationships are handled.
2. Data loads are completely configurable so in one scenario you load a list of POs, but in other scenarious you can specify to load a PO, with all it's child LineItems, etc.
3. Navigation. You can navigate the object structure transparently. Data is lazy loaded so that you get the data you need when you need it. So for example if you load just the PO and you want to access the customer, you can simply do PO.Customer and the ORM will take care of loading the data for you without any effort on your part.
4. Changes to the structure are made in one place. You simply change the definition of your object and supply the correct metadata and you are done as far as the code is concerned.
5. Compile time checking of the structure / Intellisense. All of the properties of your objects are available in intellisene dropdowns. If you rename / add a new property, all code that references to it through the entire application / system break at compile time rather than run time.
6. Rich query capability. LINQ especially has an extremely rich query functionality that is inbred into the next version of the CLR. No more ad-hoc SQL strings.
7. Concurrency support. Support for multiple users updating the same data simultaneously.
8. Cache managment.
9. Transaction management and Isolation
10. Key Management - Identity fields are automatically updated for parent and child records.
As we move more an more towards a service oriented world, having these cross cutting concerns handled for you rather than you having to roll your won become critical to being able to meet customer demands.
Glenn