Defensive Programming - Let Type Checking Work For You

Since I have been a speaker and a teacher, I have always stressed the importance of practicing proper object-oriented programming (OOP) techniques. If you don’t practice OOP, no matter what language you are using, I guarantee you will end up with a “house of cards” and they all eventually fall.

The first “pillar” of OOP is encapsulation which means the practice of data hiding. No code gets to the data in the type unless it uses properties or methods. As I always say, “bad data in, bad data out”. If that bad data gets saved to a database it could get corrupted, it could upset customers and will cause more work and money to fix it. Is this a good example of OOP coding?

  1. public class OrderData  
  2. {  
  3.     public string ORDER;  
  4.     private string wherehouseID = "";  
  5.     public string OrderNumber = "";  
  6.     public string openClosed = "";  
  7.     public string transType = "";  
  8.     public string dateOpened = "";  
  9.     public string dateClosed = "";  
  10.     public string dateShop = "";  
  11.     public OrderData(string _ORDER)  
  12.     {  
  13.         this.ORDER = _ORDER;  
  14.     }  
  15.     //Code removed for brevity  
  16. }  

NO, it is not! This type, currently in production, does not practice good encapsulation since the actual code contains over 198 public string fields! I would say over 90 percent of code I see as a consultant does not even get this first pillar right. The first line of all your properties and methods should be validating the data before proceeding.

To make this easier, always use proper data types since they will help you with validation. If the type needs a date, then use DateTime. If the type needs a URL, then use the Uri type etc. If I had the codebase to the type above, I would have changed it to something like this.

  1. public class Order  
  2. {  
  3.     private ReplacementType _replacementType;  
  4.     private OrderType _orderType;  
  5.     private DateTime? _closedOn;  
  6.     private DateTime? _customerPickupOn;  
  7.     private TransactionType _transactionType;  
  8.     private DateTime _openedOn;  
  9.     private string _orderNumber;  
  10.   
  11.     public string OrderNumber  
  12.     {  
  13.         get  
  14.         {  
  15.             return _orderNumber;  
  16.         }  
  17.         set  
  18.         {  
  19.             if (string.IsNullOrEmpty(value))  
  20.             {  
  21.                 throw new ArgumentNullException();  
  22.             }  
  23.   
  24.             _orderNumber = value;  
  25.         }  
  26.     }  
  27.   
  28.     public bool IsClosed { get; private set; }  
  29.   
  30.     public TransactionType TransactionType  
  31.     {  
  32.         get  
  33.         {  
  34.             return _transactionType;  
  35.         }  
  36.         set  
  37.         {  
  38.             if (!System.Enum.IsDefined(typeof(TransactionType), value))  
  39.             {  
  40.                 throw new ArgumentOutOfRangeException();  
  41.             }  
  42.   
  43.             _transactionType = value;  
  44.         }  
  45.     }  
  46.   
  47.     public int EmployeeId { get; set; }  
  48.   
  49.     public DateTime OpenedOn  
  50.     {  
  51.          get  
  52.         {  
  53.             return _openedOn;  
  54.         }  
  55.         set  
  56.         {  
  57.             if (value <= DateTime.MinValue)  
  58.             {  
  59.                 throw new ArgumentOutOfRangeException();  
  60.             }  
  61.   
  62.             _openedOn = value;  
  63.         }  
  64.     }  
  65.   
  66.     public DateTime? CustomerPickupOn  
  67.     {  
  68.         get  
  69.         {  
  70.             return _customerPickupOn;  
  71.         }  
  72.         set  
  73.         {  
  74.             if (this.OpenedOn <= DateTime.MinValue)  
  75.             {  
  76.                 throw new ArgumentOutOfRangeException(nameof(OpenedOn));  
  77.             }  
  78.   
  79.             if (value < this.OpenedOn)  
  80.             {  
  81.                 throw new ArgumentOutOfRangeException(nameof(CustomerPickupOn), "Value must be the same or later than OpenedOn");  
  82.             }  
  83.   
  84.             _customerPickupOn = value;  
  85.         }  
  86.     }  
  87.   
  88.     public DateTime? ClosedOn  
  89.     {  
  90.         get  
  91.         {  
  92.             return _closedOn;  
  93.         }  
  94.         set  
  95.         {  
  96.             if (this.OpenedOn <= DateTime.MinValue)  
  97.             {  
  98.                 throw new ArgumentOutOfRangeException(nameof(OpenedOn));  
  99.             }  
  100.   
  101.             if (value < this.OpenedOn)  
  102.             {  
  103.                 throw new  ArgumentOutOfRangeException(nameof(ClosedOn), "Value must be the same or later than OpenedOn");  
  104.             }  
  105.   
  106.             _closedOn = value;  
  107.             this.IsClosed = true;  
  108.          }  
  109.     }  
  110.   
  111.     public OrderType OrderType  
  112.     {  
  113.         get  
  114.         {  
  115.             return _orderType;  
  116.         }  
  117.         set  
  118.         {  
  119.             if (!System.Enum.IsDefined(typeof(OrderType), value))  
  120.             {  
  121.                 throw new ArgumentOutOfRangeException();  
  122.             }  
  123.   
  124.             _orderType = value;  
  125.         }  
  126.     }  
  127.   
  128.     public ReplacementType ReplacementType  
  129.     {  
  130.         get  
  131.         {  
  132.             return _replacementType;  
  133.         }  
  134.         set  
  135.         {  
  136.             if (!System.Enum.IsDefined(typeof(ReplacementType), value))  
  137.             {  
  138.                 throw new ArgumentOutOfRangeException();  
  139.             }  
  140.   
  141.             _replacementType = value;  
  142.         }  
  143.     }  
  144.   
  145.     // Code removed for brevity  
  146. }  

As you can see in the code above, I’m using the proper data types and even created a few enums. I am also validating all the data coming into the type and if it fails, I throw the proper exception.  

If you use proper data types, then I guarantee this will help your team. If you are a Microsoft .NET developer, please be sure to pick up a copy of my coding standards book. Please share comments you might have below.


Similar Articles
McCarter Consulting
Software architecture, code & app performance, code quality, Microsoft .NET & mentoring. Available!