21 Jan 2012 @ 3:00 PM 

Refactoring legacy code with the regular old incremental approach,

  1. If you have the chance convert to UML and document what little knarly architecture there is.

  2. If you are on version control look into generating some code churn reports and figuring out
    which files and file sections have been changed the most frequently. Make a note of these as
    they will likely be the areas you will want to deal with first.

  3. Before you change any code always try to add some test coverage
    (even ugly full stack functional tests will do).

    If dealing with large messy procedurial code extract logic you intend on changing into some
    reasonably named method or function and if possible add some test cases that verify your
    new method. make whatever god awful hack you have to and if possible paramatize the
    change if it is something commonly tweaked like margin width or title so it will be a little
    more straight forward to update the next time.

  4. Use the adapter pattern and work away at hiding the knarly bits of legacy code under
    a rug of logically named classes and methods so that for most common tasks you and
    the other developers perform you wont need to worry about the scary bits that are going
    on behind your back behind those nice little clean methods and classes you’ve hidden that
    legacy code behind — like those nice families that keep deformed murderous zombie former
    family members in barns so that they don’t spoil the day to day going-on’s of the farm
    . . . normally.

  5. As you continue to whittle away and clean up the sections of the code continue to boost your
    test coverage. Now you can dig down even deeper and “rewrite” even more code when
    needed/desired with ever increasing confidence.

  6. Repeat, or apply additional refactoring approaches to continue to improve your codebase.

Branching By Abstraction

  1. Define the trouble spot in the code you want to remove
    (the persistence layer, the pdf generator, the invoice tally mechanism, the widget generator, etc.).

  2. run (write if necessary) some functional test cases
    (automated or manual but you know automated)
    against the code base that targets this functionality along with general behavior.

  3. Extract logic related to that component from the existing sourcebase into a class
    with some reasonable interface.

  4. Verify all code is now using the new interface to perform activity X
    which was previously dispersed randomly throughout the code
    (Grep the code base, add a trace to the new class and verify pages that
    should be calling it are, etc.), and that you can control which implementation
    will be used by modifying a single file.(object registry, factory class, whatever
    IActivityXClass = Settings.AcitivtyXImplementer();)

  5. rerun functional test cases that verify everything is still functioning with
    all of Activity X throwin into your new class.

  6. Write unit tests where possible around the new activity X wrapper class.
  7. implement a new class with less insane spaghetti logic than the legacy
    implementation that adheres to the same interface as the legacy class.

  8. verify that the new class passes the unit tests you wrote for the legacy class.
  9. update your code by changing the registry/factorymethod/whatever to
    use the new class instead of the old class.

  10. verify that your functional tests still pass.

Open Closed Principle and a Common Business Logic/Persistence Layer

To some extent you might be able to get away with separating out your
presentation, business and persistence layer and writing a new app that
is fully backwards compatible with the legacy solution, or at a minimum
can still handle data inputted by legacy solution. I would probably not
recommend this approach but sometimes it is a reasonable compromise
of time/schedule/resources/required new functionality.

  • At a minimum separate the presentation layer away from the
    business and persistence layers.

  • implement a new ui and better presentation layer that uses
    the same common business and persistence layer.

  • Verify that data created with new ui does not break old ui.
    (you’re going to be in hot water if users of the new tool interrupt users of the old tool).

    If you are striving for full backwards compatibility you should be saving
    everything to the same persistence layers. If you just want forward compatibility
    into the new tool then use a new database and new tables or extension tables
    to track data not in legacy system.

  • For new functionality and persistence layer needs add new tables and methods
    don’t change existing legacy logic, or add columns, constraints to existing tables.

    e.g. if you need to start tracking employers emergency contact and some other fields
    don’t modify the existing employee table
    (we have no idea what assumptions the legacy data makes about that table) add an extension
    table employee_ext id, employee_id, emergency_contact_id, etc_id.

  • Slowly migrate users onto new system. if possible put legacy system into read only mode,
    or just add some warning telling users it will no longer be available after date X.

  • implement any hi priority missed functionality or business requirements in the new ui

  • roll over users base.
  • continue on to clean-up the business logic and persistence layer users other refactoring methodologies.
Posted By: admin
Last Edit: 21 Jan 2012 @ 03:00 PM

EmailPermalinkComments (0)
Tags
Categories: Uncategorized

 02 Dec 2011 @ 4:11 PM 

Was getting annoyed today with MsTest’s support for inline datasources for test cases. Started work on a little work around hack to simply generate and inject the xml files behind the scenes.

I ideally I will be able to inject enough logic into mstest that I can get rid of that intermediary as well.

For now I have

        [DataProviderMethodName("DataProviderExample")]
        [TestMethod]
        [DataSource("Microsoft.VisualStudio.TestTools.DataSource.XML", "|DataDirectory|\\TestMethod1.xml", "scenario", DataAccessMethod.Sequential)]
        public void UseRawDataProviderEntries()
        {
            System.Diagnostics.Trace.WriteLine("somestring = " + TestContext.DataRow["somestring"].ToString());
            System.Diagnostics.Trace.WriteLine("Gotcha = " + TestContext.DataRow["Gotcha"].ToString());
            Assert.IsTrue((bool)RawDataProviderContext["Gotcha"]);
        }

