Noob to Pro Lets Breakup

In today’s post we will continue the Noob to Pro series. With the code in a much less complicated space, we will dig into how to start to breakup the code up in the Noob to Pro 4 function calculator.

We need to breakup

There is still a major problem with this code that will hold it back until we solve it. We cannot really test this code because it all smushed up with the GUI code. We want to break it down so we can apply unit testing to our functions. Under normal circumstances, you would want to do testing first and write your code in a Test Driven way. Because this is a Noob to Pro series, we got some Noob code to cleanup instead. We won’t.

First, we have to figure out how to break up this thing. We will address testing in the next post but this one we will start the process of breaking down this code so we will having something to test.

Lets dig into where we are now.

Noob to Pro Pre Breakup

using System;
using System.Windows.Forms;
 
namespace NoobToPro
{
    public partial class FormCalc : Form
    {
        string value1 = string.Empty;
        string value2 = string.Empty;
        string results = string.Empty;
        string sign = string.Empty;
        bool isValue2 = false;
        string temp = string.Empty;
 
        const string ONE = "1";
        const string TWO = "2";
        const string THREE = "3";
        const string FOUR = "4";
        const string FIVE = "5";
        const string SIX = "6";
        const string SEVEN = "7";
        const string EIGHT = "8";
        const string NINE = "9";
        const string ZERO = "0";
        const string PERIOD = ".";
 
        const string ADD = "+";
        const string SUBTRACT = "-";
        const string DIVIDE = "/";
        const string MULTIPLE = "*";
 
 
        public FormCalc()
        {
            InitializeComponent();
        }
 
        private string setTemp(string number)
        {
            temp += number;
            return temp;
        }
 
        private string setValue(string number)
        {    
            if (!isValue2)
            {
                value1 = number;
                isValue2 = true;
                return value1;
            }
            value2 = number;
            return value2;
        }
 
        private void btn7_Click(object sender, EventArgs e)
        {
            txtInput.Text = setTemp(SEVEN);
        }
 
        private void btn8_Click(object sender, EventArgs e)
        {
            txtInput.Text = setTemp(EIGHT);
        }
 
        private void btn9_Click(object sender, EventArgs e)
        {
            txtInput.Text = setTemp(NINE);
        }
 
        private void btn4_Click(object sender, EventArgs e)
        {
            txtInput.Text = setTemp(FOUR);
        }
 
        private void btn5_Click(object sender, EventArgs e)
        {
            txtInput.Text = setTemp(FIVE);
        }
 
        private void btn6_Click(object sender, EventArgs e)
        {
            txtInput.Text = setTemp(SIX);
        }
 
        private void btn1_Click(object sender, EventArgs e)
        {
            txtInput.Text = setTemp(ONE);
        }
 
        private void btn2_Click(object sender, EventArgs e)
        {
            txtInput.Text = setTemp(TWO);
        }
 
        private void btn3_Click(object sender, EventArgs e)
        {
            txtInput.Text = setTemp(THREE);
        }
 
        private void btn0_Click(object sender, EventArgs e)
        {
            txtInput.Text = setTemp(ZERO);
        }
 
        private void btnPeriod_Click(object sender, EventArgs e)
        {
            txtInput.Text = setTemp(PERIOD);
        }
 
        private void btnDivide_Click(object sender, EventArgs e)
        {
            setValue(temp);
            temp = string.Empty;
            sign = DIVIDE;
            txtInput.Text = string.Empty;
        }
 
        private void btnMultiply_Click(object sender, EventArgs e)
        {
            setValue(temp);
            temp = string.Empty;
            sign = MULTIPLE;
            txtInput.Text = string.Empty;
        }
 
        private void btnSubtract_Click(object sender, EventArgs e)
        {
            setValue(temp);
            temp = string.Empty;
            sign = SUBTRACT;
            txtInput.Text = string.Empty;
        }
 
        private void btnAdd_Click(object sender, EventArgs e)
        {
            setValue(temp);
            temp = string.Empty;
            sign = ADD;
            txtInput.Text = string.Empty;
        }
 
