Tuesday, October 26, 2010

Open Source Software Stupid Tax

I'm sure I read or heard this somewhere before but my searches have turned up nothing.

If you fix a bug or add a feature to an open source project and you don't contribute that bug back to the project this is referred to as the stupid tax.

The reason that you fixed this bug in the first place is because it was preventing you from using the open source software the way that you wanted to use it. It might not even be a bug, it might be a feature that was missing that you needed.

Not contributing it back to the project is a stupid tax because it means that each time you want to upgrade to the latest version of the open source code you have to reapply your fix or feature. This is going to cost you in time and if you don't get it right first time it may introduce further bugs into your system. If you have someone else working on the team and they decide to upgrade the open source project to the latest version they might not know that you had "modded" the OS project. You might not even know that the developer that you replaced on the team applied a patch to it and then you're left scratching your head and trying to work out why the upgraded OS code is not working with your project.

Don't pay the stupid tax. Get your fixes and features back into the open source project as soon as possible and give yourself a pain free upgrade path to further releases of the OS project.

Saturday, October 16, 2010

RunAs Utility

I've recently discovered (been introduced to) the runas command line utility which I was previously unaware of. This command allows you to run in the context of another user which is particularly useful if you are testing access permissions under different user names. The syntax is:

runas /user:mydomain\myuser program.exe

The one annoyance is that when you run that command it requires that you type in the password and if its a particularly long and complex password I will often make a mistake. However, because this is in a command window you can copy the password to the clipboard and right click at the password prompt and select Paste and it works.

Try running the following with a different user who is registered on your local computer.

runas /user:mydomain\myuser cmd

This will bring up a new command prompt in the context of that user. Now type the command...

whoami

...in both command windows. You will see that each command window is running in the context of a different user.

Improving security and reducing HTTP header size in IIS

I've identified four unnecessary HTTP header elements that get transmitted with one of my ASP.NET MVC2 web sites. I wanted to remove these headers to improve security and reduce header size and thought that it would be easy to remove these HTTP headers from IIS7 in the same manner. It turned out that each of them had to be removed with a different technique.

X-Powered-By: ASP.NET

This header is removed through the IIS Manager. You can remove it on a site by site basis or remove it for the server. If removed from the server then it's removed from all sites on that server. This is the approach I prefer.

  1. Bring up IIS Manager.
  2. Click on the server name in the left panel
  3. Under the IIS section in the server area you will see HTTP Response Headers, double click on this.
  4. Click on the line that says "X-Powered-By ASP.NET Local"
  5. In the Actions pane on the right click Remove.

Server: Microsoft-IIS/7.0

This one is a bit more tricky to remove and needed some code to be added to the web site.

In the MasterPage.master code behind file in the Page_Load function I put the following:

HttpContext.Current.Response.Headers.Remove("Server");

X-AspNet-Version    4.0.30319

To get rid of this one I had to edit the web.config file and set the enableVersionHeader attribute to false:

<httpRuntime enableVersionHeader="false" />

X-AspNetMvc-Version: 2.0

In the constructor for the Global class in the global.asax.cs file I set the static DisableMvcResponseHeader property of the MvcHandler class to true.

public Global()
{
      MvcHandler.DisableMvcResponseHeader = true;
}

Sunday, October 3, 2010

The Male Brain by Louann Brizendine

The Male Brain by Louann BrizendineJust finished The Male Brain by Louann Brizendine.

I was very surprised at how much I liked this book and how good it was. I can't remember who recommended it or why I picked it up because it's not the sort of thing I would have normally read.

I particularly enjoyed the section about the teenage male brain. Finally I don't feel so guilty about the way that I behaved when I was a teenager, I was wired to behave that way.

I believe that the male brain is a sequel to The Female Brain which I have not read and I'm not sure if you need to read it after reading The Male Brain. I say this because at every stage of life she compares and contrasts the male brain to the female brain so you're really learning about both and their differences.

At the end of the day the reason why we act the way that we do is because we have these chemicals marinating our brains and pushing us back towards the stone age man.

Nested Parallel.ForEach()

