Monday, September 27, 2010

Test Driven Approach - Positive Impact for Developers - Conclusion

Going thru this lengthy of workshop series on TDD, I hoped I have covered enough here on positives impact from TDD approach. It takes a developer to practice it to see its worth.

Often in software development, we fall into traps like: -
Lengthy requirement gathering period.
Lengthy conceptualizing and creating over detail blueprint (architecture).
Over design/engineering a software component at early stages.
Lost focus on interactivity between requirement/conceptual model/design phases due to lengthy period.
Less integrability due to disconnected phases.

All these can be nicefully addressed with Agile and TDD.
Agile and TDD are just complementing each other and bringing developers closer to users and hence business.

Final question, why would one insert a break point at several area to debug when a defect was raised? Write a unit test to automate that checks please. Thank you.

Test Driven Approach - Positive Impact for Developers - Workshop IV

Now we need to implement the Calculate method within Core.Calculator.

So, there are many ways this can be done and whether this method is developed to its best code is not the interest of the workshop. Here is my sample: -
using System;
using System.Collections.Generic;
using System.Linq;

namespace Calculator.Core
{
    public class Calculator
    {
        private const string Add = "+";
        private const string Sub = "-";
        private const string Div = "/";
        private const string Mul = "*";
        private const string Sqrt = "sqrt";
        private const string Percent = "%";
        private const string Reciproc = "reciproc";
        private const string Pow = "pow";

        private readonly string[] _keywords = new []{ Add, Sub, Div, Mul, Sqrt, Percent, Reciproc, Pow, "(", ")", ","};

        private readonly string[] _operatorKeywords = new[] { Add, Sub, Div, Mul, Sqrt, Percent, Reciproc, Pow };

        private static readonly Dictionary<string, Math.MathOperatorHandler> Operators;

        static Calculator()
        {
            Operators = new Dictionary<string, Math.MathOperatorHandler>
                             {
                                 {Add, Math.Add},
                                 {Reciproc, Math.Reciproc},
                                 {Pow, Math.Pow},
                                 {Sub, Math.Subtract},
                                 {Div, Math.Divide},
                                 {Mul, Math.Multiply},
                                 {Sqrt, Math.SquareRoot},
                                 {Percent, Math.Percent}
                             };
        }

        public string Calculate(string formula)
        {
            double temp;
            if (double.TryParse(formula, out temp))
            {
                return formula;
            }
            var values = formula.Split(_keywords, StringSplitOptions.RemoveEmptyEntries);
            if (values.Length == 0)
            {
                var msg = string.Format("No values to be calculated. Values length is zero for formula {0}.", formula);
                throw new UnexpectedCalculationException(msg);
            }

            var subPart = formula.TrimStart(values[0].ToCharArray());
            var opCode = _operatorKeywords.FirstOrDefault(subPart.StartsWith);

            if (string.IsNullOrEmpty(opCode))
            {
                var msg = string.Format("No calculation operator found in formula {0}.", formula);
                throw new UnexpectedCalculationException(msg);
            }

            Math.MathOperatorHandler mo;

            // this is only possible when there is a %.
            if (subPart.EndsWith(Percent))
            {
                if (!Operators.TryGetValue(Percent, out mo))
                {
                    var msg = string.Format("Cannot resolve calculation operator of {0}.", Percent);
                    throw new UnexpectedCalculationException(msg);
                }
                values[values.Length - 1] = mo(values.Select(item => double.Parse(item))).ToString();
            }

            if (!Operators.TryGetValue(opCode, out mo))
            {
                var msg = string.Format("Cannot resolve calculation operator of {0}.", opCode);
                throw new UnexpectedCalculationException(msg);
            }
            var valueArray = values.Select(item => double.Parse(item));
            var result = mo(valueArray);
            return result.ToString();
        }
    }
}

