Sunday, March 27, 2016

Exploring Facade

Recently I have been working on surface on Amazon MWS API. So basically Amazon MWS API is for interacting with Amazon seller account. If we need to update products directly from your local system or database directly to Amazon that involves different operation on products, creation of reports and stuffs we need this API.

Amazon MWS API uses different types of separate feeds to update different sections of a products such as Product basic info on ProductFeed, its pricing on PricingFeed, Quantity on QuantityFeed and so on. As I was working on feeds, I felt there is some subsystem within and if Facade would match the things I was about to do, but wasn't sure if it was really needed there and might be too much for it, but then I also thought that the class would expand, might be hard later for modification while mixing everything on single class. So it went for Facade and felt later that it was a wiser choice. Here is some ripped of samples


public static class AmazonMwsFacade
{
    private static readonly PricingFeed PricingFeed = new PricingFeed();
    private static readonly ProductFeed ProductFeed = new ProductFeed();
    private static readonly ImageFeed ImageFeed = new ImageFeed();
    private static readonly InventoryFeed InventoryFeed = new InventoryFeed();
    private static readonly RelationshipFeed RelationshipFeed = new RelationshipFeed();

    public static IDictionary<string, string> CreateXml(string filterFeedType, string csvId)
    {
        #region Headers

        #endregion

        var count = 1;
        if (reader.HasRows)
        {
            while (reader.Read())
            {
                if (reader["ProductBarCode"].ToString() != "0")
                {
                    if (filterFeedType.Contains("1"))
                        ProductFeed.CreateProductFeedXml(amazonProductXml, reader, ref count);
                    if (filterFeedType.Contains("2"))
                        PricingFeed.CreatePricingFeedXml(amazonPricingXml, reader, count);
                    if (filterFeedType.Contains("3"))
                        InventoryFeed.CreateInventoryFeedXml(amazonInventoryXml, reader, count);
                    if (filterFeedType.Contains("4"))
                        ImageFeed.CreateImageFeedXml(amazonImageXml, reader, count);
                    if (filterFeedType.Contains("5"))
                        RelationshipFeed.CreateRelationshipFeedXml(amazonRelationshipXml, reader, count);
                    ++count;
                }
            }
            if (filterFeedType.Contains("5"))
                RelationshipFeed.PostRelationshipFeedXml(amazonRelationshipXml);
        }

        IDictionary<string, string> dictXml = new Dictionary<string, string>();

        if (filterFeedType.Contains("1"))
            dictXml.Add("_POST_PRODUCT_DATA_", ProductFeed.SaveProductXml(amazonProductXml));
        if (filterFeedType.Contains("2"))
            dictXml.Add("_POST_PRODUCT_PRICING_DATA_", PricingFeed.SavePricingXml(amazonPricingXml));
        if (filterFeedType.Contains("3"))
            dictXml.Add("_POST_INVENTORY_AVAILABILITY_DATA_", InventoryFeed.SaveInventoryXml(amazonInventoryXml));
        if (filterFeedType.Contains("4"))
            dictXml.Add("_POST_PRODUCT_IMAGE_DATA_", ImageFeed.SaveImageXml(amazonImageXml));
        if (filterFeedType.Contains("5"))
            dictXml.Add("_POST_PRODUCT_RELATIONSHIP_DATA_", RelationshipFeed.SaveRelationshipXml(amazonRelationshipXml));
        return dictXml;
    }
}

Now for every feed type, I created a class, on Facade terms kind of subsystem.

internal class ProductFeed
{
    private readonly bool _hasRelation;
    public ProductFeed()
    {
                // Logic
    }

    public static XElement CreateSearchString(string searchString)
    {
                // Logic
    }

    public static string RemoveTroublesomeCharacters(string inString)
    {
                // Logic
    }

    public XElement CreateProductFeedXml(XElement amazonProductXml, SqlDataReader reader, ref int count)
    {
                // Logic
    }

    public string SaveProductXml(XElement amazonXml)
    {
                // Logic
    }

    private XElement RemoveDummyProductElement(XElement tempElement)
    {
                // Logic
    }

    private XElement RemoveDummyElement(XElement tempElement)
    {
                // Logic
    }

    private XElement RemoveDummySearchElement(XElement tempElement)
    {
                // Logic
    }
}

internal class PricingFeed
{
    public XElement CreatePricingFeedXml(XElement amazonPricingXml, SqlDataReader reader, int count)
    {
                // Logic
    }

    public string SavePricingXml(XElement amazonXml)
    {
                // Logic
    }
}


internal class ImageFeed
{
    public XElement CreateImageFeedXml(XElement amazonImageXml, SqlDataReader reader, int count)
    {
                // Logic
    }

    public string SaveImageXml(XElement amazonXml)
    {
                // Logic
    }
}

internal class RelationshipFeed
{
    private string _parentSku = String.Empty;
    private int _count;
    private XElement _listElement;
    private bool _hasFooter;
    private string _groupId;

    public RelationshipFeed()
    {
        _listElement = new XElement("DummyElement");
    }

    public XElement CreateRelationshipFeedXml(XElement amazonRelationshipXml, SqlDataReader reader,
        int count)
    {
                // Logic
    }

    public XElement PostRelationshipFeedXml(XElement amazonRelationshipXml)
    {
                // Logic
    }

    private XElement RemoveDummyElement(XElement tempElement)
    {
                // Logic
    }

    public string SaveRelationshipXml(XElement amazonXml)
    {
                // Logic
    }
}

internal class InventoryFeed
{
    public XElement CreateInventoryFeedXml(XElement amazonInventoryXml, SqlDataReader reader, int count)
    {
                // Logic
    }

    public string SaveInventoryXml(XElement amazonXml)
    {
        // Logic
    }
}


Didn't think those subsystem class would expand and get dirty but if I now imagine myself without subsytem approach I am sure it will get dirtier than its now. Further common operations or methods are inside AmazonMWSFacade class and only distinct operation are on respective subsystem regardless of similar signature.