I recently wrote some code that was using Parallel.ForEach() and in the function called during the Parallel.ForEach() I nested another call to Parallel.ForEach() to process a second array. This then got me thinking. If the first array that you are processing is larger than the number of cores on the machine that you're running it on then there's no advantage to nesting a second Parallel.ForEach(). You might as well just loop in that function because we'll already have all the processors saturated. So I put together a test to see the difference between Parallel.ForEach() with a regular loop and Parallel.ForEach() with a nested Parallel.ForEach()

static void ParallelMainNestedTest()
{
    int[] lowerRange = Enumerable.Range(0, 10).ToArray();
    int[] upperRange = Enumerable.Range(1000, 1010).ToArray();

    Stopwatch timer = Stopwatch.StartNew();
    Parallel.ForEach(lowerRange, lowerValue =>
        DoItemNotNested(lowerValue, upperRange));
    Console.WriteLine("Not Nested: {0}", timer.Elapsed);

    timer.Restart();
    Parallel.ForEach(lowerRange, lowerValue =>
        DoItemNested1(lowerValue, upperRange));
    Console.WriteLine("Nested: {0}", timer.Elapsed);

    Console.ReadKey();
}

static void DoItemNotNested(int lowerValue, int[] upperRange)
{
    foreach (int upperValue in upperRange)
    {
        Thread.Sleep(10);
    }
}

static void DoItemNested1(int lowerValue, int[] upperRange)
{
    Parallel.ForEach(upperRange, upperValue =>
        DoItemNested2(lowerValue, upperValue));
}
static void DoItemNested2(int lowerValue, int upperValue)
{
    Thread.Sleep(10);
} 

The results of this test showed:

Not Nested: 00:00:14.6155628
Nested: 00:00:09.0907248

Now the reason that I put a sleep in the inner loop of the two tests is because this test code is designed to simulate network access (a REST call to a site) and I wanted to create a test where there would be idle wait time to determine which strategy is better. I appears, as you can see, that a pair of nested Parallel.ForEach() calls is most efficient in this scenario.

What if there was no latency in the inner loop and it was all down to the speed of the processor?

My suspicion is that the nested Parallel.ForEach() would be slower because of the extra overhead in managing the extra threads. To test this I replaced the Thread.Sleep(10) call with the following:

static Random r = new Random(Guid.NewGuid().GetHashCode());
private static void DoSomething(int lowerValue, int upperValue)
{
    for (int i = 0; i < 5000; i++)
    {
        int rand = r.Next(lowerValue, upperValue);
        rand = rand * rand;
    }
}

The result:

Not Nested: 00:00:05.6169188
Nested: 00:00:06.1500767

Confirmed: The nested Parallel.ForEach() shows a degradation in performance because of the extra overhead in managing all those extra threads.

Conclusion: Used nested Parallel.ForEach()'s when you know that the inner loop will be waiting on external resources (database, disk, network etc.). Use regular looping in the inner loop if you are doing a math or algorithmic intensive calculation that relies on the CPU alone.

Wednesday, September 15, 2010

Drive: The Truth About What Motivates Us

Drive: The Surprising Truth About What Motivates UsAnother audio book finished: Drive: The Surprising Truth About What Motivates Us by Daniel Pink.

Excellent book! If you've read any of the books mentioned in previous blog posts you will notice that you've already heard many of the examples that he uses. He quotes experiments done by Dan Ariely in Predictably Irrational and also uses many of the same examples as him. He also quotes the oft quoted Wikipedia example which I'm getting tired of.

In Drive, Dan discusses what motivates us and demonstrates that extrinsic motivators, if - then rewards, only work on routine tasks and have a negative impact on creative work which require intrinsic motivators.

He talks about a new "Operating System" for business revolving around the three elements of Autonomy, Master, and Purpose.

Autonomy - people want to direct their own lives.

Mastery - we want to get better and become experts or go-to-guys for something that matters.

Purpose - that what we are doing is in the service of something larger than ourselves, something meaningful.

I think that as a software engineer it's pretty easy to be in a job that satisfies the first two elements. Most development work is based around results and we're given the autonomy to produce those results. We have to master the subject to be able to do the job. Those are a given. I think that the job of software engineer might fall short when it comes to purpose and it's sometimes difficult to see the big picture of what you're contributing to.

