F# and the Open/Closed Principle

One of the advantages of using F# is that it is a .NET language.  Although F# is a functional-first language, it also supports object-oriented constructs.  One of the most powerful (indeed, the most powerful) technique in OO programming is using interfaces to follow the Open/Closed principle.  If you are not familiar, a good explanation of Open/Closed principle is found here.

As part of the F# for beginners dojo I am putting on next week, we are consuming and then analyzing Twitter.  The problem with always making calls to Twitter is that

1) The data changes every call

2) You might get throttled

Therefore, it makes good sense to have an in-memory representation of the data for testing and some Twitter data on disk so that different experiments can be run on the same data to see the result.  Using Interfaces in F# makes this a snap.

First, I created an interface:

  1. namespace NewCo.TwitterAnalysis
  2.  
  3. open System
  4. open System.Collections.Generic
  5.  
  6. type ITweeetProvider =
  7.    abstract member GetTweets : string -> IEnumerable<DateTime * int * string>

Next, I created the actual Twitter feed.  Note I am using TweetInvi (available on Nuget) and that this file has to be below the interface in the solution explorer:

  1. namespace NewCo.TwitterAnalysis
  2.  
  3. open System
  4. open System.Configuration
  5. open Tweetinvi
  6.  
  7. type TwitterProvider() =
  8.     interface ITweeetProvider with
  9.         member this.GetTweets(stockSymbol: string) =
  10.             let consumerKey = ConfigurationManager.AppSettings.["consumerKey"]
  11.             let consumerSecret = ConfigurationManager.AppSettings.["consumerSecret"]
  12.             let accessToken = ConfigurationManager.AppSettings.["accessToken"]
  13.             let accessTokenSecret = ConfigurationManager.AppSettings.["accessTokenSecret"]
  14.         
  15.             TwitterCredentials.SetCredentials(accessToken, accessTokenSecret, consumerKey, consumerSecret)
  16.             let tweets = Search.SearchTweets(stockSymbol);
  17.             tweets
  18.                 |> Seq.map(fun t -> t.CreatedAt, t.RetweetCount, t.Text)

 

I then hooked up a unit (integration, really) test

  1. [TestClass]
  2. public class UnitTest1
  3. {
  4.     [TestMethod]
  5.     public void GetTweetsUsingIBM_returnsExpectedValue()
  6.     {
  7.         ITweeetProvider provider = new TwitterProvider();
  8.         var actual = provider.GetTweets("IBM");
  9.         Assert.IsNotNull(actual);
  10.     }
  11. }

Sure enough, it ran green with actual Twitter data coming back:

image

I then created an In-Memory Tweet provider that can be used to:

1) Provide repeatable results

2) Have 0 external dependencies so that I can monkey with the code and a red unit test really does mean red

Here is its implementation:

  1. namespace NewCo.TwitterAnalysis
  2.  
  3. open System
  4. open System.Collections.Generic
  5.  
  6. type InMemoryProvider() =
  7.     interface ITweeetProvider with
  8.         member this.GetTweets(stockSymbol: string) =
  9.             let list = new List<(DateTime*int*string)>()
  10.             list.Add(DateTime.Now, 1,"Test1")
  11.             list.Add(DateTime.Now, 0,"Test2")
  12.             list :> IEnumerable<(DateTime*int*string)>

The only really interesting thing is the smiley/bird character (: >).  F# implements interfaces a bit differently than what I was used to –> F# implements interfaces explicitly.  I then fired up a true unit test and it also ran green:

  1. [TestClass]
  2. public class InMemoryProviderTests
  3. {
  4.     [TestMethod]
  5.     public void GetTweetsUsingValidInput_ReturnsExpectedValue()
  6.     {
  7.         ITweeetProvider provider = new InMemoryProvider();
  8.         var tweets = provider.GetTweets("TEST");
  9.         var tweetList = tweets.ToList();
  10.         Int32 expected = 2;
  11.         Int32 actual = tweetList.Count;
  12.         Assert.AreEqual(expected, actual);
  13.     }
  14. }