But what is more interesting is at the supporting class below: -
    internal static class Math
    {
        private delegate T TryExecuteHandler<out T>();

        internal delegate double MathOperatorHandler(IEnumerable<double> values);

        private static double Handle(TryExecuteHandler<double> handler)
        {
            try
            {
                return handler();
            }
            catch(FormatException e)
            {
                throw new IncompatibleDataTypeFormulaException("Unexpected data format.", e);
            }
        }

        internal static double Add(IEnumerable<double> values)
        {
            return Handle(() => values.Sum());
        }

        internal static double Subtract(IEnumerable<double> values)
        {
            return Handle(() =>
                              {
                                  var valueArray = values.ToArray();
                                  var result = valueArray[0];
                                  for (var i = 1; i < valueArray.Length; i++)
                                  {
                                      result -= valueArray[i];
                                  }
                                  return result;
                              });
        }

        internal static double Multiply(IEnumerable<double> values)
        {
            return Handle(() =>
                              {
                                  var valueArray = values.ToArray();
                                  var result = valueArray[0];
                                  for (var i = 1; i < valueArray.Length; i++)
                                  {
                                      result *= valueArray[i];
                                  }
                                  return result;
                              });
        }

        internal static double Divide(IEnumerable<double> values)
        {
            return Handle(() =>
                              {
                                  var valueArray = values.ToArray();
                                  var result = valueArray[0];
                                  for (var i = 1; i < valueArray.Length; i++)
                                  {
                                      result /= valueArray[i];
                                  }
                                  return result;
                              });
        }

        internal static double SquareRoot(IEnumerable<double> values)
        {
            return Handle(() =>
                              {

                                  var valueArray = values.ToArray();
                                  if (valueArray.Length > 1)
                                  {
                                      var msg = string.Format("Expect valueArray of length 1 but was {0}.", valueArray.Length);
                                      throw new UnexpectedCalculationException(msg);
                                  }

                                  return System.Math.Sqrt(valueArray[0]);
                              });
        }

        internal static double Pow(IEnumerable<double> values)
        {
            return Handle(() =>
                              {
                                  var valueArray = values.ToArray();
                                  var result = valueArray[0];
                                  for (var i = 1; i < valueArray.Length; i++)
                                  {
                                      result = System.Math.Pow(result, valueArray[i]);
                                  }
                                  return result;
                              });
        }

        internal static double Reciproc(IEnumerable<double> values)
        {
            return Handle(() =>
                              {
                                  var valueArray = values.ToArray();
                                  if (valueArray.Length > 1)
                                  {
                                      var msg = string.Format("Expect valueArray of length 1 but was {0}.", valueArray.Length);
                                      throw new UnexpectedCalculationException(msg);
                                  }

                                  return 1/valueArray[0];
                              });
        }

        internal static double Percent(IEnumerable<double> values)
        {
            return Handle(() =>
                              {
                                  var valueArray = values.ToArray();
                                  if (valueArray.Length != 2)
                                  {
                                      var msg = string.Format("Expect valueArray of length 2 but was {0}.", valueArray.Length);
                                      throw new UnexpectedCalculationException(msg);
                                  }
                                  return valueArray[0]*valueArray[1]/100;
                              });
        }
    }

In the unit tests, we expected two different kinds of exceptions as such: -
    [Serializable]
    public class IncompatibleDataTypeFormulaException : Exception
    {
        public IncompatibleDataTypeFormulaException(string message, Exception innerException)
            :base(message, innerException)
        {
        }
    }

    /// <summary>
    /// <see cref="UnexpectedCalculationException"/> - Exception indicates that there were some unexpected internal calculation error.
    /// </summary>
    [Serializable]
    public class UnexpectedCalculationException:ApplicationException
    {
        public UnexpectedCalculationException(string message)
            :base(message)
        {
        }
    }