Concepts that I enjoyed from this book

FedEx Days - Australian software company Atlassian give their employees a FedEx day once a quarter. Engineers start work on a Thursday evening at 5pm and have to deliver something by 5pm on the Friday - i.e. have to deliver something overnight - hence FedEx - so long as it has nothing to do with their regular job.

Google 20% Time - 20% of your time is spent working on a project that might benefit the company but has nothing to do with your day-to-day work. Similar to FedEx Days but you're given 1 day a week to do this instead of a 24-hour period once a quarter.

ROWE - Results Only Work Environment. No schedule, don't need to be in the office, meetings are optional. Personally I think that you have to have the right type of employee to make this work.

Tuesday, September 14, 2010

Create a chart using .NET 4 and ASP.NET MVC





This is a "pattern" that I have come up with to create a chart on-the-fly using .NET 4 and MVC. I happen to be using MVC2 but I don't believe that there are any v2 features that I'm using so this will work equally well in MVC 1.0. As you'll notice it can also easily be adapted to be used in a web form web app as well.
At the end of 2008 Scott Guthrie announced ASP.NET Charting which you could download and add to your project. Microsoft had bought Dundas Charting and was now giving it away for free. In .NET 4 they have bundled that charting library so you don't need a separate download and all you have to do is include the System.Web.UI.DataVisualization.Charting namespace, however, I'm getting ahead of myself.
Here are the components to the on-the-fly chart generation in an ASP.NET MVC web application.
The Controller
public ActionResult Chart(int id)
{
    ChartGen cg = new ChartGen();
    MemoryStream ms = cg.GenerateChart(id);

    return File(ms.ToArray(), "image/png", "mychart.png");
}

It really is that simple. All the heavy lifting takes place in my ChartGen class. What is happening here is that the GenerateChart() function is getting a memory stream and that is being passed back as a file action result of type image/png. The chart that is being generated is identified by the first parameter (id) passed in to the ShowChart() function. In this example it's a dummy placeholder value but would allow you to pull the data for the chart from a database based on that index.
The View
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <p>
        <img src="/Home/Chart/1" alt="This is a sample chart" />
    </p>
</asp:Content>

In its most simplistic form the view has a reference to the controller as the source attribute of an image tag. That's really all there is to it.
The Chart Generator
public Chart chart { get; set; }
public MemoryStream GenerateChart(int symbolId)
{
    List<Price> priceList = GetPrices().ToList();

    chart = new Chart();
    chart.Customize += new EventHandler(chart_Customize);
    chart.BorderSkin.SkinStyle = BorderSkinStyle.Emboss;
    chart.BackColor = ColorTranslator.FromHtml("#D3DFF0");
    chart.BorderlineDashStyle = ChartDashStyle.Solid;
    chart.Palette = ChartColorPalette.BrightPastel;
    chart.BackSecondaryColor = Color.White;
    chart.BackGradientStyle = GradientStyle.TopBottom;
    chart.BorderlineWidth = 2;
    chart.BorderlineColor = Color.FromArgb(26, 59, 105);
    chart.Width = Unit.Pixel(500);
    chart.Height = Unit.Pixel(300);

    Series series1 = new Series("Series1");
    series1.ChartArea = "ca1";
    series1.ChartType = SeriesChartType.Candlestick;
    series1.Font = new Font("Verdana", 8.25f, FontStyle.Regular);
    series1.BorderColor = Color.FromArgb(180, 26, 59, 105);

    foreach (Price dayBar in priceList)
    {
        bool upDay = dayBar.Open < dayBar.Close;
        series1.Points.Add(new DataPoint
        {
            BackSecondaryColor = upDay ?
                    Color.LimeGreen : Color.Red,
            BorderColor = Color.Black,
            Color = upDay ? Color.LimeGreen : Color.Red,
            AxisLabel = dayBar.Date.ToString("dd-MMM-yy"),
            YValues = new double[] { (double)dayBar.High,
                (double)dayBar.Low, (double)dayBar.Open,
                (double)dayBar.Close }
        });
    }

    chart.Series.Add(series1);

    ChartArea ca1 = new ChartArea("ca1");
    ca1.BackColor = Color.FromArgb(64, 165, 191, 228);
    ca1.BorderColor = Color.FromArgb(64, 64, 64, 64);
    ca1.BorderDashStyle = ChartDashStyle.Solid;
    ca1.BackSecondaryColor = Color.White;
    ca1.ShadowColor = Color.Transparent;
    ca1.BackGradientStyle = GradientStyle.TopBottom;

    ca1.Area3DStyle.Rotation = 10;
    ca1.Area3DStyle.Perspective = 10;
    ca1.Area3DStyle.Inclination = 15;
    ca1.Area3DStyle.IsRightAngleAxes = false;
    ca1.Area3DStyle.WallWidth = 0;
    ca1.Area3DStyle.IsClustered = false;

    ca1.AxisY.LineColor = Color.FromArgb(64, 64, 64, 64);
    ca1.AxisX.MajorGrid.LineColor = Color.Transparent;
    ca1.AxisY.MajorGrid.LineColor = Color.FromArgb(64, 64, 64, 255);
    ca1.AxisY.MajorGrid.LineDashStyle = ChartDashStyle.Dash;

    double max = (double)priceList.Select(a => a.High).Max();
    double min = (double)priceList.Select(a => a.Low).Min();
    double rangeAdjust = (max - min) * 0.03;
    max += rangeAdjust;
    min -= rangeAdjust;
    ca1.AxisY.Minimum = min;
    ca1.AxisY.Maximum = max;

    chart.ChartAreas.Add(ca1);

    MemoryStream memoryStream = new MemoryStream();
    chart.SaveImage(memoryStream, ChartImageFormat.Png);
    memoryStream.Seek(0, SeekOrigin.Begin);

    return memoryStream;
}

