Great Engineering Quotes

Monday, January 31, 2011 by K. Scott Allen
3 comments

Charles F. Kettering was an engineer, founder of Delco, and the head of research at General Motors for 27 years. I ran across a few choice quotes from the man.

“A problem well stated is a problem half solved.”

“A man must have a certain amount of intelligent ignorance to get anywhere.”

“If you want to kill any idea in the world, get a committee working on it.”

“It's amazing what ordinary people can do if they set out without preconceived notions.”

And here is one especially applicable to the world of software development:

“It is easy to build a philosophy - it doesn't have to run.”

The Big Rewrite

Thursday, January 27, 2011 by K. Scott Allen
16 comments

Lego® 7685 - DozerUnlike refactoring, a "big code rewrite" bulldozes an entire application and starts over from scratch.

Is it ever the right thing to do?

In a recent post, Steve Blank says no - never for start ups in a fast moving market (Startup Suicide - Rewriting the Code):

CEO’s face the “rewrite” problem at least once in their tenure. If they’re an operating exec brought in to replace a founding technical CEO, then it looks like an easy decision – just listen to your engineering VP compare the schedule for a rewrite (short) against the schedule of adapting the old code to the new purpose (long.) In reality this is a fools choice. The engineering team may know the difficulty and problems adapting the old code, but has no idea what difficulties and problems it will face writing a new code base.

I think the big rewrite is almost always the wrong approach to "fixing" software - even outside of startups. Rewriting is a form of engineering wankery that makes it easy to avoid the hard work - identifying, prioritizing, isolating, and improving selected subsystems or components of an application while keeping the business running. This appears to be the approach Twitter took some time ago when the service was falling over each and every hour. See the "Improving Running Components at Twitter" presentation and note it's not called "Rewriting Everything".

It's Design

Wednesday, January 26, 2011 by K. Scott Allen
14 comments

If I come across this code:

if (widget.Price < 10.0m && widget.UnitsInStock > 100)
{ 
    // ... 
}            

Then the first thing I'll suggest is refactoring to: 

if (widget.IsEligibleForDiscount)
{
    // ...
}            

But It's Not Reusable!

"IsEligibleForDiscount will never be reused!", someone will shout. "Why do we go to the trouble if the logic is never reused?".

Ah, yes - but if we only use encapsulation as a means to generalize and achieve reuse, then we're not taking advantage of what classes, methods, functions, objects, and properties truly have to offer. As Kevin Henney once wisely said: "there is no such thing as reusable software, only software that has been reused".

But It's Trivial!

"Why go to the trouble of creating a one-line method or property?".

Yes, it is is trivial, but you can't measure the effectiveness of an abstraction by it's size,  or by the amount of effort required to create the abstraction. This is like measuring the impact of an animation by counting how many colors it uses. It's often the small, quick, subtle animations that improve usability and polish. Likewise, a good abstractions can be small and still improve the usability of the code.

But It's Bad For Performance!

Go away - and don't come back without hard numbers.

It's Design

You've probably worked on applications that have two types of objects - objects with data and object with behavior. The objects with behavior are mostly procedural scripts to manipulate the objects with data. Strings and integers dominate the codebase. The objects aren't part of an object oriented design, but part of a process decomposition.

Breaking out of design habits is hard - it takes deliberate practice, and depends on introspective moments.

We can debate in our minds if the refactoring make the code better or worse - but let's at least have the debate.

The Refactoring Curve

Tuesday, January 25, 2011 by K. Scott Allen
2 comments

imageEmpirical studies on software refactoring are hard to find, but I believe refactoring follows the 80/20 rule - 80% of the possible benefit comes by applying just the first 20% of effort. Like most work in engineering and economics, the curve flattens under the pressure of diminishing returns. In this context I'm not thinking of individual refactoring operations (like extract method), but overarching efforts to improve software quality through rework, or by following a process like test-first design.

I think most of use could agree that the best place to be on this curve depends on context. Start-up software is different than complex software for a mature enterprise.

Taking context into account - do you feel like you operate in the sweet spot of the curve for your project?

My suspicion is that developers who read blogs feel like their project are always too far on the left hand side of the curve, but I wonder if the business owners feel the same way.