Finally, I created a file-system bound provider so that I can download and then hold static a large dataset.  Based on past experience dealing with on-line data sources, getting data local to run multiple tests against is generally a good idea.  Here is the implementation:

  1. namespace NewCo.TwitterAnalysis
  2.  
  3. open System
  4. open System.Collections.Generic
  5. open System.IO
  6.  
  7. type FileSystemProvider(filePath: string) =
  8.     interface ITweeetProvider with
  9.         member this.GetTweets(stockSymbol: string) =
  10.             let fileContents = File.ReadLines(filePath)
  11.                                 |> Seq.map(fun line -> line.Split([|'\t'|]))
  12.                                 |> Seq.map(fun values -> DateTime.Parse(values.[0]),int values.[1], string values.[2])
  13.             fileContents

And the covering unit (integration really) tests look like this:

  1. [TestClass]
  2. public class FileSystemProviderTests
  3. {
  4.     [TestMethod]
  5.     public void GetTweetsUsingValidInput_ReturnsExpectedValue()
  6.     {
  7.         var baseDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
  8.         var testFile = Path.Combine(baseDir, "TweetData.csv");
  9.         ITweeetProvider provider = new FileSystemProvider(testFile);
  10.         var tweets = provider.GetTweets("TEST");
  11.         var tweetList = tweets.ToList();
  12.         Int32 expected = 2;
  13.         Int32 actual = tweetList.Count;
  14.         Assert.AreEqual(expected, actual);
  15.     }
  16. }

Note that I had to add the actual file in the test project. 

image

Finally, the F# code needs to include try..catches for the external calls (web service and disk) and some argument validation for the strings come in.

In any event, I now have 3 different implementations that I can swap out depending on my needs.  I love having the power of Interfaces combined with benefits of using a functional-first language.

WCF and Interfaces

I went back to my Road Alert project and I wanted to add modifiers to the geolocations to account for the seasonality of the alter types.  For example, there are 36% more crashes in May and 27% more crashes in November.

 image

To that end, I added some more tables to my database – a table for each of the seasonal factors.  I kept the database in third normal form:

image

and the updated the Entity Model on my service layer:

:image

I then need to update my service interface to account for the new data.  I noticed that all of the tables all had the same format: PK (Int32), FKs(Int32), TableValueId(Int32), and ModifierValue(Float).  The only variation is the TableValue – in the Month table it is 1-12, in the DayOfWeek it is 0-6, DayOfMonth is 1-31 and Hour is 0-23)

Channeling my Inner Uncle Bob, I created an interface for these data structures like so:

  1. public interface IAlertTypeModifier
  2. {
  3.     Int32 AlertTypeModifierId { get; set; }
  4.     Int32 AlertTypeId { get; set; }
  5.     Int32 ModifierId { get; set; }
  6.     Int32 ValueId { get; set; }
  7.     double Modifier { get; set; }
  8. }

 

