tsJensen

A quest for software excellence...

“Come What May, And Love It” (and Learn to Laugh)

I remember listening to this wise counsel three years ago from Elder Joseph B. Wirthlin Of the Quorum of the Twelve Apostles. Today my mother reminded me of it and I enjoyed reading it again. If you have ever faced tough times or felt like you were on the losing end of a game, in sport, in work, in life, I hope this article will pick you up.

I would like to highlight one of the points Elder Wirthlin makes, perhaps my favorite:

Learn to laugh – When things go wrong, we can choose to be angry or sad or depressed, but if we choose to laugh, we can get through the present difficulty and more easily find a solution.

“The next time you’re tempted to groan, you might try to laugh instead. It will extend your life and make the lives of all those around you more enjoyable.”

When the stresses of work or a commute or a family crisis threaten to bring you down, laugh. It truly is the best medicine!

C# Basics: Symmetric Encryption with Rijndael

I often need to encrypt a string and then decrypt it. Sometimes its to move some value from one server to another without the benefit of SSL. So for the fifth installment of C# Basics, I’ll share the a generic version of a little encryption utility I’ve used many times and in many places.

Most Important: If you decide to use this code, be sure to change the key and vector text to something only you know. You might even want to use a hardware security module.

I like AES (formerly known as Rijndael, pronounced “rain-doll”) but you can pick your own algorithm. The code below will work with most of the .NET symmetric encryption algorithms.

using System;
using System.Security.Cryptography;
using System.Text;

namespace MyCrypt
{
  public static class Tokenizer
  {
    //create your own unique key and vector strings
    //maybe even lock them up and require a cert to get them out
    private const string keyText = @"The quick brown fox jumps";
    private const string vectorText = @"over the lazy dog.";
    private static byte[] key = null;
    private static byte[] vector = null;

    static Tokenizer()
    {
      key = GetMD5Hash(keyText);
      vector = GetMD5Hash(vectorText);
    }

    public static string Encrypt(string val)
    {
      if (string.IsNullOrWhiteSpace(val)) return null;
      RijndaelManaged rjm = new RijndaelManaged();
      rjm.KeySize = 128;
      rjm.BlockSize = 128;
      rjm.Key = key;
      rjm.IV = vector;
      byte[] input = Encoding.UTF8.GetBytes(val);
      byte[] output = rjm.CreateEncryptor()
        .TransformFinalBlock(input, 0, input.Length);
      string data = Convert.ToBase64String(output);
      return data;
    }

    public static string Decrypt(string val)
    {
      if (string.IsNullOrWhiteSpace(val)) return null;
      try
      {
        RijndaelManaged rjm = new RijndaelManaged();
        rjm.KeySize = 128;
        rjm.BlockSize = 128;
        rjm.Key = key;
        rjm.IV = vector;
        byte[] input = Convert.FromBase64String(val);
        byte[] output = rjm.CreateDecryptor()
          .TransformFinalBlock(input, 0, input.Length);
        string data = Encoding.UTF8.GetString(output);
        return data;
      }
      catch
      {
        return null;
      }
    }

    static byte[] GetMD5Hash(string data)
    {
      MD5 md5 = MD5CryptoServiceProvider.Create();
      return md5.ComputeHash(Encoding.UTF8.GetBytes(data));
    }
  }
}

Keystrokes – Don’t Waste Them

I spend perhaps six hours a day, five days a week, fifty weeks a year hitting the keys. At my slow average typing speed of 30 words per minute (I can type faster but I’m not constantly hitting the keys, so I’m guessing here) and assuming I spend thirty years of my life doing this, my total keystrokes (assuming an average of 6 keystrokes per word) will be:

60 minutes * 6 hours * 5 days * 50 weeks * 30 years * 30 words * 6 keystrokes = 16,200,000 keystrokes

Percentage of my work output firing off an ill conceived email providing advice to someone who does not care or want the advice and will certainly not waste time reading the missive: 0.01%

