Showing posts with label Agile Methodology. Show all posts
Showing posts with label Agile Methodology. Show all posts

Tuesday, May 7, 2013

Refactoring? Or Rewriting?

I was recently asked in an interview what it meant to refactor code and what the prerequisite was to refactoring. I have to admit, I was a bit thrown off being asked what the "prerequisite" is, since it seems to me to be reflexive software development nowadays. To me, refactoring is an interesting concept in software development that a lot of other engineering-type professions don't get to leverage as freely as we do. But, I think it has become (incorrectly) synonymous with rewriting code. (Or maybe refactoring is instead used as a guise to rewrite.)

Refactoring is very simple and is akin to rewording the language in your code to express the same idea, or original intent, in a different statement. Rewriting your code is changing the intended behavior of the code—the opposite of refactoring. I have spent a lot of time refactoring some code on my current project lately, and I have run across a the following code a lot.

public List<Foo> GetFoos(SomethingElse[] somethingElses)
{
    var retval = new List<Foo>();

    foreach(var else in somethingElses)
    {
        retval.Add(new Foo() { Bar = else.Bar });
    }

    return retval;
}

So, this is a pretty trivial sample of code, but it is really easy to see what is going on and what the intent of the code is. Basically, it is mapping a collection of one type of object to a collection of another type. We create a list and then iterate through the original collection, appending a new instance of Foo, and then return it. Using LINQ, we can actually simplify this just a tad and even type less code to get the same effect. (Refactor it.)

using System.Linq;

public List<Foo> GetFoos(SomethingElse[] somethingElses)
{
    return somethingElses
        .Select(x => new Foo() { Bar = x.Bar })
        .ToList();
}

Again, this is a trivial example, but it shows how we can refactor our code, keep in tact the original desired behavior, but use different syntactic sugars to clean it up. (I prefer using LINQ, personally, over foreach, especially in nested situations.) But, besides this being a trivial situation, what confidence do we have that we did not silently introduce a bug into our system? What assurance do we have? Well, before refactoring our code, we should put barriers in place to help us reason about our code. In the simplest sense, we should have a unit test, in place, before we make our changes to assert that we did not introduce a bug. Of course, if we're good TDDers we would have this unit test in place already, and have a nice regression test to fall back on. If not, it would behoove us to get one in place, quickly.

[Test]
public void given_an_array_of_something_elses_it_should_return_a_list_of_foos()
{
    var somethingElses = Enumerable.Range(0, 5)
        .Select(i => new SomethingElse() { Bar = i })
        .ToArray()

    // Let's assume GetFoos is defined as a static method on Baz
    var result = Baz.GetFoos(somethingElses);

    for (int i = somethingElses.Length - 1; i >= 0; --i)
    {
        Assert.That(result[i].Bar, Is.EqualTo(somethingElses.ElementAt(i).Bar));
    }
}

Well, that's refactoring, but what about rewriting? If we look at our simple method, what happens when we pass in a null array of SomethingElse? At this point, our method doesn't care and will attempt to iterate over it anyway. This, of course, results in a null reference exception and we have to track down how this happened. But, let's say we decide to change the behavior of this method. We, instead, will throw an exception if the array is null because we the precondition has not been met. Since we are changing the method's behavior, we are rewriting our code. One hint that this is a rewrite is the fact that we need to introduce a new unit test.

[Test]
public void given_a_null_array_it_should_throw_an_argument_null_exception()
{
    var exception = Assert.Throws<ArgumentNullException>(() => Baz.GetFoos(null));
    Assert.That(exception.ParamName, Is.EqualTo("somethingElses"));
}

I have used NUnit-style syntax in this post, but it should be fairly clear what is being tested.

Now, why is this important? Well, as we're writing our code, we tend to learn a lot about it. We see new ways to implement things that allow us to, later, extend the behavior of something without changing the original meaning. It also allows us to nicely execute test driven development: "Red –> Green –> Refactor."

Tuesday, April 9, 2013

Agile Software Development

As I am currently in a transition phase out of my current job, I have been looking at my résumé a lot. I noticed that I do not have the word "Agile" on it at all. This is interesting to me because it was something that I tried to promote just a few years ago. I think that has a lot to do with how I view software development now. While listening to a .NET Rocks round-table podcast a few months back, the question, "Is agile dead?" was posed. The answers were pretty interesting, but the one that stuck out to me the most was something along the lines that agile isn't dead, it is just the way we do software development now.

On the shows's page, a listener, "bashmohandes," made a comment that I have been thinking about for a very long time:

I don't think Agile is dead, but I think it got ruined by companies that think they are doing it but they are just fooling themselves, or using it as an excuse to keep changing requirements on the poor developers.

Most of the places I worked at, have some remnants of agile methods, like daily scrums, but pretty much nothing more, no fixed size sprints, or spring planning meetings, or retrospective meetings at the end of the sprint, or pair programming.

Specifically, that companies are "using it as an excuse to keep changing requirements." While I am leaving my current position, this is something that I have been struggling to keep from affecting my team. There are a few people in place who could fix this—but they don't. In fact, I don't think they know how to. It was recently told to me that we develop software in "a more waterfall approach." This made me laugh a bit as we don't even follow waterfall. That whole requirements gathering thing is a joke. The developers are currently expected to read the customer's ever changing mind and it is difficult to pin them down.

My current project has been around since the 70s and supports a major command of the USAF. The failure of the application means that troops and supplies are halted and commanders can lose situational awareness of their fleets. But, even with how critical this application is, there is hardly any structure when it comes to defining requirements and paving a path forward. Listening to the podcast really hit home. So many managers seem to want a "spray on agile" solution as if it is some sort of magic. Well, it isn't and "spray on solutions" don't work. In fact, they make things worse.

On the web development side of the shop, I have been able to focus everybody's attention on unit testing, pair programming, and actually talking with the stake holders. Unfortunately, the planning portion is still lacking. Our side of the house has been strategically made void of information silos. Unfortunately, on the COBOL side of things, they still exist. Each COBOL programmer works at their own pace, makes changes, and throws them at the web team to handle. Cause we're agile.

While I believe that true agile is the way to go in software development, I also take a pragmatic approach to things. When initially implementing an agile methodology, it is usually very difficult to get everybody on board, up front, and willing to make all the changes necessary to truly support the change. But, it is important to keep going, keep adding things, keep changing, keep growing, keep learning. It really takes a substantial commitment from management, the customer, and the development team, to realize that they are all in it together.