Now that I don't want to make the case complicated by implementing a FormulaParser and FormulaToken all that sorts just for a simple calculator, I opted for the static class implementation named Math. This supporting class is never in my mind that will be shared. It is my internal calculation logic that is for abstraction. It has very high chances that I want improve it in the future.

This class should never be unit tested.

If you do, you will quickly find you do owe yourself for a blame. Unit testing your abstraction logic will pressurize on your responsibility of maintaining highest potential to change API, process workflow, class design and etc. You ended do a lot of work and then undone many work that you were spending day and night maintaining it.

Best practice of TDD said, let those highly changeable code (abstraction logic) automatically covered by just unit testing your public API. If it was not covered automatically, you have written unplanned code and that is the risk for defects or bugs. You will be helped by the coverage to uncover the statistic for this area of risk to you.


Note: The only place that is not well-tested is at UI.

Next, look at the abstraction logic again, there is a pattern of repeatedly throwing exception is needed for most of the function like Add, Divide, Multiply etc, this just comes naturally that I will need some aspect oriented programming for exception handling in this function. Hey, now I need to use AOP design patterns with Code Injection facility.

This is awesomely beautiful isn't it, doing it TDD?

Test Driven Approach - Positive Impact for Developers - Workshop III (Part B)

Now, lets us try to compile and run the test again. As expected, it won't compile at all. We need refactoring to the unit tests at Calculator.Tests as such: -
using Calculator.Core;
using Calculator.Presenter;
using NUnit.Framework;

namespace Calculator.Tests
{
    public class CalculatorMockView : ICalculatorView
    {
        public string Result { get; set; }
        public string Formula { get; set; }
    }
    
    [TestFixture]
    public class CalculatorTester
    {
        private Presenter.Calculator _calculator;
        private ICalculatorView _view;

        [SetUp]
        public void SetUp()
        {
            _view = new CalculatorMockView();
            _calculator = new Presenter.Calculator(_view);
        }

        [TestCase("6", "6")]
        [TestCase("5 + 6", "11")]
        [TestCase("3 - 2", "1" )]
        [TestCase("5 * 6", "30")]
        [TestCase("12 / 6", "2")]
        [TestCase("5 + 6%", "5.3")]
        [TestCase("reciproc(2)", "0.5")]
        [TestCase("pow(2,3)", "8")]
        [TestCase("sqrt(4)", "2")]
        [TestCase("12 / 6 / 8", "0.25")]
        [TestCase("reciproc(2,3,2)", "", ExpectedException = typeof(UnexpectedCalculationException))]
        [TestCase("sqrt(4, 21)", "", ExpectedException = typeof(UnexpectedCalculationException))]
        [TestCase("A + B + C", "", ExpectedException = typeof(IncompatibleDataTypeFormulaException))]
        [TestCase("HelloWorld(2,3,2)", "", ExpectedException = typeof(UnexpectedCalculationException))]
        [TestCase("2 3 2", "", ExpectedException = typeof(UnexpectedCalculationException))]
        public void EvaluationTest(string formula, string expected)
        {
            _view.Formula = formula;
            _calculator.Evaluate();
            Assert.AreEqual(_view.Result, expected);
        }
    }
}

And Calculator.Core.Tests as such: -
using NUnit.Framework;

namespace Calculator.Core.Tests
{
    [TestFixture]
    public class CalculatorTests
    {
        readonly Calculator _calculator = new Calculator();

