A common practice observed during design or development of a service component; is heavy usage of ServiceFacade. According to Façade definition, A facade is an object that provides a simplified interface to a larger body of code, such as a class library. In this post I’ll be discussing about the challenge that are faced with ServiceFacade classes while working on SOA (Service Oriented Architecture).
Note: In this article we’ll be using WCF service contracts for sampling. The language is C# and code editing tool used is Visual studio 2013.
Let’s take a look at the high level design of Façade pattern.
Usually when the services are created we only concentrate on developing the server side functionality without thinking of fact that how service could grow in future because of the business. A simplest example, creating a service that manages products of an eCommerce site. Suppose the product service provides following operations:
- Create a product
- Delete a product
- Edit product
- GetProduct
- GetProductsList
- Search product
- Miscellaneous other operation
Now, Let’s take a look at the service contract. I’ll be taking the sample of WCF service contracts for demonstration:
public interface IProductServiceLet’s take a look at the usually seen implementation of above contract:
{
[OperationContract]
IEnumerable<Product> GetProductsList(Guid categoryId, int pageIndex, int pageSize);
[OperationContract]
Product Edit(Model.Product product);
[OperationContract]
Product Get(Guid productId);
[OperationContract]
Product Create(Model.Product product);
[OperationContract]
IEnumerable<Product> SearchProduct(SearchCriteria criteria);
[OperationContract]
void Delete(Guid productId);
}
public class ProductService : IProductServiceThis is Façade pattern in real life scenario. I would call it service façade since we are talking in context of SOA. When we look the above service façade sample, it seems fine, right? Unless the business decided to add/replace/remove/re-locate an operation to another service. Now think about removing the Get() method from Product contract to some other service contract. The whole logic written under Get() will be demolished or might not work when moved to another service contract. Why? Because it’s tightly coupled with Façade here.
{
IRepository<Product> product;
ILogger logger;
InventoryService service;
//...
//...
// And any other dependencies required to fulfill
// operations requirement here.
public IEnumerable<Product> GetProductsList(Guid categoryId, int pageIndex, int pageSize)
{
// A try..catch{} for error/exception handling
// Check inventory step
// Get inventory availabilities step
// Prepare products lists step
// ... bunch of other stuff.
// Log, if required etc..
// return the response.
}
public Product Edit(Product product)
{
// Actual core logic of Editing a product.
}
public Product Get(Guid productId)
{
// Actual core logic of Fetching a product.
}
public Product Create(Product product)
{
// Actual core logic of Adding a product.
}
public IEnumerable<Product> SearchProduct(SearchCriteria criteria)
{
// Actual core logic of Seraching products.
}
public void Delete(Guid productId)
{
// Actual core logic of Deleting a product.
}
}
Figure below illustrating the coupling of CoreLogic and ServiceContracts:
Let’s take a look at the downside of such Facades in SOA especially on services side:
Architect’s point of view:
The coupling of the core service logic to contracts and implementation resources can inhibit its evolution and negatively impact service consumers.
“When a service is subject to change either due to changes in the contract or in its underlying implementation, this core service logic can find itself extended and augmented to accommodate that change. As a result, the initial bundling of core service logic with contract-specific or implementation-specific processing logic can eventually result in design-time and runtime challenges.”
[Ref. SOA Design Patterns by Thomas Erl (Chapter 12)]
Developer’s point of view:
1. A huge bodied class carrying out all business logics (or core service logic).
2. Class became larger and larger as more methods will get added.
3. Hard to Unit test due to lengthy methods.
4. A centralize place where multiple developers will be working on it fix bugs/adding new operations. Now you can imagine how this central place can easily be polluted with stuff.
5. Bug prone!!! Fixing a bug could end up introducing multiple bugs also known as “Rebugging code”. See Fallacy of resue.
Considering both scenarios; ServiceFacades are problems and may become problem in future for maintenance so I decided to write this post as reference to developer seeking solution to this problem.
Solution approach –
The problem can be solved by separating core logic from service contracts(façade) to separate self-operating entities. Figure below illustrates the idea of separating the Contracts from CoreLogic:
From implementation point of view let’s try to solve this problem using CommandPattern.
Why command pattern?
A command can represent individual operation of service contract. Then we can use a dispatcher to invoke a particular command. Also the Core logic of individual operation can reside in commands. This is “An approach” to solve above problem.
Note: The implementation of CommandPattern that I’ll use in this post might differ from the samples given on various sources. Design patterns are Notion to use the power of Object Oriented world. Implementation can vary but it shouldn’t violate principles.
Simplifying ServiceFacade
Figure below shows the Idea of using commands and redirecting each operation request to dedicated command via command dispatcher.Now let’s go back to the code and create a new project which will consists of Commands representing each operation from Service Contract. So let’s create a class library project and name the project “ServiceOperations”. Well I just named it because “Naming is one of the hardest thing in computer programming world”. :)
Base – Consists of Abstract classes and interfaces.
Commands – Consists of all commands and command result(we’ll be discussing these two).
Handlers – Consists of Handlers which will execute the commands.
Now we’ll start adding commands with respect to operations from service contract. For sampling we’ll create a command for Get(Guid ProductId) operation from service contract. To start with we need some foundation classes to implement command pattern under Base folder.
BaseCommand
/// <summary>BaseCommandResult
/// Each command would be dervied from Base command
/// </summary>
public abstract class BaseCommand
{
/// <summary>
/// Logical name to represent the command.
/// [optional] and can be used for other pusposes like logging/error reporting etc.
/// </summary>
public string Name { get; protected set; }
}
/// <summary>BaseCommandHandler – Design of this class is really important as each command handler should know the command and its return type. Also common error handling etc. will be done in base class only. As I mentioned above the implementation of command pattern might differ. But first it should fulfill the purpose of business while following SOLID principles.
/// Each command must have a result to send back.
/// Any command restul must inherit from this class.
/// </summary>
public abstract class BaseCommandResult
{
/// <summary>
/// Contains error details, if occurred during execution.
/// </summary>
public ErrorDetails Error { get; set; }
}
/// <summary>
/// Represent error details happened during command execution.
/// </summary>
public class ErrorDetails
{
/// <summary>
/// Error code, For production level debugging purpose(representing technical issue type).
/// </summary>
public int Code { get; set; }
/// <summary>
/// Application friendly error message.
/// </summary>
public string Message { get; set; }
}
/// <summary>Add a new class under the folder Commands and name it GetProductCommand and GetProductCommandResult. Design the classes like below:
/// A marker interface for CommandHandlers.
/// </summary>
public interface ICommandHandler<TCommand, TResult>
{
TResult Execute(TCommand command);
}
/// <summary>
/// Each command handler must be dervied from this class.
/// </summary>
public abstract class BaseCommandHandler<TCommand, TResult> : ICommandHandler<TCommand, TResult>
{
/// <summary>
/// Executes the command logic in safe execution context.
/// </summary>
public TResult Execute(TCommand command)
{
try
{
return this.ExecuteCore(command);
}
catch(Exception exception)
{
this.HandleException(exception);
return this.GenerateFailureResponse();
}
}
/// <summary>
/// Consists of actual logic to process any command.
/// </summary>
protected abstract TResult ExecuteCore(TCommand command);
/// <summary>
/// Consists of dervied handler specific strategy to respond to
/// any error occurred during execution.
/// </summary>
protected abstract TResult GenerateFailureResponse();
/// <summary>
/// Method detailing the handling of exception.
/// Override this method to have CommandHandler specific error handling.
/// </summary>
protected virtual void HandleException(Exception exception)
{
// do logging
}
}
/// <summary>Now let’s add the GetProductCommandHandler. The GetProductCommandHandler will contains the execution logic, which will be executing in a really controlled environment. Inherit the class from BaseCommandHandler with generic argument of type GetProductCommand and GetProductCommandResult. Once you finish writing below syntax, press ctrl + . in visual studio and you’ll be prompted to implement the abstract class.
/// Contains arguments and information required to process Get product request.
/// </summary>
public class GetProductCommand : BaseCommand
{
/// <summary>
/// Product Id
/// </summary>
public Guid ProductId { get; set; }
public GetProductCommand(Guid productId)
{
this.ProductId = productId;
this.DoSanityCheckOnArguments();
}
private void DoSanityCheckOnArguments()
{
if(this.ProductId == Guid.Empty)
{
throw new ArgumentException("productId", "Failed to initialize GetProductCommand. Invalid product Id received.");
}
}
}
/// <summary>
/// Contains results of GetProductCommand execution.
/// </summary>
public class GetProductCommandResult : BaseCommandResult
{
public Product ProductDetails { get; set; }
}
public class GetProductCommandHandler : BaseCommandHandler<GetProductCommand, GetProductCommandResult>Add the Core Logic to fetch the product here. Build an error response if anything goes wrong. This is how the final class would look like after doing the patching work.
{
protected override GetProductCommandResult ExecuteCore(GetProductCommand command)
{
throw new NotImplementedException();
}
protected override GetProductCommandResult GenerateFailureResponse()
{
throw new NotImplementedException();
}
}
public class GetProductCommandHandler : BaseCommandHandler<GetProductCommand, GetProductCommandResult>
{
private IRepository repository;
public GetProductCommandHandler()
{
repository = new ProductRepository();
}
protected override GetProductCommandResult ExecuteCore(GetProductCommand command)
{
if (command == null)
{
throw new ArgumentNullException("command", "GetProductCommand object was received null.");
}
var product = repository.Fetch(command.ProductId);
var productDetails = new GetProductCommandResult
{
ProductDetails = product
};
return productDetails;
}
protected override GetProductCommandResult GenerateFailureResponse()
{
return new GetProductCommandResult
{
Error = new ErrorDetails
{
// Move it to shared constant file
Code = 200001,
// Load it from string resource file
Message = "There was an error while retreiving product details."
}
};
}
}
Now if you want you can also write some unit tests against the Command testing the individual logic of each operation. Instead of testing the whole big old mud ball service façade.
Core logic is now moved from Service contracts to a dedicated command. Now we need find a way to send those operation requests to respective commands. Let’s create a class CommandDispatcher. This class will have only Dispatch method which will actually take the command dispatch it to their respective command handler.
public static class CommandDispatcherThis CommandDispatcher is doing following work:
{
/// <summary>
/// Keep the cached instance of command handlers.
/// </summary>
internal static Dictionary<Type, Object> localCache = new Dictionary<Type, object>();
/// <summary>
/// Register all the command handler found
/// </summary>
static CommandDispatcher()
{
// A DI container can be used here.
// This is a composite root for registering all command handlers.
var coreAssembly = typeof(ICommandHandler<,>).Assembly;
var commandTypes =
from type in coreAssembly.GetExportedTypes()
where type.Name.EndsWith("CommandHandler")
select type;
// Register the handlers’ instances to local cache
commandTypes.ToList().ForEach(type => localCache[type] = GetInstance(type));
}
/// <summary>
/// Method to locate and execute the command on their respective command handler.
/// </summary>
public static TResult Dispatch<THandler, TResult>(BaseCommand command)
{
var handlerType = typeof(THandler);
var handlerInstance = Get<THandler>();
var methodInfo = handlerType.GetMethod("Execute");
return (TResult)methodInfo.Invoke(handlerInstance, new[] { command });
}
/// <summary>
/// Get the registered command handlers.
/// </summary>
internal static THandler Get<THandler>()
{
object cachedInstance = null;
if(!localCache.TryGetValue(typeof(THandler), out cachedInstance))
{
throw new InvalidOperationException("Command Handler for the respective command is not registered.");
}
return (THandler)cachedInstance;
}
/// <summary>
/// For testing purpose only.
/// </summary>
internal static void ResetCache()
{
localCache.Clear();
}
private static object GetInstance(Type type)
{
return Activator.CreateInstance(type);
}
}
1. Register instances of all the command handlers (this work can be replaced by using DI container).
2. Locate and execute the command on its handler via Dispatch method.
To test the Dispatcher I’ve created a few tests around ( ..and actually found couple of bugs to fix before using the code in this article). Refer to the sample solution here on github.
We have our Dispatcher in hand. Let’s patch it to the Service contract operations and finish the bonding of Dispatcher/New façade to Service contracts.
public class ProductService : IProductServiceThat’s it. Pretty clean huh! Question yourself what impact would be move Get() method from this contract to another contract or completely removing the method from service contract. Yes, Remove it right away the Core Logic is safe and sound and can easily be used in another service. Also we have no dependencies of the system on contracts anymore. Core service logic unit is abstracted via CommandDispatcher and Commands. Such implementation promotes more cohesiveness and less coupling in the system.
{
public Product Get(Guid productId)
{
var commandArgs = new GetProductCommand(productId);
GetProductCommandResult result =
CommandDispatcher.Dispatch<GetProductCommandHandler, GetProductCommandResult>(commandArgs);
// Raise the fault exception
if (result.Error != null)
{
throw new System.ServiceModel.FaultException<Exception>(new Exception(result.Error.Message));
}
return new Product
{
// map the GetProductCommandResult.Product properties to proerties of contracts.
};
}
}
I’m sure some readers might have observed that we have introduced a new design patterns as well while refactoring. Now Service contract is actually behaving as Adapter class for its consumer and the core service logic unit i.e. BusinessLogic. That’s how, IMO, the service contracts should behave in the system.
There are Pros and Cons (not much) of using this separation so before we wrap up let’s take a look at them.
Pros
1. Separated business unit from contracts.
2. Minimized the contract changes impact on core service logic.
3. More controlled execution of business logic via commands.
4. Each command is representing a service operation which is placed in a dedicated class means more scope to do with operations.
5. More opportunities to add unit tests at its core logic unit i.e. Commands.
6. Old service façade are now Adapters.
Cons
1. Boilerplate code. (This complain usually heard from developers. But this boiler plating is worth for long run, and of course it can also be optimized by techniques like Aspects Oriented Programming)
2. Additional mapping of Contacts and Business Entities. (This can be handled by using an awesome utility Automapper). Thanks to Jimi and community developers doing this great piece of work.
For further reading on best SOA practices and patterns I would suggest to read “SOA Design Patterns” by Thomas Erl.
Solution used in the blog post is hosted on Github here.
No comments:
Post a Comment