What&rsquo;s Wrong With This Code? (#26)

Monday, January 24, 2011 by K. Scott Allen
10 comments

A measurement consists of a high reading and a low reading, but the high and low values are optional. We also need to add measurements together, so the following C# code:

var m1 = new Measurement(lowValue: 3, highValue: 5);
var m2 = new Measurement(null, 3);
var m3 = new Measurement(6, 2);
Console.WriteLine(m1 + m2 + m3);

… should produce a total measure showing a low value of 9, a high value of 10 (effectively ignoring null values).

Unfortunately, something is wrong with the implementation...

public struct Measurement
{
    public Measurement(int? lowValue, int? highValue)
    {
        _lowValue = lowValue;
        _highValue = highValue;
    }

    public static Measurement operator +(Measurement first, 
                                         Measurement second)
    {
        var result = new Measurement
        {
            _lowValue = first._lowValue + second._lowValue,
            _highValue = first._highValue + second._highValue
        };
        return result;
    }

    public override string ToString()
    {
        return String.Format("{0}-{1}", _lowValue, _highValue);
    }

    private int? _lowValue;
    private int? _highValue;
}

Did you spot it?

Injectable, Configurable Action Filters

Thursday, January 20, 2011 by K. Scott Allen
2 comments

One of the advantages to using a custom IFilterProvider is how you gain total control over the instantiation of action filters in ASP.NET MVC 3. When you combine an IoC container with a filter provider and a custom IDependencyResolver (see Brad's posts for details),  then all the pieces fall into place. Building on the code from the last post, we can change our filter provider to utilize Ninject for action filter instantiation.

public class ConfiguredFilterProvider : IFilterProvider
{
    private readonly IKernel _kernel;

    public ConfiguredFilterProvider(IKernel  kernel)
    {
        _kernel = kernel;
    }

    public IEnumerable<Filter> GetFilters(
        ControllerContext controllerContext, 
        ActionDescriptor actionDescriptor)
    {
        var filters = FiltersSettings.Settings.Filters;
        foreach (var filter in filters.Cast<FilterAction>())
        {
            var filterType = Type.GetType(filter.Type);
            yield return new Filter(
                    _kernel.Get(filterType),
                    FilterScope.Global, order:null          
                );
        }
    }
}

Using Ninject to create the filters makes it trivially easy to inject dependencies into the filter. In case you didn't know, action filters in MVC 3 no longer need to derive from an attribute derived base class. All you need is a class that implements one or more of the action filter interfaces.

public class LoggingFilter : IActionFilter, 
                             IExceptionFilter, 
                             IResultFilter, 
                             IAuthorizationFilter
{

    public LoggingFilter(ISomeDependency dependency)
    {
            
    }

    // ...
}

If you are using Ninject, you'll also want to use a custom IDependencyResolver based on Ninject. It's easy to write your own, or you can add one already implemented for you from the NuGet gallery.

image

With the custom dependency resolver in place, you no longer need to register your filter provider in the FilterProvider.Providers collection. Instead, you can just register the provider as another service in the container.

public static class AppStart_NinjectMVC3
{
    public static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<IFilterProvider>()
              .To<ConfiguredFilterProvider>();
        kernel.Bind<ISomeDependency>()
              .To<SomeDependency>();
    }

    public static void Start()
    {
        IKernel kernel = new StandardKernel();
        RegisterServices(kernel);
        DependencyResolver.SetResolver(
            new NinjectServiceLocator(kernel));
    }
}

In previous versions of MVC, filters were notoriously difficult for injection, and mostly inflexible. MVC 3 is a great improvement.

Configurable Action Filter Provider

Wednesday, January 19, 2011 by K. Scott Allen
3 comments

In MVC 3 you can implement an IFilterProvider to create and feed action filters to the MVC runtime. Assuming you have the configuration classes in place from the last post, you can create a custom filter provider to add action filters to the MVC pipeline. 

public class ConfiguredFilterProvider : IFilterProvider
{
    public IEnumerable<Filter> GetFilters(
        ControllerContext controllerContext, 
        ActionDescriptor actionDescriptor)
    {
        var filters = FiltersSettings.Settings.Filters;
        foreach (var filter in filters.Cast<FilterAction>())
        {
            var filterType = Type.GetType(filter.Type);
            yield return new Filter(
                    Activator.CreateInstance(filterType),
                    FilterScope.Global, order:null          
                );
        }
    }
}

Notice a filter provider receives context parameters it can use to determine if it should create a filter, or not. In this case we are creating global filters from whatever we find in the web.config file, so the parameters are left untouched.

To plug your filter provider into the MVC runtime, you'll need to execute a bit of code during application start up:

FilterProviders.Providers.Add(new ConfiguredFilterProvider());

In the next post we'll combine the filter provider with Ninject to take advantage of MVC 3's new dependency resolution features.

by K. Scott Allen K.Scott Allen
My Pluralsight Courses
The Podcast!