Today I wasted 0.01% of my available productivity.

I’ve already consumed nearly 50% of my available keystrokes, so I’m posting this to remind myself to conserve my energy and use what remains of my personal utility more wisely.

Important note to self. Do not waste time writing perfectly good advice and sending it to someone who could not care less about your opinion. Instead, read a good book. Write a new blog post. Refactor some old code. Or just watch the leaves in the trees dance in the wind. This would be a more valuable use of that time. Time that cannot ever be recaptured.

C# Basics: If-Else If-Else vs Switch vs Dictionary<K,T> in Dealing with Multiple Choices

In this fourth installment of C# Basics, let’s take a look at how you handle multiple choice questions in your code. When you need to decide on a course of action based on the multiple possible values a variable may have, you have three essential choices.

  1. if | else if … | else
  2. switch
  3. Dictionary<K,T>

The code below shows you an example of each:

public class DownloadViewModel
{
  public Byte[] Contents { get; set; }
  public string FileName { get; set; }

  public string ContentType1
  {
    get
    {
      string ext = Path.GetExtension(FileName).ToLower();
      if (ext == ".pdf")
        return "application/pdf";
      else if (ext == ".txt")
        return "application/txt";
      else  
        return "application/octet-stream";
    }
  }

  public string ContentType2
  {
    get
    {
      switch (Path.GetExtension(FileName).ToLower())
      {
        case ".pdf":
          return "application/pdf";
        case ".txt":
          return "application/txt";
        default:
          return "application/octet-stream";
      }
    }
  }

  public string ContentType3
  {
    get
    {
      if (map.Count == 0) LoadMap();
      string val = string.Empty;
      if (!map.TryGetValue(Path.GetExtension(FileName).ToLower(), out val))
      {
        val = "application/octet-stream";
      }
      return val;
    }
  }

  private void LoadMap()
  {
    map.Add(".pdf", "application/pdf");
    map.Add(".txt", "application/txt");
    map.Add("*.*", "application/octet-stream");
  }

  private Dictionary<string, string> map = new Dictionary<string, string>();
}

So how do you pick which one to use? For me, the choice is easy. If I have only a few possible values that are not likely to change, I’ll use the if|else if|else construct. If I have a fair number (more than 3 and less than 16) and these values are not likely to change, I’ll use the switch statement. But if the values are likely to change or be data driven or if the number of values is greater than 15, I prefer to use a Dictionary.

Another highly valuable use of the Dictionary is when the values will kick off some action that may be lengthy or complicated. In that case, I prefer a Dictionary<T, ActionForT>. I can then retrieve the ActionForT and call the Execute method. Like this:

public class DownloadModel
{
  public Byte[] Contents { get; set; }
  public string FileName { get; set; }

  public string ContentType
  {
    get
    {
      string ext = Path.GetExtension(FileName).ToLower();
      if (ext == ".pdf")
        return "application/pdf";
      else if (ext == ".txt")
        return "application/txt";
      else  
        return "application/octet-stream";
    }
  }

  public void Save()
  {
    if (map.Count == 0) LoadMap();
    Action action = null;
    if (map.TryGetValue(Path.GetExtension(FileName).ToLower(), out action))
    {
      action(); //execute the action stored in our map
    }
    else
    {
      map["*.*"](); //execute the default action
    }
  }

  private void SavePdf()
  {
    throw new NotImplementedException();
  }

  private void SaveTxt()
  {
    throw new NotImplementedException();
  }

  private void SaveOther()
  {
    throw new NotImplementedException();
  }

  private void LoadMap()
  {
    map.Add(".pdf", new Action(SavePdf));
    map.Add(".txt", new Action(SaveTxt));
    map.Add("*.*", new Action(SaveOther));
  }

  private Dictionary<string, Action> map = new Dictionary<string, Action>();
}

Be a Software Development Mentor

I like many aspects of my job but one stands out above all others: helping other developers. Nothing gives me as much satisfaction as hooking up the mental chains and pulling a fellow developer out of the code mud in which she or he is stuck.