And I want to atleast get to

        [DataProviderMethodName("DataProviderExample")]
        [TestMethod]
        public void UseRawDataProviderEntries()
        {
            int t = 3243;
            System.Diagnostics.Trace.WriteLine("somestring = " + TestContext.DataRow["somestring"].ToString());
            System.Diagnostics.Trace.WriteLine("Gotcha = " + TestContext.DataRow["Gotcha"].ToString());
            Assert.IsTrue((bool)RawDataProviderContext["Gotcha"]);
        }

although . . .

        [TestMethod]
        [DataProviderMethodName("DataProviderExample")]
        public void UseRawDataProviderEntries(bool Gotcha, string somestring)
        {
            int t = 3243;
            System.Diagnostics.Trace.WriteLine("somestring = " + somestring);
            System.Diagnostics.Trace.WriteLine("Gotcha = " + Gotcha.ToString());
            Assert.IsTrue(Gotcha);
        }
        //===============
        // And
        //===============
        [TestMethod]
        [InlineDataSet]
        [DataSet("gotcha column","some string column")]
        [DataSet("just used reflection "," to read attributes and plug them in order of appearance into testmethod")]
        public void UseRawDataProviderEntries(string gotcha, string somestring)
        {
            int t = 3243;
            System.Diagnostics.Trace.WriteLine("somestring = " + somestring);
            System.Diagnostics.Trace.WriteLine("gotcha = " + gotcha);
            Assert.IsTrue(Gotcha == "true");
        }

would be swell.

using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Reflection;
using System.IO;
using System.Runtime.Serialization;
using System.Xml.Serialization;

namespace TestProject1
{
    [System.AttributeUsage(System.AttributeTargets.Method)]
    public class DataProviderMethodName : System.Attribute
    {
        private string name;
        public double version;

        public string Name
        {
            get
            {
                return name;
            }
        }

        public DataProviderMethodName(string name)
        {
            this.name = name;
            version = 1.0;
        }
    }

    [TestClass]
    public abstract class HackThePlanet
    {
        //todo encapsulate further
        protected static Dictionary>> _dataprovidercache = new Dictionary>>();
        protected Dictionary RawDataProviderContext
        {
            get
            {
                if (TestContext.DataRow["meta_provider"] != null)
                {
                    return _dataprovidercache[TestContext.DataRow["meta_provider"] + "_" + TestContext.DataRow["meta_providerhash"]][int.Parse(TestContext.DataRow["meta_index"].ToString())];
                }
                else
                {
                    return new Dictionary();
                }
            }
        }

