Monday, February 25, 2013

Named Locks and Lock Striping

Suppose there is a function to which a reference to some arbitrary resource is passed (a file name, for example). The function needs exclusive access to that referenced resource, but should allow concurrent access to other resources. On the one hand, a single lock object would synchronize all calls to the function, which would ruin concurrency. On the other hand, the references are arbitrary, so the number of lock objects required is non-deterministic.

Framework support for named locks is kind of thin. The .NET framework offers named mutexes. For .NET developers this seems like an obvious choice, but since they are system-level they are very tricky to implement properly and can get out of sync very easily.

One more broadly applicable approach I've seen involves locking on the interned string representation of the resource reference. Any two references that are the same will convert to the same interned string instance, so the lock will prevent concurrent access. Meanwhile references that are not the same will convert to different interned string references, so the locks should permit concurrent access. However, if there are a lot of different possible values (names of temporary files, for example) then this approach is not sustainable--the number of interned strings would grow without bound until some kind of limit is reached, and there is usually no way to un-intern a string.

Another approach would be to set up a concurrent dictionary. When the function needs exclusive access, a GetOrAdd is attempted on the dictionary using the resource reference as a key. Atomically, the concurrent dictionary will add the key-value pair if it does not exist or return the existing value for the key. Other threads needing access to the same reference will therefore receive the same lock instance, which should prevent concurrent access to the same resource while permitting concurrent operations on different resources.

However, there is no good heuristic for determining when (or even if) a lock should be removed from the concurrent dictionary. If the lock is removed as a thread exits the critical section, then new threads attempting to access the resource will get a new lock object for that key as a result of the GetOrAdd call. This would permit concurrent access to the same resource if there are already threads waiting for access to the previous lock object. Or perhaps a cleanup thread could run in the background and periodically block all threads while old keys are cleaned up, but that increases the potential for deadlocks and race conditions that would be difficult to track down.

So the trick is to somehow map an arbitrary set of inputs to a reasonable number of lock objects. One possibility is to compute a hash code for each resource reference, which reduces a potentially infinite set of inputs to the range of an int. But that still leaves millions of possibilities, so the next step is to mod the hash code by some reasonable number of lock objects. Say, for example, 64. An array of 64 objects doesn't take up too much space, and more importantly, its size will never grow. The final algorithm looks something like this:

class LockExample
{
    private const int MaxLocks = 64;
    private static object[] Locks = new object[MaxLocks];

    static LockExample()
    {
        for (var i = 0; i < MaxLocks; i++)
        {
            Locks[i] = new object();
        }
    }

    public void Critical(string resourceName)
    {
        EnterLock(resourceName);
        try
        {
            // Critical section
        }
        finally
        {
            ExitLock(resourceName);
        }
    }

    private void EnterLock(string resourceName)
    {
        Monitor.Enter(GetLock(resourceName));
    }

    private void ExitLock(string resourceName)
    {
        Monitor.Exit(GetLock(resourceName));
    }

    private object GetLock(string resourceName)
    {
        if (resourceName == null) throw new ArgumentNullException();
        var lockIndex = resourceName.GetHashCode() % MaxLocks;
        return Locks[lockIndex];
    }
}

This technique (which I gather is called lock striping) offers much more concurrency than a single lock object while avoiding the out-of-control memory growth of dictionaries and interned strings. I decided to write about it after spending an entire afternoon searching for things like "named lock" and coming up empty. It wasn't until I finally thought to look at the details of sp_getAppLock procedure in SQL server function that I found myself on the right track.

