A common practice observed during creating a service is heavy usage of ServiceFacade. By 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 simple example, creating a service that manages products of an eCommerce site. Suppose the product service provides the 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 IProductService
- {
- [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);
- }
Let’s take a look at the usually seen implementation of above contract:
- public class ProductService: IProductService
- {
- IRepository < Product > product;
- ILogger logger;
- InventoryService service;
-
-
-
-
- public IEnumerable < Product > GetProductsList(Guid categoryId, int pageIndex, int pageSize)
- {
-
-
-
-
-
-
-
- }
- public Product Edit(Product product)
- {
-
- }
- public Product Get(Guid productId)
- {
-
- }
- public Product Create(Product product)
- {
-
- }
- public IEnumerable < Product > SearchProduct(SearchCriteria criteria)
- {
-
- }
- public void Delete(Guid productId)
- {
-
- }
- }
This 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.
The following figure 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
- A huge bodied class carrying out all business logics (or core service logic).
- Class became larger and larger as more methods will get added.
- Hard to Unit test due to lengthy methods.
- 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.
- 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. The following figure illustrates the idea of separating the Contracts from CoreLogic:
From implementation point of view let’s try to solve this problem using Command Pattern.
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
The following figure 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”.
In this project we have 3 project folders which I have created for separating the classes by their respective responsibilities.
- 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
-
-
-
- public abstract class BaseCommand
- {
-
-
-
-
- public string Name { get; protected set; }
- }
BaseCommandResult -
-
-
-
- public abstract class BaseCommandResult
- {
-
-
-
- public ErrorDetails Error { get; set; }
- }
-
-
-
-
- public class ErrorDetails
- {
-
-
-
- public int Code { get; set; }
-
-
-
-
- public string Message { get; set; }
- }
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.
-
-
-
- public interface ICommandHandler<TCommand, TResult>
- {
- TResult Execute(TCommand command);
- }
-
-
-
-
- public abstract class BaseCommandHandler<TCommand, TResult> : ICommandHandler<TCommand, TResult>
- {
-
-
-
- public TResult Execute(TCommand command)
- {
- try
- {
- return this.ExecuteCore(command);
- }
- catch(Exception exception)
- {
- this.HandleException(exception);
-
- return this.GenerateFailureResponse();
- }
- }
-
-
-
-
- protected abstract TResult ExecuteCore(TCommand command);
-
-
-
-
-
- protected abstract TResult GenerateFailureResponse();
-
-
-
-
-
- protected virtual void HandleException(Exception exception)
- {
-
- }
- }
Add a new class under the folder commands and name it
GetProductCommand and
GetProductCommandResult. Design the classes like the following:
-
-
-
- public class GetProductCommand : BaseCommand
- {
-
-
-
- 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.");
- }
- }
- }
-
-
-
-
- public class GetProductCommandResult : BaseCommandResult
- {
- public Product ProductDetails { get; set; }
- }
Now let’s add the
GetProductCommandHandler. The
GetProductCommandHandler will contain the execution logic, which will be executed in a really controlled environment. Inherit the class from
BaseCommandHandler with generic argument of type
GetProductCommand and
GetProductCommandResult. Once you finish writing the following syntax, press ctrl + . in visual studio and you’ll be prompted to implement the abstract class.
- public class GetProductCommandHandler: BaseCommandHandler < GetProductCommand, GetProductCommandResult >
- {
- protected override GetProductCommandResult ExecuteCore(GetProductCommand command)
- {
- throw new NotImplementedException();
- }
- protected override GetProductCommandResult GenerateFailureResponse()
- {
- throw new NotImplementedException();
- }
- }
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.
- 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
- {
-
- Code = 200001,
-
- 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 CommandDispatcher
- {
-
-
-
- internal static Dictionary < Type, Object > localCache = new Dictionary < Type, object > ();
-
-
-
- static CommandDispatcher()
- {
-
-
- var coreAssembly = typeof (ICommandHandler < , > )
- .Assembly;
- var commandTypes = from type in coreAssembly.GetExportedTypes()
- where type.Name.EndsWith("CommandHandler")
- select type;
-
- commandTypes.ToList()
- .ForEach(type => localCache[type] = GetInstance(type));
- }
-
-
-
- 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
- });
- }
-
-
-
- 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;
- }
-
-
-
- internal static void ResetCache()
- {
- localCache.Clear();
- }
- private static object GetInstance(Type type)
- {
- return Activator.CreateInstance(type);
- }
- }
This CommandDispatcher is doing the following work:
- Register instances of all the command handlers (this work can be replaced by using DI container).
- 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: IProductService
- {
- public Product Get(Guid productId)
- {
- var commandArgs = new GetProductCommand(productId);
- GetProductCommandResult result = CommandDispatcher.Dispatch < GetProductCommandHandler, GetProductCommandResult > (commandArgs);
-
- if(result.Error != null)
- {
- throw new System.ServiceModel.FaultException < Exception > (new Exception(result.Error.Message));
- }
- return new Product
- {
-
- };
- }
- }
That’s it. Pretty clean huh! Question yourself what impact would 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.
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: - Separated business unit from contracts.
- Minimized the contract changes impact on core service logic.
- More controlled execution of business logic via commands.
- Each command is representing a service operation which is placed in a dedicated class means more scope to do with operations.
- More opportunities to add unit tests at its core logic unit i.e. Commands.
- Old service façade are now Adapters.
Cons:
- Bolerplate 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).
- 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.