        private TestContext testContextInstance;
        ///

        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///

        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }
    }

    [TestClass]
    public class UnitTest1 : HackThePlanet
    {

        static public List> DataProviderExample()
        {
            return new List>()
            {
                new Dictionary {  {"Gotcha", false}  , {"somestring","value2"}   },
                new Dictionary {  {"Gotcha", true}   , {"somestring","value3"}   },
                new Dictionary {  {"Gotcha", false}  , {"somestring","value2"}   },
            };
        }

        static public List> DataProviderExample2()
        {
            return new List>()
            {
                new Dictionary {  {"Gotcha", false}  , {"agag","value2"}   },
                new Dictionary {  {"Gotcha", true}   , {"agag","value3"}   },
                new Dictionary {  {"Gotcha", false}  , {"agag","value2"}   },
            };
        }

        [ClassInitialize()]
        public static void SetupClass(TestContext testContext)
        {
            var d = new DataSourceAttribute("Microsoft.VisualStudio.TestTools.DataSource.XML", "|DataDirectory|\\XMLFile1.xml", "row", DataAccessMethod.Sequential);
            var de = new DeploymentItemAttribute("TestProject1\\XMLFile1.xml");

            MethodInfo[] methodInfos = typeof(UnitTest1).GetMethods(BindingFlags.Public | BindingFlags.Instance);
            foreach(var m in methodInfos)
            {
                var t = m.Attributes;
                var a = m.GetCustomAttributes(false);

                var UseDataProviderMethodList = (from dpm in a
                                             where dpm.GetType() == typeof(DataProviderMethodName)
                                             select dpm);

                if (UseDataProviderMethodList.Count() > 0)
                {
                    // Grab DataSourceAttribute
                    var DataSourceAttributeList = (from dsa in a
                                               where dsa.GetType() == typeof(DataSourceAttribute)
                                               select dsa);

                    if (DataSourceAttributeList.Count() > 0)
                    {
                        var DataProviderMethodName = ((DataProviderMethodName)UseDataProviderMethodList.First()).Name;
                        var DataProviderMethod = typeof(UnitTest1).GetMethod(DataProviderMethodName);
                        var dataset = (List>)DataProviderMethod.Invoke(null, new object[0]);

                        //todo add some hash logic here if we want to allow dataprovider to return non determanistic data.
                        var hash = DateTime.Now.GetHashCode();
                        _dataprovidercache[DataProviderMethodName + "_" + hash] = dataset;

                        var DataSource = (DataSourceAttribute)DataSourceAttributeList.First();
                        //todo better support for different location preferences.
                        var requestedFile = DataSource.ConnectionString.Replace("|DataDirectory|\\", "\\");

                        //todo use xml tools for htis
                        string output = "";
                        output += "\n";
                        output += "\n";

                        int index = 0;

                        foreach (Dictionary scenario in dataset)
                        {
                            output += "\n";
                            // record keeping
                            output += "" + (index++) + "";
                            output += "" + DataProviderMethodName + "";
                            output += "" + hash + "";
                            foreach (KeyValuePair kv in scenario)
                            {
                                output += "     <" + kv.Key.Replace("\"", "\\\"") + ">" + kv.Value.ToString().Replace("\"", "\\\"") + "\n";
                            }
                            output += "\n";
                        }
                        output += "\n";
                        System.IO.File.WriteAllText(testContext.DeploymentDirectory + requestedFile, output);
                    }
                }
            }
        }

        [TestMethod]
        public void TestMethod1()
        {
            this.ToString();
            bool k = true;
            Assert.IsTrue(k);
        }

        //@todo Implement some way of preventing overwrites to the same DataSource.XML file ( preferably alter what is stored in the runner for xml name and
        // just replace with testcase name to insure uniqueness.
        [DataProviderMethodName("DataProviderExample")]
        [TestMethod]
        [DataSource("Microsoft.VisualStudio.TestTools.DataSource.XML", "|DataDirectory|\\TestMethod1.xml", "scenario", DataAccessMethod.Sequential)]
        public void UseRawDataProviderEntries()
        {
            int t = 3243;
            System.Diagnostics.Trace.WriteLine("somestring = " + TestContext.DataRow["somestring"].ToString());
            System.Diagnostics.Trace.WriteLine("Gotcha = " + TestContext.DataRow["Gotcha"].ToString());
            Assert.IsTrue((bool)RawDataProviderContext["Gotcha"]);
        }

        [DataProviderMethodName("DataProviderExample2")]
        [TestMethod]
        [DataSource("Microsoft.VisualStudio.TestTools.DataSource.XML", "|DataDirectory|\\TestMethod2.xml", "scenario", DataAccessMethod.Sequential)]
        public void UseRegularTestContext()
        {
            int t = 3243;
            System.Diagnostics.Trace.WriteLine("agag = " + TestContext.DataRow["agag"].ToString());
            System.Diagnostics.Trace.WriteLine("Gotcha = " + TestContext.DataRow["Gotcha"].ToString());
            Assert.IsTrue(TestContext.DataRow["agag"].ToString() == "value3");
        }

    }
}

. . .

Posted By: admin
Last Edit: 02 Dec 2011 @ 04:26 PM

EmailPermalinkComments (0)
Tags
Categories: Uncategorized

 07 Jul 2011 @ 1:47 AM 

Courtesy of the long list of things you probably shouldn’t do but will anyway heres how one goes about implementing mutex locking between multiple powershell scripts.

<#
1. Instantiate Mutex Object using new-object syntax
2. Use the same "DesiredMutexName" across scripts.  Or move mutex logic into a shared script included by each script desiring access to these mutexes.  (. Path\ScriptWithMutexLocks.ps1)
#>
$mutex = new-object -TypeName System.Threading.Mutex -ArgumentList $false, "YourDesiredMutexName";

# 3. Lock Access to critical sections in each script
$result = $mutex.WaitOne();
<#
Critical Section
#>

#4 Release
$mutex.ReleaseMutex();
<#
Script Specific / Non viotile section
#>

. . . Enjoy

Posted By: admin
Last Edit: 02 Dec 2011 @ 04:27 PM

EmailPermalinkComments (0)
Tags
Categories: Uncategorized

 24 Aug 2010 @ 4:59 AM 

I’ve been working on a port of JBehave/Cucumber for PHPUnit. So far things are looking good and I am getting very close to pushing my source code up to the google project page.

Essentially I hsve setup a test suite class that uses some simple regex logic to map test step functions to the plain text sentences stored in my test text file. I’ve got a long way to go in terms of polish and finish but the initial work looks pretty good so far.

More »

Posted By: admin
Last Edit: 24 Aug 2010 @ 05:01 AM

EmailPermalinkComments (2)
Tags
Categories: Uncategorized

 24 Aug 2010 @ 4:39 AM 

Andrescue has a couple of just genius approaches to generic meta programming his book “Modern C++ Generic Programming and Design Patterns Applied.” I really recommend checking it out.

Posted By: admin
Last Edit: 24 Aug 2010 @ 04:44 AM

EmailPermalinkComments (0)
Tags
Categories: Uncategorized





 Last 50 Posts
 Back
Change Theme...
  • Users » 71
  • Posts/Pages » 14
  • Comments » 10
Change Theme...
  • VoidVoid « Default
  • LifeLife
  • EarthEarth
  • WindWind
  • WaterWater
  • FireFire
  • LightLight

About



    No Child Pages.

About



    No Child Pages.

Resume



    No Child Pages.