Despite being widely used (Google's Guava library has a reusable implementation), there does't seem to be much discussion about it. In fact, I didn't even know the name of it until I stumbled across a mention of the jkeylockmanager project in a Stack Overflow discussion and browsed the source. (Which, happily, has a file named StripedKeyLockManager.)

Granted, this isn't something that comes up every day, and generally speaking locks are something to be avoided if at all possible. But every once in a while a situation like this does come up, and knowing what to look for makes all the difference.

Monday, October 8, 2012

Code Contracts by Example

So how does one get his feet wet with Design-by-Contract? I remember when I first started using Microsoft Code Contracts I immediately made a huge mess of my projects from which it took several weeks to fully recover. After a while I figured out what worked and what didn't and I've developed a habitual way of doing things that seems to work okay. I won't go so far as to say they are best practices, but they keep me out of trouble. So without delving too deep into the theory of DbC, here are a few of the patterns I use.


Constructor-based Dependency Injection

While property-based DI is possible with code contracts, it gets ugly really quickly. The only way I've been able to make it work is with a backing field and explicit null checks in the getter. Basically, if you have a public setter then all bets are off as far as invariants are concerned. Constructor-based injection, on the other hand, is very clean and straightforward, and allows you to offload some of the work onto the caller. Further, the static checker can leverage readonly fields to infer pre- and postconditions.

public class Foo
{
    private readonly IBar _bar;
    private readonly IBaz _baz;

    public Foo(IBar bar, IBaz baz)
    {
        Contract.Requires(bar != null);
        Contract.Requires(baz != null);
        
        Contract.Ensures(_bar != null);
        Contract.Ensures(_baz != null);

        _bar = bar;
        _baz = baz;
    } 

    [ContractInvariantMethod]
    private void Invariant()
    {
        Contract.Invariant(_bar = bar);
        Contract.Invariant(_baz = baz);
    }
}

The invariants are probably not absolutely necessary, but I've found that the combination of explicit postconditions in the constructor, combined with explicit invariants, speeds up the static analysis and generally has better results.


Conversion of One Nullable Type to Another

I use this frequently for mapping DTOs to domain objects and vice-versa. The contract literally states that either the method parameter is null or the return value will not be null. Put another way, it guarantees that the return value will not be null so long as the method parameter is not null.

public DomainType ToValueObject(DtoType dto)
{
    Contract.Ensures(dto == null || Contract.Result<DomainType>() != null);
    if (dto == null)
    {
        return null;
    }
    return new DomainType(...);
}


Value Objects

When I first started migrating from if/throw blocks I had a lot of preconditions that looked like this:

Contract.Requires(str != null);
Contract.Requires(!string.IsNullOrWhiteSpace(str));
Contract.Requires(Regex.IsMatch(str, @"^[a-zA-Z0-9]+$");
Contract.Requires(str.Length() >= 3);
Contract.Requires(str.Length() < 255);

And so on. Moreover, I found that I had a lot of methods sprinkled about with identical sets of preconditions--usually there was some value that wasn't central to my domain (a telephone number or domain name) that had certain validation requirements in the 3 or 4 places it was used. After performing this conversion I discovered a number of things:

  • The responsibility for validation shifted out of my method and onto the caller
  • There were far more call sites than methods being called, which meant that these preconditions now had to be checked in many more places than before
  • The static checker had to prove the preconditions were met at every call site
  • The maintenance burden had increased by an order of magnitude

This was obviously not a move in the right direction. However, all of these issues were resolved by replacing string typed arguments with value objects (not necessarily value types) that had the following characteristics:

  • Explicit verification in the constructor
  • Postconditions on the constructor ensuring the validity of the newly instantiated instance
  • Immutability

The result was that all of the explicit checks moved to one place (the value object constructor) and all instances of the value object type are guaranteed to be always be valid (else the constructor would throw).

I found it helpful to put the validation logic into a public static IsValid method so that callers have a means to defensively validate input without catching exceptions. The result is something like this:

public class ValueObject
{
    private readonly string _value;

    public ValueObject(string str)
    {
        Contract.Ensures(!string.IsNullOrWhiteSpace(_string));
        Contract.Ensures(_string.Length >= 5);
        Contract.Ensures(_string.Length <= 15);
        if (!IsValid(str))
        {
            throw new ArgumentException();
        }
        _string = str;
    }

    public static bool IsValid(string str)
    {
        Contract.Ensures(Contract.Result<bool>() == false || !string.IsNullOrWhiteSpace(str));
        Contract.Ensures(Contract.Result<bool>() == false || str.Length >= 5);
        Contract.Ensures(Contract.Result<bool>() == false || str.Length <= 15);

        if (string.IsNullOrWhiteSpace(str)) return false;
        if (str.Length < 5) return false;
        if (str.Length > 15) return false;
        return true;
    }

    [ContractInvariantMethod]
    private void Invariant()
    {
        Contract.Invariant(!string.IsNullOrWhiteSpace(_string));
        Contract.Invariant(_string.Length >= 5);
        Contract.Invariant(_string.Length <= 15);
    }
}

The contracts for the method calls then could be reduced to simple Contract.Requires(arg != null) checks, which are much easier to prove. This also works well with numeric types such as prices, quantities, percentages, and other such range-restricted values.


Conclusion

DbC requires a lot of investment up front, but it does offer a lot of value. The trick is enforcing contracts that add value and letting other things go. For example, a telephone number may need to be validated against a regular expression, but it usually isn't necessary to express that as a postcondition, especially if none of the callers depend on that fact. Often it's enough to use an if/throw block and leave it at that. In fact, that last point bears repeating: contracts are not a wholesale replacement for if/throw blocks, and are actually inferior in many cases.

It should also be said that DbC alone is no substitute for good design and good programming. If a method has a laundry list of contracts, then it might be that there are simply too many parameters, or too many dependencies between parameters. Sometimes splitting a method into multiple methods with different parameters, or encapsulating a set of parameters into a new type of object will completely obviate the need for complex preconditions. Convoluted preconditions are probably an indication that a method is in need of refactoring, which is valuable in and of itself.

Bottom line, the point of DbC is to formally specify things that both the caller and the callee should be responsible for, so contracts should be limited to things that should have been obvious or inferred to begin with (such as null checks). There are many conditions that are not the responsibility of the caller and should continue to be handled during runtime within the method (such as business logic and complex validation requirements). Done right, DbC will simply help you prove what you already assumed in the first place and identify places in your code where the assumptions are met.

Thursday, October 4, 2012

More on Non-nullable Reference Types

I was thinking about this some more today, and it occurred to me that a very simple construct could achieve what is being asked for without making any changes to the language or tools. Nullable value types (structs) were first implemented with an explicit wrapper class; it wasn't until later that the ValueType? shorthand appeared. With implicit operators, we could basically do the same for non-nullable reference types:

public struct NotNull<T> : IEquatable<T>, IEquatable<NotNull<T>> where T: class
{
    private T _value;

    public NotNull(T value)
    {
        if (value == null)
        {
            throw new ArgumentNullException("value");
        }
        _value = value;
    }

    public T Dereference()
    {
        if (_value == null)
        {
            throw new NullReferenceException();
        }
        return _value;
    }

    public override bool Equals(object other)
    {
        if (ReferenceEquals(null, other)) 
        {
            return false;
        }
        if (other is NonNullable<T>)
        {
            return Equals((NotNull<T>)other);
        }
        if (other is T)
        {
            return Equals((T)other);
        }
        
        return false;
    }

    public bool Equals(NotNull<T> other)
    {
        return Equals(other._value);
    }

    public bool Equals(T other)
    {
        if (ReferenceEquals(null, other))
        {
            return false;
        }
        return Equals(Dereference(), other);
    }

    public int GetHashCode()
    {
        return Dereference().GetHashCode();
    }

    public static bool operator ==(NotNull<T> left, NotNull<T> right)
    {
        return Equals(left, right);
    }

    public static bool operator !=(NotNull<T> left, NotNull<T> right)
    {
        return !Equals(left, right);
    }

    public static implicit operator NotNull<T>(T value)
    {
        return new NotNull<T>(value);
    }

    public static implicit operator T(NotNull<T> notNullValue)
    {
        return notNullValue.Dereference();
    }
}

This does not get rid of NullReferenceExceptions, but it does bake in null checks into the code and makes for some interesting syntax:

public static void Main(string[] args)
{
    if (args.Length < 1) throw new Exception();
    // Implicit conversion to NotNull<string> will throw at call site
    // if args[0] is null
    Method(args[0]);
}

public static NotNull<string> Method(NotNull<string> stringValue)
{
    // Implicit conversion from NotNull<string> to string will
    // call NotNull<T>.Dereference(), which will throw in the case
    // that default(NotNull<string>) was passed in.
    string foo = stringValue;
    return foo + "bar";
}

It's not perfect. I used a struct because it's a value type that can never be null, so we don't have to worry about the nullity of the NotNull<T> itself. However, all structs have a default constructor that cannot be overridden, which means that if default(Nullable<T>) is used then the internal _value field will not be properly initialized. So the Dereference() method is implemented such that it will throw a NullReferenceException if _value in this case.

So what does this actually achieve? Well, a couple of things. First, it serves to document the method prototype. Obviously the caller is expecting a non-null value and/or ensures that the return value is not null. Second, it does enforce null checks as close to the call site as possible, which should prevent null references from making it too far. This is beneficial in that it would prevent NullReferenceExceptions from occurring within third-party code that may not have debugging enabled.

When dealing with anything more complicated than a single number or character, we need pointers, even with fancy managed languages like C# and Java. And unless they have something to point to, uninitialized references are here to stay. Syntactic candy and helper classes only go so far. I still contend that design-by-contract is the way to go.

Wednesday, October 3, 2012

Non-nullable Reference Types

A few days ago on InfoQ I saw a link to this blog post offering a solution to "The Billion Dollar Mistake": allowing null references. The proposal, non-nullable reference types, is designed to replace this:

/// <exception cref="ArgumentNullException">
///     Thrown if <paramref name="argument"/> is null.
/// </exception>
public void Method(SomeType argument)
{
    if (argument == null)
    {
        throw ArgumentNullException("argument");
    }
    // Do stuff...
}

With something like this:

public void Method(SomeType! argument)
{
    // Do stuff...
}

Of course complications arise with arrays of non-nullable reference types and with the methods that feature non-nullable output parameters. There are workarounds for those issues, but the result is a convoluted syntax and unnecessary overhead. But I think the main problem is that we're looking at the problem from the wrong direction.

I think we have to accept that reference types are nullable, period. There will always be a case in which a reference has not yet been or may never be initialized. However, we can stipulate that a caller must provide a properly initialized reference when invoking a function, and we can promise that the results of our function will not be null under normal program flow.

This isn't a new idea. "Design by Contract" has been around since the 80s in the Eiffel programming language. More recently it has reemerged with Spec# and Code Contracts tool set from Microsoft. And it works. For example, this:

public void Method(SomeType argument)
{
    Contract.Requires(argument != null);
    // Do something...
}

... will cause the static analysis tool to verify that all calls to that method within scope have verified that argument reference is not null before making the call. And it doesn't require new keywords, new syntax, compiler enhancements, or breaking changes to existing code.

While I would like to see pre- and post-conditions baked into the language itself (ala Eiffel or Spec#), I think that the "Billion Dollar Problem" is largely solved with the tools we already have.

Tuesday, October 2, 2012

Code Formatting in Blogger

I've several hours of research, trial, and error, I've finally come across a workable solution for formatting code snippets in Blogger. Here are the basic steps:
  1. From your dashboard view, click "Template" and then "Edit HTML".  A modal confirmation dialog will appear.  Click "Proceed".
  2. Find the <head> tag and insert the following on the next line:
    <link href='https://sites.google.com/site/itswadesh/codehighlighter/shCore.css' rel='stylesheet' type='text/css' />
        <link href='http://sites.google.com/site/itswadesh/codehighlighter/shThemeDefault.css' rel='stylesheet' type='text/css' />
        <script src='http://sites.google.com/site/itswadesh/codehighlighter/shCore.js' type='text/javascript' />
        <script src='http://sites.google.com/site/itswadesh/codehighlighter/shBrushCSharp.js' type='text/javascript' />
        <script src='http://sites.google.com/site/itswadesh/codehighlighter/shBrushJava.js' type='text/javascript' />
        <script src='http://sites.google.com/site/itswadesh/codehighlighter/shBrushCss.js' type='text/javascript' />
        <script src='http://sites.google.com/site/itswadesh/codehighlighter/shBrushXml.js' type='text/javascript' />
        <script type='text/javascript'>
            // Required for Blogger:
            SyntaxHighlighter.config.bloggerMode = true;
            // Set to true to enable line numbers:
            SyntaxHighlighter.defaults['gutter'] = false;
            // Apply formatting:
            SyntaxHighlighter.all();
        </script>
    

  3. Save the template

Once your template is updated, simply wrap your code snippets in a <pre> tag with a special class:

<pre class="brush: csharp">
public class Test
{
    public string Property { get; set; }

    public void Method()
    {
    }
}
</pre>

The result should look something like this:
public class Test
{
    public string Property { get; set; }

    public void Method()
    {
    }
}

The full list of brushes can be found here. Note that the HTML snippet in step 2 above only imports the C#, Java, XML, and CSS brushes. If, for example, you wanted to use Erlang, you would also have to include the following <script> tag:

    <script src='http://sites.google.com/site/itswadesh/codehighlighter/shBrushErlang.js' type='text/javascript' />

Wednesday, July 18, 2012

20 Questions

In the game 20 questions one player thinks of something and the other players ask yes or no questions in an attempt to determine what the first player is thinking of.  The first player considers each question in light of his privately held information and replies with the appropriate response.

This is a great model for encapsulation.  The first player thinks of an object and holds it in memory, and the details of the object are not available to the other players (private state).  Other player ask questions (invoke behaviors) to gather information about the object.  The behaviors are limited to yes or no questions and consist mostly of a common, predictable set of useful questions:  Is it an animal, vegetable, or mineral?  Is it bigger or smaller than a breadbox? Is it something you eat? etc.

Suppose the game ends without a successful guess, and the first player thinks of another object for the next round of questions.  The new object replaces the previous one in his mind, and the other players repeat the questioning process.  Are the previous set of questions still valid?  Absolutely.  Are they relevant?  For the most part.  Are they useful?  Probably.

The internal state has changed, but the interactions have not.  The same set of behaviors still applies although it may produce a different set of responses.  This is wonderful if we are writing a 20 questions simulator, but how does this apply to real world business objects?

Suppose we are modeling an object that represents an order.  Right off the bat we are told that the order can have the following statuses: New, Processing, Shipped, Completed, and Canceled.  So we naively create an OrderStatus enumeration with those values and model the Order object like so:

public class Order {
    public OrderStatus Status { get; private set;}

    public Order() {
        Status = OrderStatus.New;
    }

    public void Submit() {
        if(Status == OrderStatus.Canceled)
            throw new OrderException("Already canceled");
        if(Status != OrderStatus.New)
            throw new OrderException("Already submitted");
        Status = OrderStatus.Processing;
    }

   public void Ship() {
       if(Status == OrderStatus.New)
           throw new OrderException("Not submitted");
       if(Status == OrderStatus.Shipped)
           throw new OrderException("Already shipped");
       if(status == OrderStatus.Canceled) 
           throw new OrderException("Already canceled");
       if(status == OrderStatus.Completed) 
           throw new OrderException("Already completed");
       Status = OrderStatus.Shipped;
   }

   public void Deliver() {
        if(Status == OrderStatus.New) 
            throw new OrderException("Not submitted");
        if(Status == OrderStatus.Processing) 
            throw new OrderException("Not shipped");
        if(status == OrderStatus.Canceled) 
            throw new OrderException("Already canceled");
        if(status == OrderStatus.Completed) 
            throw new OrderException("Already completed");
       Status = OrderStatus.Completed;
   }
   
   public void Cancel() {
        if(status == OrderStatus.Shipped) 
            throw new OrderException("Already shipped");
        if(status == OrderStatus.Canceled) 
            throw new OrderException("Already canceled");
        if(status == OrderStatus.Completed) 
            throw new OrderException("Already completed");     
        Status = OrderStatus.Canceled;
    }
}

Now, as soon as that hits source control we’re told that there is also an Invalid status that would prevent the order from being shipped.  That value must then be added to the enum and the Ship() method must be modified to enforce the new business rule.  Also, any reference to Order.Status will need to be evaluated to ensure that the new enum value does not break existing logic—perhaps there is a switch statement with cases for the first set of values known at the time and a default block that throws an exception.  If the order ever enters the Invalid state then such code would fail in undefined ways.

Even if such concerns could be easily addressed, suppose yet another new requirement dictates that cancelations should have an effective date that can be in the future, and that there should be a distinction between orders that have been canceled versus orders that are currently canceled.  Such a change would require a change in the representation of internal state, with additional properties, which would affect code downstream.

What what if the original Order object was instead written in such a way that it’s state was exposed with 20-questions style behaviors?

public class Order {
    private OrderStatus _status;

    public bool CanBeSubmitted {
        get { return _status == OrderStatus.New; }
    }
    public bool IsSubmitted { 
        get { return _status == OrderStatus.Processing; }
    }
    public bool HasBeenSubmitted { 
        get { return _status != OrderStatus.New; }
    }
    public bool IsReadyToShip { 
        get { return _status == OrderStatus.Procesisng; }
    }
    public bool HasBeenShipped { 
        get { return _status == OrderStatus.Shipped; }
    }
    public bool IsCanceled { 
        get { return _status == OrderStatus.Canceled; }
    }
    public bool IsCompleted { 
        get { return _status == OrderStatus.Completed; }
    }

    public Order() {
        Status = OrderStatus.New;
    }

    public void Submit() {
        if(IsCanceled) 
            throw new OrderException("Order has been canceled");
        if(HasBeenSumitted) 
            throw new OrderException("Order already submitted");
        Status = OrderStatus.Processing;
    }

    public void Ship() {
        if(IsCanceled) 
            throw new OrderException("Order has been canceled");
        if(IsCompleted) 
            throw new OrderException("Order has been completed");
        if(HasBeenShipped) 
            throw new OrderException("Order has already been shipped");
        if(!IsReadyToShip) 
            throw new OrderException("Order not ready to ship");
        Status = OrderStatus.Shipped;
    }

    public void Deliver() {
        if(IsCanceled) 
            throw new OrderException("Order has been canceled");
        if(IsCompleted) 
            throw new OrderException("Order has been completed");
        if(!HasBeenShipped) 
            throw new OrderException("Order has not been shipped");
        Status = OrderStatus.Completed;
    }
   
    public void Cancel() {
        if(IsCanceled)
            throw new OrderException("Order has been canceled");
        if(IsCompleted)
            throw new OrderException("Order has been completed");
        if(HasBeenShipped) 
            throw new OrderException("Order has already been shipped");
        Status = OrderStatus.Canceled;
     }
}

Now the new requirements can be folded in easily by changing the internal state and adding new behaviors, while leaving the existing behaviors as they are:

public class Order {
    private bool _submitted;
    private bool _invalid;
    private bool _processed;
    private bool _shipped;
    private bool _canceled:
    private DateTime _cancelationDate;
    private bool _completed;

    public bool CanBeSubmitted { 
        get { return !_submitted && !_canceled; }
    }
    public bool IsSubmitted { 
        get { return _submitted && !_processed && !_canceled; }
    }
    public bool HasBeenSubmitted { get { return _submitted; } }
    public bool IsReadyToShip { 
        get { return !_invalid && _processed && !_shipped && !_canceled; }
    }
    public bool HasBeenShipped { get { return _shipped; } }
    public bool IsCanceled { 
        get { return _canceled && DateTime.Now >= _cancelationDate; }
    }
    public bool IsCompleted { get { return _completed; } }

    // New behaviors
    public bool IsInvalid { return _invalid; }
    public bool HasBeenCanceled { return _canceled; }

    public Order() {
    }

    public void Submit() {
        if(IsCanceled) 
            throw new OrderException("Order has been canceled");
        if(HasBeenSumitted) 
            throw new OrderException("Order already submitted");
        _submitted = true;
    }

    public void MarkInvalid(string reason) {
        _invalid = true;
    }

    public void MarkValid()
    {
        _invalid = false;
    }

    public void Ship() {
        if(IsCanceled) 
            throw new OrderException("Order has been canceled");
        if(IsCompleted) 
            throw new OrderException("Order has been completed");
        if(HasBeenShipped) 
            throw new OrderException("Order has already been shipped");
        if(!IsReadyToShip) 
            throw new OrderException("Order not ready to ship");
        if(IsInvalid)
            throw new OrderException("Order not valid");
        _shipped = true;
    }

   public void Deliver() {
       if(IsCanceled) 
           throw new OrderException("Order has been canceled");
       if(IsCompleted) 
           throw new OrderException("Order has been completed");
       if(!HasBeenShipped) 
           throw new OrderException("Order has not been shipped");
       _completed = true;
   }

   public void Cancel() {
       Cancel(DateTime.Now);
   }   

   public void Cancel(DateTime asOfDate) {
        if(IsCanceled)
            throw new OrderException("Order has been canceled");
        if(IsCompleted)
            throw new OrderException("Order has been completed");
        if(HasBeenShipped) 
            throw new OrderException("Order has already been shipped");
        _canceled = true;
        _cancelationDate = asOfDate;
    }
}

Notice that because the object calls these behaviors internally, the method bodies themselves did not change much (if at all).  This provides a good indication that downstream consumers will also be protected against the changes that were made.

That isn’t to say that all state exposed by objects should be boolean in nature.  But when choosing the types of data to expose, it’s helpful to consider how those types might change over time.  Exposing enums directly is probably not a good idea most of the time, but descriptive strings and public value objects are probably safe.  The point is that external callers should only be able to access the information that is required and no more, and usually this can be elegantly handled by a series of very simple behaviors that enable the called object hide (and protect others from) its logic.

Friday, June 29, 2012

Objects Are People, Too

Determining what state or behaviors to expose on an object can be difficult.  We all know the basic rules—encapsulate logic, only expose immutable value objects, and so on—but putting those rules into practice does not come naturally.  In fact, given our heritage of anemic, relational models, it’s almost unnatural.  Several years ago I remember reading about SOLID and other OOP principles and thinking to myself, how on earth would you persist that?

Of course not all objects are persistent, and having the benefit of experience I now know that the view, domain, and persistence models need not be one and the same.  That being the case, there are incredible benefits to encapsulation, if done properly.  But how exactly does one put aside relational habits?

One trick I have is to imagine objects have personalities and imagine how they would react if I asked certain questions or requested certain behaviors.  For example, suppose I had a Person object and I wanted to know where they were from.  If it were a real person, I would simply ask him, “Where are you from?”.  The person would then think about the places he has lived, how long he has lived there, whether he had family there, etc.  Eventually he would arrive at an answer and would provide it.

Now, my personal tendency would have been to model the Person object with a one-to-many collection of Residence (or similar) with public virtual getter and a protected/internal setter, which would map nicely onto a set of tables in a relational database using any number of ORM tools.  And given a public PlacesOfResidence property, any caller can iterate through it and make whatever judgment he likes about where the person might be from.

Bringing that back to the real-life example, how would a person react if you (a stranger) walked up to them and asked for a complete history of all of the places they lived, when they lived there, how long they lived there, whether they have family there, etc.?  And, given that information, would you then know definitively where the person was “from”?  Of course not.

So the Person object needs a GetWhereFrom behavior that encapsulates that logic.  Further, the full list of Residences should not be exposed via any public or protected/internal method.  And finally, chances are that the GetWhereFrom behavior should not return a Residence, but rather some kind of immutable Location value object that does not reveal more than the question that was asked.

Now, knowing where the person is from, what else might one ask?  How about, “Were you born there?” or “How long did you live there?” or “Do you have family there?”  These are all excellent opportunities for encapsulated logic and could be realized as behaviors like WasBornIn(Location), GetLengthOfResidence(Location), HasFamilyIn(Location).

An object does not know who might call it, so all callers must be treated as strangers.  They should not be trusted.  An object should jealously guard its secrets (its state), only responding to the behaviors that are exposed, and only then with very simple and direct answers.  This will reduce coupling and avoid leaky abstractions, allowing the freedom to change how the answers are calculated without impacting callers.
In the next post I’ll talk about the internal representation of state versus exposed state, and practical ways that proper encapsulation can improve maintainability.