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:


You, Inc.: The Art of Selling Yourself

You Inc The Art of Selling YourselfRecently finished listening to the audio version of You, Inc.: The Art of Selling Yourself by Harry Beckwith.

There was nothing in this book that I could disagree with. It all made perfect sense. The main takeaway that the book kept on hinting at was to look around you and take note of who impresses you, how they do it and why. Same applies to companies. Compare people to each other. Why does Jill impress you and Nancy not as much? Nancy knows more, speaks better, and is friendlier but she wears jeans and T-shirts to work. Jill is always wearing a business suit, that's all it takes. This is of course a contrived and simple example but it highlights how we are always selling ourselves in everything we do, say, wear and eat.

Sex, politics and religion

It seems that I have known forever that you don't talk about sex, politics, and religion in formal environments. I once attended a lunch with 7 journalists and during the first 30 minutes of lunch all that was talked about was sex, politics and religion. When I jokingly pointed this out they said that as journalists they could talk about anything at anytime. So maybe this rule doesn't apply to journalists. However, it definitely applies to all work environments that I have been in and I have seen some interesting mistakes through slight of tongue on these three forbidden topics.

Apart from listening to this book I also have the hard copy. One thing that I didn't realize about it while listening to it is that it's made up of lots of short one page chapters. Easy vignettes that can each be read in 30 seconds. This is a great book to keep in the lavatory - if that isn't awesome praise then nothing is.

Monday, September 13, 2010

Strengths Finder 2.0

Strengths Finder 2.0Just finished doing the test and reading the book for Strengths Finder 2.0 by Tom Rath.

This is an interesting "book" to read from the point of view that the book is only "usable" by one person. You cannot gift the book after you've read it. The book starts off with 30 pages of introduction which are fairly quickly put behind you and effectively convince you of the merits of continuing. You then turn to the back of the book and cut open the packet which has your unique access code to the strengthsfinder 2.0 assessment and website. Using this one-off code you do the 30 to 40 minute test online and this spits out top 5 strengths. Mine are:

  • Learner
  • Activator
  • Analytical
  • Achiever
  • Focus

Once you have the list your then read the 5 Themes and Ideas for Action from the list of 34 themes and actions in the next part of the book. These themes explain how these strengths impact who you are, give some quotes from real world people who share those attributes, and finally some action points that will help you leverage those strengths. There are also a few action points for working with people who have those strengths.

Learner

Your are energized by the steady and deliberate journey from ignorance to competence. Understand how you best learn (me: by doing). Track progress when you're learning and find opportunities to do courses and further yourself.

Activator

You learn more from real experience than from theoretical discussions. Most developers (software engineers) would fall into the activator category as I think that most of us "click" when we do rather than when taught or reading.

Analytical

Prove to me that this is true. "Show me the money." I'm not going to believe your theories until you've demonstrated to me that they have some sound validity. Objective and dispassionate.

Partner with someone with strong Activator talents. This person's impatience will move you more quickly through the analytical phase into the action phase. (This means, I think, that I should partner with myself.)

Achiever

You feel as if every day starts at zero. By the end of the day you must achieve something tangible in order to feel good about yourself. And by "every day" you mean every single day...

I completely agree with this assessment and how it applies to me. I also agree with the statement that the feeling of achievement is short lived and I need to start looking for the next item. In general I agree with the action items and considering the Learner I have to accept that the "attain certifications" item is going to have to now be on my list.

Focus

You stay on the main road and don't wander off down alleys that don't benefit the final goal. You are goal orientated and driven. You must have a purpose and goal to focus on. Include time-lines and measurements in goals.

Friday, September 10, 2010

Linchpin by Seth Godin

Linchpin by Seth GodinI recently finished reading Linchpin by Seth Godin. This is a great read and packed with insight. The full title is Linchpin - Are you Indispensable?

I found the book from reading Seth's blog which I try and read daily but usually catch-up with it on weekends.

The crux of the book is about how some employees are able to do anything. They are the go-to guys who seem to know someone or something that can get the job done and have the talent for making it happening. They are the linchpins.

A lot of the book discusses art and the generosity on non-reciprocal giving. I've read a number of books like this lately and the one example that keeps on coming up is Wikipedia and I have to say that this example has been overdone many times. Perhaps it's still relevant and perhaps it's the largest and best known example of its time but I would like to see some other examples apart from Wikipedia.

Seth is a big fan of shipping and doing so on time. He's right and to get a product to market you have to ship. Don't look for perfection or you will never ship.

Thursday, September 9, 2010

X.CO Url Shortener

Go Daddy have just launched their x.co url shortener which is the shortest url shortener that I have been able to find. If you are doing shortening on your server (as opposed to doing it client side using JavaScript) then here is some C# code that will work on your web server to shorten a url using their API. You will need your API key which can be found here: Integrating x.co with applications you develop.

public class XcoApi
{
    private const string apiKey = "put your API key here";

    public static string ShortenUrl(string longUrl)
    {
        var shortUrl = string.Format(
            "http://x.co/Squeeze.svc/text/{0}?url={1}",
            apiKey, HttpUtility.UrlEncode(longUrl));

        WebClient wc = new WebClient();
        return wc.DownloadString(shortUrl);
    }
}

The main advantage of shortening a URL on the server side instead of the client side is that you can keep your API key hidden and therefore usable only by you.