I grew up on a small farm where there was never any lack for work to do, much of which was tedious and boring. But it was always exciting to get a call from a neighbor asking us to come pull them out of the mud or jump start a car or rescue an animal from some odd predicament. It never took much time, but the simple gratitude of the person helped was the best compensation I’d ever known as a child.

Now my tractor is my brain and my software tools and the chains are made of thousands of hours of experience forging one experience into another and storing these up, mostly for my own work, but also for those enjoyable moments when I take a call from a colleague who is just stuck and needs a little guidance.

My tractor and chain is not better than anyone else’s really. But sometimes I’m in the right place at the right time to help another developer and this aspect of my job is my favorite. Spinning up a GotoMeeting session and helping another developer find and solve a problem may sound dull and boring to some, but it gives me a boost.

Sometimes my colleagues are reluctant to call. (I work remotely.) Perhaps this is because they don’t want to waste my time or because they feel the need to solve the problem on their own. That’s okay. It’s good to solve problems on your own but I do appreciate the opportunity to help when I can.

And that is one of the main reasons I get up in the morning and make the 30 second commute to my basement office. Today, I might get to hook up the chains to the tractor and pull a friend or a neighbor out of the mud.

Hook up your chains to your tractor and become a software development mentor.

C# Basics: Beware of Catch (Exception e)

In this third installment of C# Basics, let's take a look at exception handling. It is one the easiest things to do poorly in an application. In C# you can capture an error and do something with it as easily as this:

try
{
  //do something that may raise an exception
}
catch (Exception e)
{
  //do something with e--log it, modify a return value, etc.
  //if you want the caller of your code to have a crack at the same exception
  throw; //raise the exception again with throw; (almost NEVER throw e;)
}

But do try your best to NEVER catch the base Exception class. Be more specific, especially where you have to do something specific with a particular type of exception and allows others to rise up the call stack. Here’s just one example of being a bit more specific:

try
{
  //call a service that reads data from SQL Server
}
catch (SqlException se)
{
  if (se.Message.Contains("Timeout"))
  {
    //send a timeout log message to the DBA service
  }
  throw; //raise it up the stack to be handled by the caller
}

Of course, you can and ought to handle different exceptions differently where required. Here’s a brief example:

try
{
  //call a service that reads data from SQL Server
  //call another service that writes to a file
}
catch (SqlException se)
{
  if (se.Message.Contains("Timeout"))
  {
    //send a timeout log message to the DBA service
  }
  throw; //raise it up the stack to be handled by the caller
}
catch (IOException iox)
{
  //special handling or logging of IO exceptions
  Console.WriteLine(iox.Message);
}
catch (Exception e)
{
  //log a general exception and rethrow
  throw;
}

And don’t forget, you can create your own specialized exception classes. In fact, with Visual Studio you can use the code snippet for Exception. Just put your cursor in a C# file, outside of a class declaration, and start typing Exception and when you see the Intellisense prompt just hit TAB TAB. And you will have the following:

[Serializable]
public class MyException : Exception
{
	public MyException() { }
	public MyException(string message) : base(message) { }
	public MyException(string message, Exception inner) : base(message, inner) { }
	protected MyException(
	 System.Runtime.Serialization.SerializationInfo info,
	 System.Runtime.Serialization.StreamingContext context)
		: base(info, context) { }
}

Flesh out your own custom exception and raise and catch it just like a pro.

public void ShowExample(int count)
{
  if (count < 0) throw new MyException("Count cannot be less than zero.");
  // . . .
}

public void CallExample()
{
  try
  {
    ShowExample(-4);
  }
  catch (MyException me)
  {
    Console.WriteLine(me.Message);
  }
}