void chart_Customize(object sender, EventArgs e)
{
    CustomLabelsCollection yAxisLabels = chart.ChartAreas["ca1"].AxisY.CustomLabels;

    for (int labelIndex = 0; labelIndex < yAxisLabels.Count; labelIndex++)
    {
        decimal price = Convert.ToDecimal(yAxisLabels[labelIndex].Text);
        // Do your formatting of price here
        yAxisLabels[labelIndex].Text = (price/100).ToString("0.00");
    }
}

Random r = new Random((int)DateTime.Now.Ticks);
IEnumerable<Price> GetPrices()
{
    int open, high, low, close = r.Next(4000, 6000);
    for (int i = -20; i < 1; i++)
    {
        open = r.Next(close - 30, close + 30);
        close = r.Next(open - 70, open + 70);
        high = Math.Max(open, close);
        high = r.Next(high, high + 100);
        low = Math.Min(open, close);
        low = r.Next(low - 100, low);

        yield return new Price
        {
            Date = DateTime.Now.AddDays(i).Date,
            Open = open,
            High = high,
            Low = low,
            Close = close
        };
    }
}

That's a chunk of code to read through but it's not that bad.
We start off by creating a Chart object and attaching an event handler to the Customize property. This event is raised when all the axis and data have been calculated for the chart and just before the chart is rendered. This allows you to change formatting and options on the chart. For example the Chart object will generate values for you on the Y-Axis, when the customize event is raised you can format these values.
There are a bunch of colors and formats you can set for the chart.
The Series object allows you to define a series of data that will be displayed on the chart. In this example we're displaying stock market data in a candlestick format so we set the appropriate data. Once we've defined the series we add it to the chart object.
The rest of the code addresses mostly formatting. There is some code that sets the maximum and minimum values for the Y-Axis so that they are 3% off the lows and highs.
Finally we generate a memory stream and return this image as a memory stream.
I usually have caching in there as well and will cache the memory stream for a period of time using the id passed in to the function as the key to the cache. That way I can have many chart images in memory cache and pull them out without causing them to be generated each time. I have also excluded all the try catch blocks that I would usually have in there.
Here is the Price class that you'll need in the code above:
public class Price
{
    public DateTime Date { get; set; }
    public double Open { get; set; }
    public double High { get; set; }
    public double Low { get; set; }
    public double Close { get; set; }
}

This is the final result: