Web API Tutorials Part 3 : Translation Abstraction

There’s a famous quote in the world of Software Development:

“We can solve any problem by introducing an extra level of indirection.”

In my experience, this is almost certainly correct, this post will see us adding in an additional layer of Abstraction to allow us to simplify our Controller(s) and manage our Dependencies in a more straightforward manner.

Outcome

Last post saw us implement our Translation PCL into our Web API using Dependency Injection.  The problem is that our ITranslator Interface only handles a single Translator Implementation, such that when we inject from our Container we can’t currently translate more than one direction.  We’ll look into the why’s shortly, but by the end of the post we will have created :

  • ITranslatorService Interface;
  • TranslatorService Implementation and Unit Tests.

Implementation

Why the Abstraction?

We can currently only inject a single ITranslator into our application, which makes extending it problematic (we could use another container that supports instance keys but this is a bit of a hack).  So what are our options :

  1. An Interface for each Translator Type;
    • This is a step backwards as it binds each Controller to a specific Type, let’s rule this out.
  2. A Service that manages our instances of Translators;
    • Our Controller knows what Direction it wants to translate, the controller name tells us this much, what it doesn’t know is how to do it, this is what gets injected in.  A service that takes a Direction, along with the user input and returns the correct translation would meet our requirement.

ITranslatorService

Let’s go with Option 2.  What would this service look like?  We’ll need to

  • take a Direction and the User Input and return a string;
  • be able to add a Translator;
  • be able to find out what Translators the Service knows about.

Let’s define this with an Interface:

using System.Collections.Generic;

namespace MorseCoder.PCL.Interfaces
{
public interface ITranslatorService
{
void AddTranslator(string translatorKey, ITranslator translator);

ICollection<string> TranslatorKeys { get; }

string Translate(string translatorKey, string input);
}
}

TranslatorService

It would be nice if our TranslatorService dealt with N-Number of Translation Directions (aside from the fact we’re only interested in two!).

One simple way of implementing this would be to wrap a couple of if statements around a couple of instances of our Translators, but this binds our TranslatorService to specific Translators, which would be undesirable, let’s not do that.

Let’s wrap a few tests around our interface, unfortunately PCL’s referencing Windows 8.1 don’t support Reflection so we can’t use mocking frameworks.  It would be good to keep our Translator agnostic of our “actual” Translators, so let’s create a couple of Test Translators.

Pass Through Translator:

namespace MorseCoder.Windows.Test.TranslatorServiceTests.Translators
{
public class PassThroughTranslator : ITranslator
{
public TranslationDirection Direction
{
get
{
throw new NotImplementedException();
}
}

public string Translate(string input)
{
return input;
}
}
}

Dummy Response Translator:

namespace MorseCoder.Windows.Test.TranslatorServiceTests.Translators
{
public class DummyResponseTranslator : ITranslator
{
private const string DummyResponse = "DummyResponse";

public TranslationDirection Direction
{
get
{
throw new NotImplementedException();
}
}

public string Translate(string input)
{
return DummyResponse;
}
}
}

But what about those TranslationDirections.  This leaves us closed to adding in new Translators.  Let’s leave them stubbed for now, but we’ll need to refactor that out shortly.

Because we now support any number of translator’s we need a way of deciding which is the correct Translator to run our input through.  We can use a Dictionary<string, ITranslator> to do our lookups.

With our Dictionary in mind, write a few unit test scenarios as a starter for ten :

  • Empty Dictionary;
  • Invalid Key;
  • Pass Through Lookup;
  • Dummy Response Lookup;
  • Add Translator;
  • Add Duplicate Translator.

You can check these on GitHub.

Let’s start fleshing out our Translator Service:

public class TranslatorService : ITranslatorService
{
private IDictionary&lt;string, ITranslator&gt; translators = new Dictionary&lt;string, ITranslator&gt;();

public ICollection&lt;string&gt; TranslatorKeys
{
get
{
return translators.Keys;
}
}

public void AddTranslator(string translatorKey, ITranslator translator)
{
translators.Add(translatorKey, translator);
}

public string Translate(string translatorKey, string input)
{
return translators[translatorKey].Translate(input);
}
}

Breaking that down there’s:

  • Our Dictionary to store instances of our Translators;
  • A property to return our Translator Keys (this could be extended to return a TranslatorDescriptor class in future, if we decided to make our API more discoverable);
  • A method to add a Translator to the Dictionary;
  • A Translate Method that takes our Key, looks up the Translator in the Dictionary, Translates and returns the response.

Summary

Where are we?

  • We added an additional layer of Abstraction to manage multiple Translators.

Where are we heading?

  • Implementing MorseToAlphabetController using our new TranslatorService;
  • Deploy to Azure;
  • Consuming our new Endpoint from our UWP app;
  • Implementing a LiveTileUpdate;
  • Making the app User Experience (UX) more friendly.

1 thought on “Web API Tutorials Part 3 : Translation Abstraction”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s