Of course, in the above example, you would more likely want to just throw a new ArgumentException. There is a very long list of commonly used exception classes in the .NET base class libraries. Spend some time on MSDN and get familiar with them. Here’s a brief but incomplete list of common exception classes you may want to catch or throw and then catch.

  • System.ArgumentException  
  • System.ArgumentNullException  
  • System.ArgumentOutOfRangeException  
  • System.ArithmeticException  
  • System.DivideByZeroException  
  • System.FormatException  
  • System.IndexOutOfRangeException  
  • System.InvalidOperationException  
  • System.IO.IOException  
  • System.IO.DirectoryNotFoundException  
  • System.IO.EndOfStreamException  
  • System.IO.FileLoadException  
  • System.IO.FileNotFoundException  
  • System.IO.PathTooLongException  
  • System.NotImplementedException  
  • System.NotSupportedException  
  • System.NullReferenceException  
  • System.OutOfMemoryException  
  • System.Security.SecurityException  
  • System.Security.VerificationException  
  • System.StackOverflowException  
  • System.Threading.SynchronizationLockException  
  • System.Threading.ThreadAbortException  
  • System.Threading.ThreadStateException  
  • System.TypeInitializationException  
  • System.UnauthorizedAccessException

Small and Simple: The Keys to Enterprise Software Success

Someone once said, “By small and simple things are great things brought to pass.” The context was certainly not enterprise software development but I have come to believe that these words are profound in this context as well.

Every enterprise, medium and large, is challenged with complexity. Their systems and businesses are complex. Their politics and personnel and departments are complex. Their business models and markets and product lines are complex.

And their software is complex. But why?

Because we make it complex. We accept the notion that one application must accomplish all the wants and wishes of the management for whom we work, either because we are afraid to say, “This is a bad idea,” or because we are arrogant enough to think we’re up to the challenge. So we create large teams and build complex, confusing and unmanageable software that eventually fulfills those wants and wishes, sometimes years later—that is, if the project is not cancelled because the same management team loses patience and/or budget to see it through.

Some companies have made a very large business from selling such very large and complex software. They sell it for a very large “enterprise class” price to a business who wants all those nice shiny features but doesn’t want to take the risk of building it for themselves. And then they buy the very large enterprise software system and find that they must spend the next six to twenty months configuring and customizing the software or changing their own business processes and rules to fit the strictures of the software they have purchased.

The most successful enterprise projects I’ve worked on have all shared certain qualities. These projects have produced workable, usable and nearly trouble-free service all because they shared these qualities. The are:

  • A small team consisting of:
    • A senior lead developer or architect
    • Two mid-senior level developers
    • A project manager (part time)
    • And a strong product owner (part time)
  • A short but intense requirements gathering and design period with earnest customer involvement.
  • Regular interaction with product owner with a demo of the software every week.
  • Strong communication and coordination by the project manager, assuring the team and the customer understands all aspects of project status and progress.

The challenge in the enterprise is to find the will and means to take the more successful approach of “small and simple.”

You may say, “Well, that’s all fine and good in some perfect world, but we have real, hard and complex problems to solve with our software.” And that may be true. Software, no matter how good, cannot remove the complexity from the enterprise. But there is, in my opinion, no reason that software should add to it.

The real genius of any enterprise software architect, if she has any genius at all, is to find a way to break down complex business processes and systems into singular application parts that can be built by small, agile teams like I’ve described, and where necessary, to carefully define and control the service and API boundaries between them.

Must a single web application provide every user with every function and feature they might need? No. But we often try for that nirvana and we often fail or take so long to deliver that delivery does not feel like success.

Must a single database contain all the data that the enterprise will need to perform a certain business function or fulfill a specific book of business? No. But we often work toward that goal, ending up with a database that is so complex and so flawed that we cannot hope to maintain or understand it without continuous and never ending vigilance.

When your project complexity grows, your team grows, your communication challenges grow and your requirements become unwieldy and unknowable. When you take on the complex all in one with an army, you cannot sufficiently focus your energy and your strength and collectively you will accomplish less and less with each addition to your team until your project is awash is cost and time overruns, the entire team collectively marching to delivery or cancellation. And in the end either outcome, delivery or cancellation, feels the same.

