OdeToCode IC Logo

Make It Yours

Wednesday, February 2, 2011 by K. Scott Allen

I went to a general store, but they wouldn't let me buy anything specific. - Steven Wright.

One of the challenges of working with a general purpose programming language (like C#) and a general purpose framework (like ASP.NET, Silverlight, or any other application framework) is building something specific.

The trick is to apply constraints and build abstractions to take ownership of the situation, and there is an entire bag of fancy tricks to pull from, like using fluent APIs or applying domain driven design. But taking real ownership goes beyond just building the right classes - it's also about circumventing the underlying framework to match the needs of the team, the application, and the business in general. If you look at opinionated frameworks like OpenRasta, FubuMvc, and Caliburn.Micro, you'll find they make assumptions about what you want from a framework. These assumptions simplify design decisions and you'll often find it easier to find the one right way to achieve some goal.

Example, Please

Let's say your are using a relatively general purpose web framework like ASP.NET MVC 3. Every controller action needs to respond with one of two views depending on some bit of user information. To simply the scenario, we'll say we switch on the IsAuthenticated flag.

if (Request.IsAuthenticated)
{
    return View("private/index");
}
else
{
    return View("public/index");
}
image

Although it feels pretty good to keep the different views you need inside of separate folders, it's just a first step. The above code typifies what happens when you let the framework control you instead of taking control of the framework. When the above code appears inside of every primary controller action it reads like this: "the framework gives me a View method, and that's all I have to use."

To take this one step further you'll want to simplify the controller code and move the view decision out of the controller. Maybe this means you write a new helper method, a new action filter, or if the logic applies everywhere, a new view engine.

public class CustomViewEngine : IViewEngine
{
    ...

    public ViewEngineResult FindView(
        ControllerContext controllerContext, 
        string viewName, string masterName, bool useCache)
    {
        if (controllerContext.HttpContext.Request.IsAuthenticated)
        {
            viewName = "private/" + viewName;
        }
        else
        {
            viewName = "public/" + viewName;
        }
        return _inner.FindView(controllerContext, viewName, 
                               masterName, useCache);
    }

    RazorViewEngine _inner = new RazorViewEngine();
    ...
}

Then configure the engine into your application.

protected void Application_Start()
{
    ViewEngines.Engines.Clear();
    ViewEngines.Engines.Add(new CustomViewEngine());    
    ...
}

And now controller code is simple again.

return View();

The need for your application to offer two distinct views in every scenario is now implicitly baked into the infrastructure.

Conventions and Constraints

Taking control of the software often means you apply constraints (what I should not do) and conventions (what I don't need to do). The downside is having more implicit "magic" inside the code, but the upside is having simple code focused on specific solution.

JavaScript Koans

Tuesday, February 1, 2011 by K. Scott Allen

Programming koans liberally borrow from Zen Buddhism to teach programming. If you look around the Internet, you'll find koans to learn Ruby, koans to learn functional programming, and thanks to Liam Mclennan, you can alse use koans to learn JavaScript.

From the readme:

JavaScript Koans is an interactive learning environment that uses failing tests to introduce students to aspects of JavaScript in a logical sequence. The inspiration for this project comes from the Edgecase Ruby Koans and the book 'Javascript: The Good Parts'. Open the file jskoans.htm in your favourite browser and make the tests pass.

image

Liam also just finished a JavaScript course for Pluralsight On-Demand! If you are a subscriber - check it out.

Great Engineering Quotes

Monday, January 31, 2011 by K. Scott Allen

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

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

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

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

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?