        private void btnEquals_Click(object sender, EventArgs e)
        {
            setValue(temp);
            temp = string.Empty;
 
            switch (sign)
            {
                case ADD:
                    results = (Decimal.Parse(value1) + Decimal.Parse(value2)).ToString();
                    break;
                case SUBTRACT:
                    results = (Decimal.Parse(value1) - Decimal.Parse(value2)).ToString();
                    break;
                case MULTIPLE:
                    results = (Decimal.Parse(value1) * Decimal.Parse(value2)).ToString();
                    break;
                case DIVIDE:
                    results = (Decimal.Parse(value1) / Decimal.Parse(value2)).ToString();
                    break;
            }
 
            value1 = string.Empty;
            value2 = string.Empty;
            txtInput.Text = value1;
            isValue2 = false;
 
            lblResult.Text = results;
        }
 
        private void FormCalc_Load(object sender, EventArgs e)
        {
            lblResult.Text = string.Empty;
        }
    }
}

It’s Hammer time.

Not sure how many people will get that reference but we are about to start smashing the code. There is going to be a major, Hulk SMASH, sort of thing. Maybe I should have headed it with that one. Meh. Lets dig into it.

First, lets see if we can make this code move useful. How can we keep adding in additional values into the calculator and move away from just 2.

We will ditch the sign and values, and place them into their own class called Number. This class will also handle the parsing of the strings into numbers.

Number

using System;
 
namespace NoobToPro
{
    public class Number
    {
        public int value { getset; }
        public string sign { getset; }
 
        public void ParseSetValue(string valueToParse)
        {
            bool parseSuccess;
            int temp;
 
            parseSuccess = int.TryParse(valueToParse, out temp);
 
            if (parseSuccess)
            {
                value = temp;
            }
            else
            {
                throw new Exception("Value was not a number.");
            }
        }
    }
}

Next, we will replace them with a list of numbers in the main form. Be sure to include the using System.Collections.Generic at the top.

List<Number> values;