        [TestCase("6", "6")]
        [TestCase("5 + 6", "11")]
        [TestCase("3 - 2", "1")]
        [TestCase("5 * 6", "30")]
        [TestCase("12 / 6", "2")]
        [TestCase("5 + 6%", "5.3")]
        [TestCase("reciproc(2)", "0.5")]
        [TestCase("pow(2,3)", "8")]
        [TestCase("sqrt(4)", "2")]
        [TestCase("12 / 6 / 8", "0.25")]
        [TestCase("reciproc(2,3,2)", "", ExpectedException = typeof(UnexpectedCalculationException))]
        [TestCase("sqrt(4, 21)", "", ExpectedException = typeof(UnexpectedCalculationException))]
        [TestCase("A + B + C", "", ExpectedException = typeof(IncompatibleDataTypeFormulaException))]
        [TestCase("HelloWorld(2,3,2)", "", ExpectedException = typeof(UnexpectedCalculationException))]
        [TestCase("2 3 2", "", ExpectedException = typeof(UnexpectedCalculationException))]
        public void EvaluationTest(string formula, string expected)
        {
            Assert.AreEqual(expected, _calculator.Calculate(formula));
        }
    }
}

Above, I have also added a few additional test cases where necessary. Now lets us compile and test run them. As expected, they are still failed.


Before we proceed, to correct all these tests, let us revisit what have we done so far?
1. We created solution based on some (small) fundamental architecture design.
2. We created a wire frame demonstrated how this look like conceptually.
3. We then created some unit tests focuses on "how we think the public API would be useful and clean". (API Usability Concern from consumer perspective.)
4. We introduce new projects (core) to ensure we provide better separation of business core logic. (Separation of Concern and Single Responsibility)
5. We then decide again how is the public API of the new project just added would look like. (API Usability again)
6. We implemented the presenter logic, wire up the UI wire frame, and the Core logic classes. (some UI design patterns were introduced for unit tests and better code separation).
7. We refactor the some API within its implementation and its corresponding unit testings in Calculator.Tests and Calculator.Core.Tests. (Refactoring based on needs).

Now, all the above just came naturally as we do our development in TDD fashion.

So, the next workshop, we will be aiming to clear all these unit tests.

Test Driven Approach - Positive Impact for Developers - Workshop III (Part A)

Quickly, we are now at 3rd session. Before we start, I would like to cover a bit on the missing architecture detail. This small application will be (hopefully) tailored into 3 layers design. UI, Core Logic, Data Access (if any). It is not that the requirements asking for so, it is simply some thought to have clear separation such that each component can be more tidy up with better cut of responsibility. Also, I hope I will have an opportunity in the future to bring this example into some further discussion on Scaling Out and Services Oriented fashion.


We have not create any data access layer assembly, but because we created a new assembly, "Core", hence a new Unit Test project for Core project is needed.

Enough said, now lets focus on the assignment. In reality, the calculator will be very unlikely to perform the calculation of such formula at once, "5 + 5% * 50 / 2 + pow(2,3)". Soon as you type in "5 + 5%", the calculator has already responded with the result. (Please verify with Windows Calculator). So, we will probably not cover this within this series of workshop.

Question: Where do we start coding to pass the test?
Answer: Let's start with the UI.

Question: How do we test the code in the UI?
Answer: We need a presenter or controller logic.

Calculator Presenter class develop as such: -
using System;
using System.Text;

namespace Calculator.Presenter
{
    public class Calculator
    {
        private readonly ICalculatorView _view;
        private readonly Core.Calculator _calculatorCore;

        public Calculator(ICalculatorView view)
        {
            _view = view;
            _calculatorCore = new Core.Calculator();
        }

        public void Evaluate()
        {
            _view.Result = _calculatorCore.Calculate(_view.Formula);
        }
    }

    public interface ICalculatorView
    {
        string Result { get; set; }
        string Formula { get; set; }
    }
}

This will need an additional Calculator class within the Core assembly as such: -
    public class Calculator
    {
        public string Calculate(string formula)
        {
            throw new NotImplementedException();
        }
    }

Now we sort of have everything (API) within this application that needs public access modifier done. We need to ensure the new public API sits under the Core project is unit tested as well. In this case, it is very similar to the earlier unit test created in Workshop II.

Next, we focus on how to wire up the UI into the presenter logic. This is what generated by VS 2010.
namespace Calculator
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            Application.Run(new CalculatorForm());
        }
    }
}

