Condividi tramite


Fluent Interface for System.Identity – The Basics

<Author’s Note>

A very talented Developer I know just recently gave me some very succinct feedback on my blog - “good blog…too long”.

As I respect this Developer’s opinion quite highly (not to mention I always try to listen to Developers), I am going to start putting his suggestion into practice by chunking further posts into smaller pieces.

It is worthy to note that these smaller pieces will quite likely lead to more frequent posts – apologies in advance for any RSS bloat.

</Author’s Note>

 

Introduction

As I’ve written about previously, I’m highly interested in DSLs and Oslo’s System.Identity schema. Based on these two interests I recently decided that I would start exploring a Fluent Interface as an Internal DSL for the System.Identity schema. My motivations for this are two-fold:

  1. Give myself an excuse to play around with actual code
  2. Attempt to illustrate the power of the Party Model (via System.Identity) using an avenue that may be more appealing than (as much as it pains me to type this ;-) UML

Being both an Architect and unrepentant Object-Oriented bigot, I’ve convinced myself that this exploration will adhere to number of “modern” OO Software Engineering best practices. My intent with taking the tack is to hit a number of coding topics that are near and dear to my cold and black Architect heart. We shall see if I will be successful in this regard.

 

Fluent Interface Architectural/Design Principles

Throughout this subseries on System.Identity I plan to adhere to a number of Architectural/Design specifications in crafting the interface code:

  1. The architectural specification of the Law of Demeter
  2. Martin Fowler’s design specification for a Parsing Layer
  3. Domain-Driven Design’s (DDD’s) design specification for Aggregates
  4. The Pragmatic Bookshelf’s design specification for “Tell, don’t ask
  5. Design specifications from the concepts included in Prefactoring

As we shall see, application of these five specifications will have very interesting consequences on the shape of the code. Indeed, I wouldn’t be surprised at all if the code’s shape ends up looking quite a bit different from “run of the mill” C#. One potential effect of this might be that the Command-Query API will tend to look more like a Fluent Interface. 

To be honest, I expect that quite a number of readers will disagree with either my interpretations of these specifications, or they will disagree with my practical application of these specifications in the code. Some readers will undoubtedly disagree with both.

This is 100% by design and I sincerely look forward to any discussion on these topics.

 

Starter Class

As we saw in the UML models of System.Identity, every class had two basic attributes – an Id field and a Folder field. For the sake of convenience we’ll create an abstract base class that encapsulates this universality:

 

    1: public abstract class SystemIdentityBase
    2: {
    3:     private Int64 Id { get; set; }
    4:     private int Folder { get; set; }
    5:  
    6:     public SystemIdentityBase ()
    7:     {
    8:         Folder = 100;
    9:     }
   10: }

What some folks might find interesting in the snippet above is that the automatic properties on lines 3 and 4 are marked private. One of the design specifications from Prefactoring is that it is better to put a level of indirection between the state of an object and the object’s operations. In terms of early versions of C# that meant only accessing a class’ member variables via a property – even in private helper methods.

Since automatic properties can’t hold any business logic or data access code, I would argue that automatic properties are nothing more than syntactic sugar for old school member variables. Therefore, under Prefactoring thinking, an additional level of indirection is required. In accordance with this design specification, the automatic properties are marked private.

We can now augment SystemIdentityBase’s public interface with some methods that adhere to Prefactoring, the Law of Demeter and the “Tell, don’t ask” specifications:

    1: public bool IsInFolder ( int folder )
    2: {
    3:     return Folder == folder;
    4: }
    5:  
    6: public void MoveToFolder ( int folder )
    7: {
    8:     Folder = folder;
    9: }

The IsInFolder() method conforms to “Tell, don’t ask” specification by disallowing clients of SystemIdentityBase instances from directly retrieving the Folder value and basing decisions on that value. To use a conversational metaphor, this results in statements along the lines of “Tell me if you’re currently in this folder” rather than “Give me your current folder”. This is a core aspect of “Tell, don’t ask” and simultaneously increases cohesion and lowers coupling in the code. Another benefit of shaping the code in this manner is an increase in the “fluency” of the Command-Query API.

In terms of the Law of Demeter, the IsInFolder() method is compliant with the architectural specification because it prevents code like the following:

    1: var testValue = 125;
    2:  
    3: if ( testValue == someEntity.Folder )
    4: {
    5:     // Do some cool logic here
    6: }

While the snippet above seems innocuous enough, what really happens behind the scenes is the following:

    1: var testValue = 125;
    2:  
    3: if ( someEntity.Folder.Operator == ( testValue ) )
    4: {
    5:     // Do some cool logic here
    6: }

Strictly speaking, this “two dot” situation is violation of the Law of Demeter (being quite the stickler here, aren’t I? ;-). Compare the above code to the following:

    1: var testValue = 125;
    2:  
    3: if ( someEntity.IsInFolder ( testValue ) )
    4: {
    5:     // Do some cool logic here
    6: }

Call me an OO junkie, but I just like the look of this last code snippet a lot better – even though I’ve personally written a ton of code that uses the straight “property-ask, then compare” approach. The code just feels like OO should. I also know that from first-hand experience that this style of code is easier to maintain over long periods (say 5 year or so) in Production.

Compared to IsInFolder(), the MoveToFolder() method is a straight forward “setter” method for the Folder automatic property and really doesn’t bear a lot of explanation. That being said, it is interesting to note that we again have another increase in the fluency of the Command-Query API from compliance with the chosen architectural/design specifications. Take the following code snippet as an example:

    1: var testValue = 125;
    2:  
    3: someEntity.MoveToFolder ( testValue );

For the time being I’ll leave the Id fields of the entities alone. I’ve got two main reasons for this:

  1. The Ids are really just RDBMS implementation details – a good ORM framework (e.g., NHibernate) usually takes care of the administration of these things transparently
  2. Leaving out makes the posts shorter and we don’t miss any of the goodness

 

Next Time

For the next post in the series we’ll move to take a look at an implementation of the Command-Query API Kind class.

Until next time, thoughts greatly appreciated!

Comments