Call Us
Back to all

Coding Abstractions Part 2: Creating a Contract and First Provider

April 9, 2019
By
Steve Danner
Back to all
Share this article

This is the second post in a series of posts about coding abstractions into your applications.  In our first post, we discussed how to identify potential points of abstraction from a business point of view.  Abstractions are a technical concept, so it also takes some technical thought on breaking those points down.  The remaining posts in this series will focus more on the technical side of abstractions, while keeping and eye on the business problems we might be solving with them.  This post will focus on getting an application ready for abstractions by means of implementing a “contract”, as well as building out your first “provider”, which is normally the default functionality of an application.  In other words, the way you might build that application without an abstraction in place.

Creating a “Contract”

Once we have our abstraction point identified, you will need to create a contract, or interface between which your abstracted components will interact with the main application.  If you have never created something like this, the task can seem strange, and it may be difficult to figure out where to begin.  In almost any language, you are going to be creating an “Interface”, or a contract that defines the expected functionality of any implementing provider.  Java, .NET, and C++ all have the concept of an interface already baked in.  Languages like Ruby and Python don’t have a proper “interface” construct, but the concept of programming against common members, or functionality is certainly present.  I encourage you to read more about programming against interfaces if your language of choice doesn’t offer a proper “interface” construct.  For our examples, we will use C# from here on out.   If you already have an existing, non-abstracted component that has essentially already defined your abstraction point, it might be as simple as to just take the public methods and properties from the class and create an interface with the exact same members.  The general idea here is to identify common functionality that the main application can depend upon.  Going back to the file-syncing example from our first post, any Cloud Storage Provider we use might need the following interface with the included properties and functions (sample written in C#):

public interface ICloudProvider
{
  string Name { get; set; }
  string Url { get; set; }
  string UserName { get; set; }
  string Password { get; set; }
  string SourceDirectory { get; set; }
  string TargetDirectory { get; set; }

  bool StartFileSync();
  bool StopSync();
}

There might be more, of course, but this is just a conceptual interface.  It will be important that all provider-specific functionality be encapsulated, such that the main application doesn’t concern itself with those details.  It can be challenging to come up with a common interface that covers every provider implementation, since details about each individual implementation will start to surface once development has begun (long after your interface has been defined!).  It is even more challenging when you don’t know all of the providers from the onset of your project.  It’s common to have to adjust an interface after a few providers have been implemented.  Don’t be afraid to make these adjustments and add new members once you better understand the overarching requirements.  If you’ve already deployed an application, and have several third party provider implementations out there (consider someone else wrote a proprietary SharePoint file sync provider against your existing ICloudProvider interface), you will, of course have to worry about breaking those implementations.  However, there is still hope!  Often times, developers will create an abstract class, which would contain several common properties and methods, making it unnecessary for each provider to implement this functionality over and over again.  If you are to alter an interface, requiring a new property or method, consider placing a default implementation in an abstract class and advising providers to inherit the abstract class rather than implementing the interface directly.  Doing this from the get go will help alleviate versioning concerns later on.  It’s always possible you’ll have to break existing providers if you do change an interface or base class, but it should be avoided wherever possible.

Your First “Provider”

Before deciding whether to create an abstraction point in your application, there was undoubtedly some sort of default behavior that the application had already exhibited that should serve as the basis for your first provider, or implementation of that abstraction.  In our file syncing example, let’s say that initially, we knew that all of our target audience was going to use Microsoft’s OneDrive.  Perhaps our application even started as a file system to OneDrive synchronization application before we changed to allow different providers.  For our purposes, let’s focus on the case where there is no implementation in advance, and you’ve defined your abstraction point early on.  Creating the first provider is as simple as implementing the interface, or inheriting a common abstract class!  For simplicity, we’ll implement the interface with our OneDrive provider (again, code sample is written in C#).

public class OneDriveProvider : ICloudProvider
{
  public string Name { get; set; }
  public string Url { get; set; }
  public string UserName { get; set; }
  public string Password { get; set; }
  public string SourceDirectory { get; set; }
  public string TargetDirectory { get; set; }

  public bool StartFileSync()
  {
     //...actual code omitted
     return true;
  }

  public bool StopSync()
  {
     //...actual code omitted
     return true;
  }
  // supporting methods and properties go here...
}

The issue here is that if we add a member to our interface above, this implementation will be broken as it will no longer adhere to the interface!  So, if we were to put an abstract class in front of the interface first, we will no longer have that problem.  Consider the abstract class case:

public abstract class BaseCloudProvider : ICloudProvider
{
  public virtual string Name { get; set; }
  public virtual string Url { get; set; }
  public virtual string UserName { get; set; }
  public virtual string Password { get; set; }
  public virtual string SourceDirectory { get; set; }
  public virtual string TargetDirectory { get; set; }

  public abstract bool StartFileSync();  //force provider to provide this
  public abstract bool StopSync(); //force provider to provide this
  // supporting methods and properties go here...
}

public class OneDriveCloudProvider : BaseCloudProvider
{
  public bool StartFileSync()
  {
     //...actual code omitted
     return true;
  }

  public bool StopSync()
  {
     //...actual code omitted
     return true;
  }
  // supporting methods and properties go here...
}

Notice that now the OneDrive provider doesn’t have all the common property implementations as we’ve offloaded them to the base class.  Now if we add members to the interface, we can simply include a default implementation in the base, and the final concrete provider will not break!  As long as you declare the default implementation as “virtual” (in C#, in Java, this is default behavior), you can override the default functionality in your providers by recompiled and redeploying, but it’s no longer absolutely necessary.  Why use an interface at all when you can use abstract classes?  There are several reasons that we will cover in the 3rd and final post of this series. Hopefully, it’s now evident how the interface and provider are working together.  In our next post, we’ll focus on how to glue all of these pieces together, how to change providers in a clean, best-practices way and how the main application might consume the providers as our audience uses the application!