And here, we improve the sample WinForm class created during prototyping to utilize the presenter coded, as such: -
using System.Windows.Forms;
using Calculator.Presenter;

namespace Calculator
{
    public partial class CalculatorForm : Form, ICalculatorView
    {
        private Presenter.Calculator _calculator;

        public CalculatorForm()
        {
            InitializeComponent();
            _calculator = new Presenter.Calculator(this);
        }

        public string Result
        {
            get { return textBoxDisplay.Text; }
            set { textBoxDisplay.Text = value; }
        }

        public string Formula
        {
            get { return textBoxDisplay.Text; }
            set
            {
                textBoxDisplay.Text = value;
                textBoxDisplay.Refresh();
            }
        }
    }
}

Till this stage, we already have wire up most of the API needed within this application.

Sunday, September 26, 2010

Test Driven Approach - Positive Impact for Developers - Workshop II

First of all, there were couple of useful tools for Test Driven within Visual Studio .NET 2008 or 2010.

These are the tools the I usually use: -
1. NUnit
2. TestDriven.NET
3. JetBrains ReSharper

Note: JetBrains resharper is not free though.

So, after all, how should we start the development based on the requirements?

I usually create a new Test Project first, named Calculator.Tests.

For any TDD development, we should always attempt to write the tests from highest level possible with the simplest code. To achieve this, we should always attempt with the simplest API that we are going to deal with.

So, I would imagine the calculator class to work like this: -
Calculator cal = new Calculator();
var result = cal.Evaluate(formula);
Hence, I created a class within the Calculator.Tests as such: -
using NUnit.Framework;

namespace Calculator.Tests
{
    [TestFixture]
    public class CalculatorTester
    {
        private Calculator _calculator;

        [SetUp]
        public void SetUp()
        {
            _calculator = new Calculator(); 
        }

        [TestCase("5 + 6", "11")]
        [TestCase("3 - 2", "1")]
        [TestCase("5 * 6", "30")]
        [TestCase("12 / 6", "2")]
        [TestCase("2 * 3 - 4 / 5 + 6", "11.2")]
        [TestCase("5 + 6%", "5.3")]
        [TestCase("reciproc(2)", "0.5")]
        [TestCase("pow(2,3)", "8")]
        [TestCase(new [] {"A + B + C", string.Empty},
                    "Incompatible data type evaluation test.",
                    typeof(IncompatibleDataTypeFormulaException))]
        public void EvaluationTest(string formula, string expected)
        {
            var result = _calculator.Evaluate(formula);
            Assert.AreEqual(result.ToString(), expected);
        }
    }
}
Now with have almost demonstrated most of the features needed using various test cases based on TestCaseAttribute of NUnit 2.5.

You may be asking, so, this is the business logic, where is the UI testing? Isn't it we must start from the UI?

Yes, you got it half spots on. We must start from the UI (highest level), however are you sure this calculator class is just a business logic class? We shall see then.

Now, lets try to fix all the compilation error by creating some fundamental skeleton for it to compile.
public class Calculator
{
    public double Evaluate(string formula)
    {
        throw new NotImplementedException();
    }
}

public class IncompatibleDataTypeFormulaException:Exception
{
}
Now that we have written the unit tests and the compilation is done. We should test run it and see all of them failed.



As expected, all test cases failed. I would be extremely surprised if any of this passed. :)

So, the next assignment is to get them green.

Friday, September 24, 2010

Test Driven Approach - Positive Impact for Developers - Workshop I

Start from this post and over the next few posts, I will be covering the Test Driven Approach - Positive Impacts for Developers.

Impacts: -
1. Think like a user
2. Clean APIs Design
3. Improves Abstractions
4. Better Used of Patterns
5. Improves Separation of Concerns.

Let starts with some fundamental user requirements on a calculator.