By small and simple things, great enterprise software can be brought to pass. Sooner rather than later. Delivering solid, workable, maintainable, supportable solutions. Put one small thing together with another, win the war on complexity and provide real value to your management team. Do this again and again and you’ll have a team that will never want another job because they will have become all too familiar with real success.

What’s Wrong with Technical Recruiters

I’ve had a series of ongoing discussions with a friend who is also a senior software architect. In recent months he’s become quite dissatisfied with his manager specifically and employer generally. He has put his resume out on the typical job search sites, Dice, Monster, TheLadders, LinkedIn and others, and has been sorely disappointed with the result. Technical recruiters seem to be, with rare exceptions, a sorry lot of would-be telemarketers rejected for lack of integrity by the local call-center-for-hire.

On a daily basis this friend of mine receives emails and calls with a hot job listing that do not generally match his skills or experience like the one that he forwarded to me today, not because he might really be a match but in hopes of sparking a conversation that goes something like this:

  • Recruiter: “I know you may not be a good fit for this job, but do you know anyone who is?”
  • Candidate: “No. I do not know anyone with this skill set and experience level interested in a 6 month contract.”
  • Recruiter: “Okay. I’d like to keep in touch with you and I will definitely call you if something comes through that is a better match for what you’re looking for.”
  • Candidate: “Okay, sure. Thanks for the call.”

My friend reports that he has at least three of those conversations per week and at least two or three such emails as the one below per day. I’ve changed the company names and the place to avoid the chance of embarrassing any of them, especially since one or two of them is a household brand name.

Hello,

I am Recruiter with XYZConsulting (formerly ABCConsulting), a dedicated QRS contractor sourcing service, managed by TenCharms. We recruit solely for QRS Contract Positions. Should you accept a contract position, it will be through our preferred partner TenCharms, an independent vendor chosen to manage this program for QRS.

I saw your resume on a job board. I am currently recruiting .net Consultant for a 12 months contract project with QRS – Chicago, IL.

Email me a copy of WORD formatted resume, along with these details:

  • Best time & number to speak to you:
  • Location:
  • Visa Status:
  • How soon you can start:
  • Work mode, W2, C2C (if self-incorporated):
  • Expectations on Compensation:

Position’s name: .net Consultant

Assignment period: 12 months
Location: Chicago, IL

Required skills
Primary Skills: asp.net, vb.net, Oracle / SQL Server, SQL. Secondary Skills: C#.net, MS Access / VBA

As this is an urgent requirement, kindly respond to it at earliest possible.

Best Regards,
Bad Excuse (name changed to protect the guilty)

Recruiter | XYZConsulting (formerly ABCConsulting)
A TenCharms Solution
Dedicated QRS Contractor Sourcing Services

My friend has shown me many other emails that are far worse than this one. Many of them are poorly written, lacking proper grammar and teeming with spelling errors, yet they claim to represent well known companies. I wonder if these companies for whom these recruiters work ever bother to review the practices and general quality of the communications of their agents. Somehow I doubt it.

In some of the emails my friend has forwarded to me, it becomes clear that the recruiting company has employed some shoddy keyword matching algorithm to select from a list of candidates who have put their resumes out into the swamp of job sites (see above mentioned sites). In some of these I have been able to identify one or two specific keywords that match my friend’s resume. I should know. I helped him write it.

Sometimes the keyword match is even close, such as, “architect” or “jQuery.” But since my friend is a .NET architect and the job is for a J2EE architect who also knows jQuery and PHP and Oracle while my friend does not mention Oracle or PHP on his resume at all, it is clear that the recruiter’s matching algorithm, whether it is their own or provided by one of the job sites, is severely lacking in even the most basic intelligence.

Either that or the recruiter is far more interested in spamming the candidate with a job posting that is clearly not a fit in hopes that the candidate will do the job of the recruiter for him or her or it.

To all such recruiters, please for the love of Pete, what’s wrong with you? Stop wasting my friend’s time!