I then updated the service interface like this:

  1. [ServiceContract(Namespace = "http://schemas.tff.com/2013/07/RoadAlert.Services&quot;)]
  2. public interface IRoadAlert
  3. {
  4.     [OperationContract]
  5.     Location GetLocation(Int32 locationId);
  6.  
  7.     [OperationContract]
  8.     List<Location> GetLocations();
  9.  
  10.     [OperationContract]
  11.     List<Location> GetLocationsForMultipleAlertTypes(List<Int32> alertTypeIds);
  12.  
  13.     [OperationContract]
  14.     AlertType GetAlertType(Int32 alertTypeId);
  15.  
  16.     [OperationContract]
  17.     List<AlertType> GetAlertTypes();
  18.  
  19.     [OperationContract]
  20.     IAlertTypeModifier GetAlertTypeModifier(Int32 alertTypeId, Int32 modifierId, Int32 valueId);
  21.     
  22.     [OperationContract]
  23.     List<IAlertTypeModifier> GetAlertTypeModifiers();
  24.  
  25.     [OperationContract]
  26.     List<IAlertTypeModifier> GetAlertTypeModifiersForAnAlertType(Int32 alertTypeId);
  27.  
  28.     [OperationContract]
  29.     List<IAlertTypeModifier> GetAlertTypeModifiersForAModifierId(Int32 modifierId);
  30.  
  31.     [OperationContract]
  32.     List<IAlertTypeModifier> GetAlertTypeModifiersForAnAlertTypeAndModifierId(Int32 alertTypeId, Int32 modifierId);
  33.  
  34. }

 

I then created the supporting internal methods to these public methods and ran them though my unit tests and the public methods ran green.  For example:

  1. [TestMethod]
  2. public void GetModifiers_ReturnExpectedValue()
  3. {
  4.     RoadAlert roadAlert = new RoadAlert();
  5.     List<IAlertTypeModifier> modifiers = roadAlert.GetAlertTypeModifiers();
  6.  
  7.     Int32 notExpected = 0;
  8.     Int32 actual = modifiers.Count;
  9.  
  10.     Assert.AreNotEqual(notExpected, actual);
  11. }

image

I then deployed the service to my web hosting provider and updated the service interface on my other tests.  Whn I did that, I ran into trouble:

 

  1. [TestMethod]
  2. public void GetModifiers_ReturnExpectedValue()
  3. {
  4.     RoadAlertClient client = new RoadAlertClient();
  5.     List<IAlertTypeModifier> modifiers = client.GetAlertTypeModifiers();
  6.  
  7.     Int32 notExpected = 0;
  8.     Int32 actual = modifiers.Count;
  9.  
  10.     Assert.AreNotEqual(notExpected, actual);
  11. }

 

With the exception:

Cannot implicitly convert type ‘System.Collections.Generic.List

And When I Googled on Bing, I found out that you can’t return interfaces because you can’t serialize interfaces.  Crap!  Looks like I need to concrete classes if I want to use WCF.

So now I have a choice:

1) Return each concrete type so I add 8 methods to the service interface (GetMonth, GetMonths, etc…)  Put these together on the client side

2) Return a more generic concrete class (equiv to an abstract class) and parse the results on the client

3) Use REST