I can do fundamental calculation, +, -, *, /, sqrt, %, pow and 1/x.
I can use whole numbers or rational numbers as the input.
I can defined the result format within the format of whole number or rational number.
I can specify the number of decimal places for the results.
I can define a formula and save it.
I can load a formula and calculate using the loaded formula.
I can only specify the values for variables within the formula.

There is all we have for the requirements.

So, if we're to start right away, we should have start writing the unit tests first.

A quick glance into the requirements, it seems quite straight forward to accomplish.

Questions: -
1. How many of you already start thinking of classes for logic separation, like Adder, Subtractor, Divisor and Multiplicator etc.?

2. How many of you already start writing unit tests right away based on the requirement defined?

"If there is anyone falling into those traps, you're wrong!" The requirement wasn't quite defined into a stage where this can be started.

Based on the requirements given, we should have at least asking how would it be deployed? Web Services, Windows Services, Web Apps or Windows Forms Apps for instance.

So, to make it more simple, this is a Win Form application, just like the calculator in Windows.

New User Requirements: -
"I can use it like many windows desktop application."

So now, we are good to start, however, not unit testing yet. It is the UI wireframe (prototyping for GUI, i.e. Forms.) Here it is: -



Now, we can start writing some tests, that will be in workshop II.

Wednesday, September 8, 2010

ETL Sorting or SQL Sorting (ORDER BY)

ETL Magic



Often hear about ETL (Extract, Transform, Load) solution for better data integration between applications, systems or solution within an enterprise. What are the major consideration before choosing an appropriate ETL solution?

Sorting, Merging, Unification, Transformation and Loading are quite commonly happen within Data Integration stage. Often, we heard of NSort, CoSort (IRI), SyncSort and others famous 3rd party ETL solution and tools. Each of these offers some great performance if not exceptional in their respective technical strength with many data integration efficiency (Terabytes of data size) bar being set higher and higher.

EnTerprise solution missing Link?



Quite honestly, many solution architects would think these ready made ETL solution is best used to glue their data movement processes within the sub-solutions altogether to not just making data extraction, transformation and loading much faster (conceptually), but also act as a missing link to gel data from many independent components within the enterprise solution to ensure they get the right data in timely fashion before going live.

Question of the day



What would be the topic of discussion today is rather, will those 3rd parties solution offers best performance value to the enterprise solution and often considered as the missing link in the solutions integration?

ETL Rules of thumb: -



If data is already in the database and you would want to extract all these data into another database, consider doing the sorting and filtering related tasks within your database server itself. Ordering, filtering and unification tasks within the database server is always consider as "as good" when compared to the other ETL solution.

If the data has to be somewhat inserted into tables within database, consider doing sorting, unification, merging (joins), filtering, data enrichment (meta tagging) and etc. altogether within the database server. Again, the same principles applied here. Database server can handle all those as good as the third parties ETL.

If the batch data integration process can be avoided by putting it into an incremental data integration approach, by all means doing it in an incremental fashion with proper application/data partitioning.

If the data is migrating from one database platform into another, try to look for some out of the box integration solutions. For example, SSIS for Microsoft SQL Server. (SSIS is free and has also recently breaking some integration records.)

Never ever thinking of re-inventing your own ETL solution, from ground up, if you are not intending to step into the red ocean, ETL business.

Consider 3rd parties ETL solutions when the data source is originated from a non-database model and the data target is another non-database model.

Consider 3rd parties ETL solutions when majority of the data transformation, extraction, unification, merging, filtering and sorting involves many different types of data sources.

Consider 3rd parties ETL solutions when it has more than one intended data target that are of different platforms.

Take Away



SQL ordering, filtering, conditional relationship/merging (joins) are almost equally as fast as the 3rd parties ETL tools.

No real magics with ready made ETL solutions, it is the solution integration architecture that counts.

Fancy solutions will cost more in terms of investment capital, learning curve, maintenance efforts, business opportunity, end product selling prices (to your customers).