In the operator buttons, +-/*, we will create a placeholder Number called temp and set the sign and set the value. Since we are using the txtInput as the source for the complete number we will have to change the number button’s click events to append.

As a result of appending in the click events, setTemp won’t be needed any longer as the list takes care of dealing with the value storage location. So the function setTemp goes bye bye.

In the number button’s click events, we’ll swap out the setTemp function with appending the value to the contents of txtInput.Text. So the variable temp can go away too. So in each operation button, we can ditch the setValue and temp functions because we have resolved the assignment to a value issue. This also eliminates the isValue2 variable and the setValue function.

One little list changed so much. It is a testament to how much work we were doing just trying to get the correct number in the correct location.

With all that gone, the btnEqual_Click function is a mess. We need to clean it up. Since we have a list of numbers, we can loop through them. Before we loop, we need to know the expected operation. We will store that with a local variable lastSign. We must also capture the last value in the equation so we declare a temp variable then add it to the values list. Because we need to prime the pump we need the first value to be processed outside the loop. Check to make sure it is there, then process and remove it from the list.

Once it is gone then start the loop. We can strip out all the calculations and parsing because we did that with our ParseSetValue function in the Number class. As a result, we can just calculate. Then store the current value sign into lastSign so that we can move to the next value.

Clear everything out and we have done a small breakout that totally redefined the application’s code base and added a new level of usefulness to the program. I hope it is clear why the work we did before made this step easier.

Summing up the Noob to Pro break up process

We removed all the global empty strings. Getting rid of global variables is a really nice thing. We now only have one global variable to worry about in the code. The function setTemp and setValue are in the dump heap of obsolete code. Each of the number button’s click events have been simplified. The operator button’s click events are different but mostly a bust in terms of improvement. The equal button’s click event is a bit more complicated but not by a whole lot.

Compare the two code bases and you can see what changes happened and how the new base is so much cleaner in terms of what is going on and changing things.

Noob to Pro Post Breakup

using System;
using System.Windows.Forms;
using System.Collections.Generic;
 
namespace NoobToPro
{
    public partial class FormCalc : Form
    {
        List<Number> values;
 
        const string ONE = "1";
        const string TWO = "2";
        const string THREE = "3";
        const string FOUR = "4";
        const string FIVE = "5";
        const string SIX = "6";
        const string SEVEN = "7";
        const string EIGHT = "8";
        const string NINE = "9";
        const string ZERO = "0";
        const string PERIOD = ".";
 
        const string ADD = "+";
        const string SUBTRACT = "-";
        const string DIVIDE = "/";
        const string MULTIPLE = "*";
        const string EQUALS = "=";
 
 
        public FormCalc()
        {
            InitializeComponent();
        }
 
        private void btn7_Click(object sender, EventArgs e)
        {
            txtInput.Text += SEVEN;
        }
 
        private void btn8_Click(object sender, EventArgs e)
        {
            txtInput.Text += EIGHT;
        }
 
        private void btn9_Click(object sender, EventArgs e)
        {
            txtInput.Text += NINE;
        }
 
        private void btn4_Click(object sender, EventArgs e)
        {
            txtInput.Text += FOUR;
        }
 
        private void btn5_Click(object sender, EventArgs e)
        {
            txtInput.Text += FIVE;
        }
 
        private void btn6_Click(object sender, EventArgs e)
        {
            txtInput.Text += SIX;
        }
 
        private void btn1_Click(object sender, EventArgs e)
        {
            txtInput.Text += ONE;
        }
 
        private void btn2_Click(object sender, EventArgs e)
        {
            txtInput.Text += TWO;
        }
 
        private void btn3_Click(object sender, EventArgs e)
        {
            txtInput.Text += THREE;
        }
 
        private void btn0_Click(object sender, EventArgs e)
        {
            txtInput.Text += ZERO;
        }
 
        private void btnPeriod_Click(object sender, EventArgs e)
        {
            txtInput.Text += PERIOD;
        }
 
        private void btnDivide_Click(object sender, EventArgs e)
        {
            Number temp = new Number();
            temp.sign = DIVIDE;
            temp.ParseSetValue(txtInput.Text);
 
            values.Add(temp);
 
            txtInput.Text = string.Empty;
        }
 
        private void btnMultiply_Click(object sender, EventArgs e)
        {
            Number temp = new Number();
            temp.sign = MULTIPLE;
            temp.ParseSetValue(txtInput.Text);
 
            values.Add(temp);
 
            txtInput.Text = string.Empty;
        }
 
        private void btnSubtract_Click(object sender, EventArgs e)
        {
            Number temp = new Number();
            temp.sign = SUBTRACT;
            temp.ParseSetValue(txtInput.Text);
 
            values.Add(temp);
 
            txtInput.Text = string.Empty;
        }
 
        private void btnAdd_Click(object sender, EventArgs e)
        {
            Number temp = new Number();
            temp.sign = ADD;
            temp.ParseSetValue(txtInput.Text);
 
            values.Add(temp);
 
            txtInput.Text = string.Empty;
        }
 
        private void btnEquals_Click(object sender, EventArgs e)
        {
            string lastSign;
            Number final = new Number();
            Number temp = new Number();
 
            temp.ParseSetValue(txtInput.Text);
            values.Add(temp);
 
            if(values.Count >= 1)
            {
                final = values[0];
                values.RemoveAt(0);
                lastSign = final.sign;
 
                foreach (Number val in values)
                {
                    switch (lastSign)
                    {
                        case ADD:
                            final.value += val.value;   
                            break;
                        case SUBTRACT:
                            final.value -= val.value;
                            break;
                        case MULTIPLE:
                            final.value *= val.value;
                            break;
                        case DIVIDE:
                            final.value /= val.value;
                            break;
                    }
                    lastSign = val.sign;
                }
            }
 
            lblResult.Text = final.value.ToString();
 
            values = new List<Number>();
            lastSign = string.Empty;
            txtInput.Text = string.Empty;
        }
 
        private void FormCalc_Load(object sender, EventArgs e)
        {
            lblResult.Text = string.Empty;
            values = new List<Number>();
        }
    }
}
using System;
 
namespace NoobToPro
{
    public class Number
    {
        public int value { getset; }
        public string sign { getset; }
 
        public void ParseSetValue(string valueToParse)
        {
            bool parseSuccess;
            int temp;
 
            parseSuccess = int.TryParse(valueToParse, out temp);
 
            if (parseSuccess)
            {
                value = temp;
            }
            else
            {
                throw new Exception("Value was not a number.");
            }
        }
    }
}

Wrapping this up, we still have some duplication in the code. Because I am not done with the breakup of this program, we will leave it be for another day. In the next post we will build some testing.

Leave a Reply

Your email address will not be published. Required fields are marked *