Since I am already down the SOAP path on this project, I do not want to pivot to REST right now.  In order to offload processing from the client, I decided to clutter up my Service interface with more methods.  So I changed my interface like this:

  1. [ServiceContract(Namespace = "http://schemas.tff.com/2013/07/RoadAlert.Services&quot;)]
  2. public interface IRoadAlert
  3. {
  4.     [OperationContract]
  5.     Location GetLocation(Int32 locationId);
  6.  
  7.     [OperationContract]
  8.     List<Location> GetLocations();
  9.  
  10.     [OperationContract]
  11.     List<Location> GetLocationsForMultipleAlertTypes(List<Int32> alertTypeIds);
  12.  
  13.     [OperationContract]
  14.     AlertType GetAlertType(Int32 alertTypeId);
  15.  
  16.     [OperationContract]
  17.     List<AlertType> GetAlertTypes();
  18.  
  19.     [OperationContract]
  20.     AlertTypeDayOfMonthModifier GetAlertTypeDayOfMonthModifier(Int32 AlertTypeDayOfMonthModifierId);
  21.  
  22.     [OperationContract]
  23.     List<AlertTypeDayOfMonthModifier> GetAlertTypeDayOfMonthModifiers();
  24.  
  25.     [OperationContract]
  26.     AlertTypeDayOfWeekModifier GetAlertTypeDayOfWeekModifier(Int32 AlertTypeDayOfWeekModifierId);
  27.  
  28.     [OperationContract]
  29.     List<AlertTypeDayOfWeekModifier> GetAlertTypeDayOfWeekModifiers();
  30.  
  31.     [OperationContract]
  32.     AlertTypeHourModifier GetAlertTypeHourModifier(Int32 AlertTypeHourModifierId);
  33.  
  34.     [OperationContract]
  35.     List<AlertTypeHourModifier> GetAlertTypeHourModifiers();
  36.  
  37.     [OperationContract]
  38.     AlertTypeMonthModifier GetAlertTypeMonthModifier(Int32 AlertTypeMonthModifierId);
  39.  
  40.     [OperationContract]
  41.     List<AlertTypeMonthModifier> GetAlertTypeMonthModifiers();
  42. }

 

And because I don’t need to abstract the valueId, I renamed it to be more reflective of its intent.  For example:

AlertTypeDayOfWeekModifier.ValueId is now AlertTypeDayOfWeekModifier.DayOfWeekId

Also, I changed the PK to more intention revealing also:

AlertTypeDayOfMonthModifier.AlertTypeModifierId is now AlertTypeDayOfMonthModifier.AlertTypeDayOfMonthModifierId

I then ditched the interface and put the common fields into a base class:

  1. public abstract class AlertTypeModifier
  2. {
  3.     public Int32 AlertTypeId { get; set; }
  4.     public Int32 ModifierId { get; set; }
  5.     public double Modifier { get; set; }
  6.  
  7. }

 

And had each of the implementations like this:

  1. public class AlertTypeDayOfMonthModifier : AlertTypeModifier
  2. {
  3.     public Int32 AlertTypeDayOfMonthModifierId { get; set; }
  4.     public Int32 DayOfMonthId { get; set; }
  5. }

 

Which severs well enough.  Then it was just a question of updating the service.cs file with the implementation (an incredibly boring 15 minutes) and adding some tests.  I got green locally and then green via the web service.

image

So I guess the lesson learned is that you really can’t apply the Open/Closed principle using WCF Web Services.

Dependency Injection: Keeping It Simple

When I gave my talk at TriNug’s SIG about the SOLID principles, I whipped up an example of Dependency Injection (DI) that some people really liked.  I decided to blog about it.  Consider a basic console application that has a single Interface included – Animal.  The Animal interface looks like this:

public interface IAnimal
{
    void Talk();
    void Eat();
}

The Console application includes a couple of classes that implement the interface:

public class Elephant: IAnimal
{
    public void Talk()
    {
        Console.WriteLine("Trumpet");
    }

    public void Eat()
    {
        Console.WriteLine("Yummy Peanuts");
    }
}

public class Seal(): IAnimal 
{
    public void Talk()
    {
        Console.WriteLine("Ark Ark");
    }

    public void Eat()
    {
        Console.WriteLine("Yummy Fish");
    }
}

Then in the Main method, I want to inject in an animal at run time.  I could write something like this:

static void Main(string[] args)
{
    IAnimal animal = ????;
    animal.Talk();
    animal.Eat();
}

What I don’t want to do is to have a switch/if..then statement in the Main function because as new animals are added to my project, I would have to update existing code and violate the Open/Closed principle.  I know if a couple of ways around this problem:

  • Using a Dependency Injection Framework like Unity
  • Using Microsoft Extension Framework
  • Use a Factory Pattern
  • Injecting the name of the class and using Activator to resolve. Note that this name can come from a database call or a .config file.

A DI framework seems a bit too heavy for this kind of solution.  I tried MEF and quickly gave up, Using a factory pattern delays but does not alter the problem resolution.  I think the Activator keyword is the best solution to my problem.

To that end, I added a section in my .config file like this:

<configuration>
  <appSettings>
    <add key="animalTypeName" value="Tff.PoorMansDependencyInjection.Seal"/>
  </appSettings>
</configuration>

And then in my Main method:

String animalTypeName = ConfigurationManager.AppSettings["animalTypeName"].ToString();
Type animalType = Type.GetType(animalTypeName);
IAnimal animal = (IAnimal)Activator.CreateInstance(animalType);
animal.Talk();
animal.Eat();
Console.ReadKey();

And I get this:

image

Polymorphic Dispatch, Open/Closed Principle, and Notifications

I started on working on a new application last week – one that will read data from various sources, analyze the data, and then notify interested parties about the results of the analysis.  I started working on the notification piece first.  My first premise is that there can be an variety of notification methods and an infinite number of providers of the methods.  For example, a person can receive a notification via an email, a text, a phone call, an IM, an audio signal from their phone app, Twitter, Skype, Facebook, etc…   Each of these methods can be served up by a host of providers.  Since these providers change so quickly and new mechanisms arrive (and quickly become old mechanisms), it makes sense that this part of my application should be extensible as possible.

After trying a variety of scenarios and objects, I decided to concentrate on the core Interface – which is the Alert.  I created an interface like so:

public interface IAlert
{
    void Send();
}

I then created a class called Alertee that contains a collection of IAlerts with some other properties:

public class Alertee
{
    public Alertee()
    {
        this.AlertList = new List<IAlert>();
    }

    public Int32 AlerteeId { get; set; }
    public String FirstName { get; set; }
    public String LastName { get; set; }
    public List<IAlert> AlertList { get; set; }

}

Notice the Command/Query separation.   This class is a data structure that only has public properties.  I initially toyed with calling the Alertee “User” but “User” is such an overused word – most every implementation of IAlert already has a “User” class – and I am a big believer of domain-unique language (and I hate fully-qualifying my Instances) so I chose the less ambiguous if-not-a-real-word: “alertee”.

I then created an AlertFactory (a command class) like so:

public class AlertFactory
{
    public void SendAlerts(List<Alertee> alertees)
    {
        foreach (Alertee alertee in alertees)
        {
            foreach (IAlert alert in alertee.AlertList)
            {
                alert.Send();
            }
        }
    }
}

Notice that by using the IAlert interface, the dependency is inverted and that Alert Factory delegates responsibility of the actual alert implementation via calling the alert.Send().

With the interface, the POCO, and the Factory class ready, I then started implementing the different kinds of alerts.  My first stop was an email alert from the local SMTP server.  I coded this class like so:

public class LocalEmailAlert: IAlert
{
    private String _from = String.Empty;
    private String _to = String.Empty;
    private String _subject = String.Empty;
    private String _body = String.Empty;

    public LocalEmailAlert(String from, String to, String subject, String body)
    {
        if (String.IsNullOrEmpty(from))
            throw new AlertsException("from cannot be null or empty.");
        if (String.IsNullOrEmpty(to))
            throw new AlertsException("to cannot be null or empty.");
        if (String.IsNullOrEmpty(subject))
            throw new AlertsException("message cannot be null or empty.");
        if (String.IsNullOrEmpty(body))
            throw new AlertsException("message cannot be null or empty.");

        _to = to;
        _from = from;
        _subject = subject;
        _body = body;
    }

    public void Send()
    {
        SmtpClient smtpClient = new SmtpClient();
        MailMessage mailMessage = new MailMessage(_from, _to, _subject, _body);
        smtpClient.Send(mailMessage);
    }
}

A couple of things to note.  All of the values that the SMTP needs to use are passed in via the constructor (constructor injection) and these values are stored in private fields.  Also, the values are verified in the constructor and a generic exception is thrown.

I then went to one of the million email providers out there and picked one at random: MailJet.  I then coded up a MailJetEmailProvider like so:

public class MailJetEMailAlert: IAlert
{
    private String _mailServerName = "in.mailjet.com";
    private Int32 _mailServerPort = 465;
    private String _apiKey = String.Empty;
    private String _secretyKey = String.Empty;
    private String _from = String.Empty;
    private String _to = String.Empty;
    private String _subject = String.Empty;
    private String _body = String.Empty;

    public MailJetEMailAlert(String from, String to, String subject, String body)
    {
        if (String.IsNullOrEmpty(from))
            throw new AlertsException("from cannot be null or empty.");
        if (String.IsNullOrEmpty(to))
            throw new AlertsException("to cannot be null or empty.");
        if (String.IsNullOrEmpty(subject))
            throw new AlertsException("message cannot be null or empty.");
        if (String.IsNullOrEmpty(body))
            throw new AlertsException("message cannot be null or empty.");

        _to = to;
        _from = from;
        _subject = subject;
        _body = body;
    }

    public void Send()
    {
        MailMessage mailMessage = new MailMessage();
        mailMessage.From = new MailAddress(_from);
        mailMessage.To.Add(new MailAddress(_to));
        mailMessage.Body = _body;
        mailMessage.Subject = _subject;

        SmtpClient client = new SmtpClient(_mailServerName, _mailServerPort);
        client.EnableSsl = true;
        client.Credentials = new NetworkCredential(_apiKey, _secretyKey);
        client.Send(mailMessage);
    }
}

Notice that the constructor is exactly the same as the local email implementation.  The Mail-Jet specific code/fields are assigned locally and are unique only to the Mailjet class.  I suppose that I could pass those elements in via the constructor and then keep the values in the .config file – but that didn’t seem right to me.  I also could access the config file directly from this class  but that introduces an unneeded dependency – now this class has to worry about the config file (see if it exists, if the section is there, etc…) which is another reason that the class has to change – a violation of the Single Responsibility Principle.  The more I code, the more I think that the config file should be accessed only once and in 1 place (in Main) and those values are then passed into the classes that need it.  That is a blog post for another time – and certainly is against what Microsoft has recommended for many years.

In any event, I don’t think that having the MailJetspecific code embedded into the class is a bad idea  in fact I think it is a good idea.  If these values changes, this class has to be recompiled and redeployed (so what, this isn’t java where the calling assembly has to be recompiled) compared to having the UI being mail-jet aware (via its config) and then having the config file redeployed.  I would rather have a cleaner separation of concerns and have a recompile than a muddied SOC and no recompile.  Both scenarios need to be redeployed anyway.

Back to Mail, I then realized that the mail classes could derive from an abstract base class like so:

public abstract class MailAlert
{

    private String _from = String.Empty;
    private String _to = String.Empty;
    private String _subject = String.Empty;
    private String _body = String.Empty;

    public MailAlert(String from, String to, String subject, String body)
    {
        if (String.IsNullOrEmpty(from))
            throw new AlertsException("from cannot be null or empty.");
        if (String.IsNullOrEmpty(to))
            throw new AlertsException("to cannot be null or empty.");
        if (String.IsNullOrEmpty(subject))
            throw new AlertsException("message cannot be null or empty.");
        if (String.IsNullOrEmpty(body))
            throw new AlertsException("message cannot be null or empty.");

        _to = to;
        _from = from;
        _subject = subject;
        _body = body;
    }

}

The problem is that the derived class still needs to access these private fields – the protected scope solves that:

protected String _from = String.Empty;
protected String _to = String.Empty; 
protected String _subject = String.Empty;
protected String _body = String.Empty;

So the next problem is abstract base class does not have a constructor that takes zero arguments  which is required.  So I added a default empty constructor like so:

public MailAlert():
    this(String.Empty,String.Empty,String.Empty,String.Empty)
{

}

It now complies and I removed the duplicative code.  The sub-lesson here is that, as rule, don’t start with an abstract class.  Start with implementations and if there is lots of repetitive code, the consider refactoring to an abstract class.  Your covering unit tests will tell you if your refactor is wrong  and you are using unit tests, aren’t you?

I then tackled Text pushing via CDyne.  I added a reference to the CDyne Service (I love SOAP) in Visual Studio, received a developer key from CDyne, and wrote the following implementation:

public class CDyneTextAlert: IAlert
{
    private String _phoneNumber = String.Empty;
    private String _message = String.Empty;
    private Guid _licenseKey = new Guid("XXXXXXXXXXXXXXXXXXXXXXX");
    
    public CDyneTextAlert(String phoneNumber, String message)
    {
        if (String.IsNullOrEmpty(phoneNumber))
            throw new AlertsException("phoneNumber cannot be null.");

        if (String.IsNullOrEmpty(message))
            throw new AlertsException("message cannot be null.");

        _phoneNumber = phoneNumber;
        _message = message;
    }

    public void Send()
    {
        IsmsClient client = new IsmsClient();
        SMSResponse response = client.SimpleSMSsend(_phoneNumber, _message, _licenseKey);
    }
}

I then added a Twitter push like so:

public class TwitterAlert: IAlert
{
    private String _twitterUri = "http://twitter.com/statuses/update.json";
    private String _twitterUserId = String.Empty;
    private String _twitterPassword = String.Empty;
    private String _message = String.Empty;

    public TwitterAlert(String message)
    {
        if (String.IsNullOrEmpty(message))
            throw new AlertsException("message cannot be null.");
        
        this._message = message;
    }

    public void Send()
    {

        HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(_twitterUri);
        request.Credentials = new NetworkCredential(_twitterUserId, _twitterPassword);
        request.Timeout = 5000;
        request.Method = "POST";
        request.ContentType = "application/x-www-form-urlencoded";
        using (Stream requestStream = request.GetRequestStream())
        {
            using (StreamWriter streamWriter = new StreamWriter(requestStream))
            {
                streamWriter.Write(_message);
            }
        }
        WebResponse response = request.GetResponse();
    }
}

I then added a Phone notification from CDyne:

public class CDynePhoneAlert: IAlert
{
    String _phoneNumber = String.Empty;
    String _message = String.Empty;
    String _callerId = String.Empty;
    String _callerName = String.Empty;
    String _voiceId = String.Empty;
    String _licenseKey = "XXXXXXXXX";

    public CDynePhoneAlert(String phoneNumber, String message, String callerId, String callerName, String voiceId)
    {

        if (String.IsNullOrEmpty(phoneNumber))
            throw new AlertsException("phoneNumber cannot be null.");

        if (String.IsNullOrEmpty(message))
            throw new AlertsException("message cannot be null.");

        if (String.IsNullOrEmpty(callerId))
            throw new AlertsException("callerId cannot be null.");

        if (String.IsNullOrEmpty(callerName))
            throw new AlertsException("callerName cannot be null.");

        if (String.IsNullOrEmpty(voiceId))
            throw new AlertsException("voiceId cannot be null.");

        _phoneNumber = phoneNumber;
        _message = message;
        _callerId = callerId;
        _callerName = callerName;
        _voiceId = voiceId;

    }


    public void Send()
    {
        PhoneNotifySoapClient client = new PhoneNotifySoapClient("PhoneNotifySoap");
        NotifyReturn callReturnValue = client.NotifyPhoneBasic(_phoneNumber, _message, _callerId, _callerName, _voiceId, _licenseKey);
    }
}

I noticed that the message variable is being passed into the constructor in every IALert implementation so perhaps that should be added to the interface definition Send(String message) but then realized that each implementer might have its own requirements on the message.  For example, Twitter needs to check the number of characters:

public TwitterAlert(String message)
{
    if (String.IsNullOrEmpty(message))
        throw new AlertsException("message cannot be null.");

    if(message.Length > 140)
        throw new AlertsException("message is too long for Twitter.");
    
    this._message = message;
}

Also, what happens when the message is no longer a string – perhaps a .mp3 file with an recorded voice message to be sent to the phone?  Then the Send() method would have to overload an audioStream argument.

So instead of trying to build some class (or worse, some enum) of the different types messages that are passed in, I left it to the specific implementation.  This makes sense of the fluid nature of the distribution mechanisms in today’s technology landscape  – the API needs to be as flexible as possible.

So far, I have a solution that follows the Open/Closed principle.  As new distribution mechanisms come available, I just need to add a new class that implements the IAlert interface, add it to the Alertee’s Alerts collection, and it implements.  No other code needs to change.  I then ran into a bump – adding an Alert to the Alertee’s Alerts collection.

I added 1 more class to the project  – a Provider that creates alertes with instantiated Alerts.  I added a SqlAlerteeProvider figuring I will store each Alertee’s desired Alert mechanism (0 to infinity) in a Sql Server database so it looks like so:

public class SqlAlerteeProvider
{
    public Alertee GetAlertee(Int32 alerteeId)
    {
        return null;
    }

    public List<Alertee> GetAllAlertees()
    {
        return null;
    }

    public void UpdateAlertee(Alertee alertee)
    {

    }

    public void InsertAlertee(Alertee alertee)
    {

    }

    public void DeleteAlertee(Alertee aleertee)
    {

    }
}

However, I am deferring the implementation of the data store for as long as possible.  Who knows, I may find a different place to store the data.

So does application follow the open/closed principle?  It does up to the point of the Alertee Provider.  If a new alert needs to be created, a new class is added (ok with O/C) AND the GetAlertee code needs to be changed to account for the new provider (new fields in the database, etc..) (not OK with the O/C).  I suppose I can dig into making the provider follow the O/C, but that is a task for another day.

The important thing is that the calling application DOESN’T change – It just keeps calling SendAlerts() on the AlertFactory regardless of what else happens.