Developing a Smart Architecture, Part 2

WEBINAR: On-demand webcast

How to Boost Database Development Productivity on Linux, Docker, and Kubernetes with Microsoft SQL Server 2017 REGISTER >

Developing an Application Architecture


This series of articles will walk through the creation of a simple application architecture that can be utilized in programs of nearly any size. The code posted in these articles is for illustrative purposes of concepts and is not intended for direct production use.


In Part 1 of this series, you did a detailed walkthrough of creating intelligent data fields that reduced the reprtitive coding effort while at the same time providing both (simple) validation and change notification.

Part 2: Building Intelligent Entities

Now that you have the ability to create intelligent fields, you need to expand this to creating useful intelligent classes. To begin this process, you will need to re-work a few of your existing classes. This is primarily being done so that you can treat specialized instances of the generic Field class in a unified way. You will create an interface and then update the class to implement this interface.

public interface IField
   event EventHandler<ValueChangedEventArgs<Object>> Changed;

public class Field<DATA_TYPE> : IField
   // Basic implementation remains the same with the following
   // additions/changes...
   private void Fire_ValueChanged(DATA_TYPE oldValue,
                                  DATA_TYPE newValue)
      if (ValueChanged != null)
         ValueChanged(this, new ValueChangedEventArgs<DATA_TYPE>
                      (oldValue, newValue));
      if (Changed != null)
         Changed(this, new ValueChangedEventArgs<Object>
                 (oldValue, newValue));
   public event EventHandler<ValueChangedEventArgs<Object>> Changed;

Because every instance of a Field<T> can now be treaded as an IField, you can create your Entity class. The exposed functionallity is as follows:

public class Entity : IField
   public void RegisterField(string name, IField field) {...}
   public Field<DATA_TYPE>GetField<DATA_TYPE>(string name) {}

   public event EventHandler<ValueChangedEventArgs<object>> Changed;
   public event EventHandler<FieldValueChangedEventArgs> FieldChanged;

You now have a basic set of abilities, including:

  • Registering Fields with the Entity and assigning them a Name
  • Retrieving a given Field by Name
  • Propogating events from the Fields to the Entity itself

It is important to note that an Entity is itself an IField. This allows for the creations of entities, whereas the fields themselves are entities.

You will also need the ability to create collections of these entities. For right now, you will only implement a few critical methods and properties.

public class EntityCollection<KEY_TYPE, ENTITY_TYPE> : Entity
   where ENTITY_TYPE : Entity
   public void Add(KEY_TYPE key, ENTITY_TYPE item) {}
   public bool Remove(KEY_TYPE key) {}
   public event EventHandler<CollectionChangedEventArgs>
   public void Clear()
   public int Count { get { } }
   public ENTITY_TYPE this[KEY_TYPE key] {}


It is important to note that an EntityCollection is itself an Entity (and therefor a IField). This allows any EntityCollection to be a Field member of an Entity.

Both the Entity and EntityCollection classes at this point are still very simplistic, but are already ready to create some powerful examples.

Enhancing the Invoice Sample Code

First, you must update your Invoice and InvoiceLineItem classes, and enhance them to make use of these entity base classes. This will require the Registration of the various Field objects in the constructor.

public class Invoice : Entity
   public Invoice()
      RegisterField("InvoiceDate",      InvoiceDate);
      RegisterField("InvoiceID",        InvoiceID);
      RegisterField("InvoiceNumber",    InvoiceNumber);
      RegisterField("Items",            Items);
      RegisterField("ItemsTotalPrice",  ItemsTotalPrice);
      RegisterField("ItemsTotalTax",    ItemsTotalTax);
      RegisterField("ItemsTotalWeight", ItemsTotalWeight);
      RegisterField("Shipping",         Shipping);
      RegisterField("ShippingRate",     ShippingRate);
      RegisterField("TaxRate",          TaxRate);
      RegisterField("InvoiceTotal",     InvoiceTotal);

   // Remainder of the Class is identical to previous version.....

public class InvoiceLineItem : Entity
   public Invoice()
      RegisterField("InvoiceID",     InvoiceID);
      RegisterField("ItemID",        ItemID);
      RegisterField("LineNumber",    LineNumber);
      RegisterField("Quantity",      Quantity);
      RegisterField("Taxable",       Taxable);
      RegisterField("UnitPrice",     UnitPrice);
      RegisterField("Weight",        Weight);
      RegisterField("ExtendedPrice", ExtendedPrice);

   // Remainder of the Class is identical to previous version.....

Now, you can add a series of events that will ensure that all fields are properly updated when their dependancy fields change. Because these "rules" are inherent in the nature of your Invoice, you will implement them internally to the class and install them during object construction.

public class Invoice : Entity
   // Called from Constructor after registration
   private void InstallRules()
      Items.CollectionChanged       += Items_CollectionChanged;
      ItemsTotalPrice.ValueChanged  += Recalculate_Tax;
      ItemsTotalTax.ValueChanged    += Recalculate_Total;
      ItemsTotalWeight.ValueChanged += Recalculate_Shipping;
      ItemsTotalTax.ValueChanged    += Recalculate_Total;
      ShippingRate.ValueChanged     += Recalculate_Shipping;
      TaxRate.ValueChanged          += Recalculate_Tax;

   private void Items_CollectionChanged(object sender,
      CollectionChangedEventArgs e)
      InvoiceLineItem lineItem =   e.Item as InvoiceLineItem;
      switch (e.ChangeType)
         case CollectionChangedEventArgs.CollectionChangeTypes.Added:
            ItemsTotalPrice.Value  += lineItem.ExtendedPrice.Value;
            ItemsTotalWeight.Value += lineItem.Weight.Value;
         case CollectionChangedEventArgs.CollectionChangeTypes.Removed:
            ItemsTotalPrice.Value  -= lineItem.ExtendedPrice.Value;
            ItemsTotalWeight.Value -= lineItem.Weight.Value;
         case CollectionChangedEventArgs.CollectionChangeTypes.Cleared:
            ItemsTotalPrice.Value  = 0.0M;
            ItemsTotalWeight.Value = 0.0M;

   private void Recalculate_Tax(object sender,
      ValueChangedEventArgs<decimal> e)
      ItemsTotalTax.Value = ItemsTotalPrice.Value * TaxRate.Value;

   private void Recalculate_Shipping(object sender,
      ValueChangedEventArgs<decimal> e)
      Shipping.Value =   ItemsTotalWeight.Value * ShippingRate.Value;

   private void Recalculate_Total(object sender,
      ValueChangedEventArgs<decimal> e)
      InvoiceTotal.Value = ItemsTotalPrice.Value
                         + ItemsTotalTax.Value
                         + Shipping.Value;

   public void AddItem(InvoiceLineItem lineItem)
      lineItem.LineNumber.Value = Items.Count + 1;
      Items.Add(lineItem.LineNumber.Value, lineItem);
      lineItem.ExtendedPrice.ValueChanged +=

   private void ExtendedPrice_ValueChanged(object sender,
      ValueChangedEventArgs<decimal> e)
      ItemsTotalPrice.Value += (e.NewValue - e.OldValue);

Developing a Smart Architecture, Part 2

WEBINAR: On-demand webcast

How to Boost Database Development Productivity on Linux, Docker, and Kubernetes with Microsoft SQL Server 2017 REGISTER >

And there you have it. A very simple implementation that embodies all of the logical operations related to calculating the appropriate iformation related to a simple invoice. This code is very maintainable and easily testable.

To illustrate its usage, consider the following sample program:

private static void Main()
   Invoice invoice = new Invoice();
   invoice.InvoiceNumber.Value = "1000";
   invoice.TaxRate.Value = 0.07M;
   invoice.ShippingRate.Value = 1.23M;

   InvoiceLineItem invoiceLineItem = new InvoiceLineItem();
   invoiceLineItem.Quantity.Value = 10;
   invoiceLineItem.UnitPrice.Value = 19.95M;
   invoiceLineItem.Weight.Value = 0.75M;


   Console.WriteLine("Invoice Items Total: {0}",
   Console.WriteLine("Invoice TAX: {0}",
   Console.WriteLine("Invoice Weight: {0}",
   Console.WriteLine("Invoice Shipping: {0}",
   Console.WriteLine("Invoice GRAND TOTAL: {0}",

Advanced Topics

Although too advanced for details at this point in your design, it is important to realize that there are many alternatives to explicitly coding the fields and explicitly registering them. Full functionallity implementations may use reflection to automatically register applicable fields, and may use Attributes for providing the requirement information. Once you have completed the simple architecture, I will begin to discuss these alternatives.


Even at this early stage, you are able to create "applications" that involve a minimum amount of coding. Even better, the enhancements in the next few installments will not require any (significant) changes to the Invoice sample itself. This is the real "power" of this style of architecture and implementation; you can add power to your library classes (Field, Entity, EntityCollection) as needed, and that capability will become available immediately in both future and past applications.

More Information

The information in these articles is based on the "Smart Architecture" guidance published by Dynamic Concepts Development Corp. This is an open architecture and recommended set of interfaces that can be freely utilized by the developer community. Commercial Vendors are encouraged to produce implementations and tool sets that utilize this architecture.

About the Author

David Corbin

Sr Software Architect with 30 years experience developing high-performance / high-reliability software systems.



  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date