I enjoy continually learning from Robert Martin (Uncle Bob). Sometimes I disagree with him but usually only until I’ve thoroughly processed what he is trying to teach me. In his latest missive on 8thlight.com, Uncle Bob writes a stunningly cogent brief called Screaming Architecture in which he makes a critical point: software architecture is all about the use cases of a system and NOT the framework.
“Architectures are not (or should not) be about frameworks. Architectures should not be supplied by frameworks. Frameworks are tools to be used, not architectures to be conformed to. If your architecture is based on frameworks, then it cannot be based on your use cases.”
Focus on the use cases and perhaps even group them into logical hierarchies with tidy “40,000 foot level” epochs that describe the thing you are building. Is it a customer relationship management system? The first thing we should notice in an architecture, whether document or code, is that this is a CRM system. Presentation, delivery, storage and communication frameworks are all secondary, just plumbing, not the architecture.
“A good software architecture allows decisions about frameworks, databases, web-servers, and other environmental issues and tools, to be deferred and delayed.”
I’m not completely at this point in my journey toward architectural perfection but I recognize the need to strive for this idea of producing architectures that are designed to solve the problems of the users first rather than designed fit within the strictures of a framework while addressing the use cases after the fact.
I recommend you read the full article. Take Uncle Bob’s advice, as I intend to do, and focus more strongly on architecture for your use cases on your next project. Use frameworks carefully and work to keep your business code independent of your frameworks and thus imminently more testable. And don’t forget your tests.
I’ve recently been interested in the subject of respect and the question of whether respect is given or earned. My conclusion is that respect is given most often when it is earned and certainly most easily when that is so. In contemplating and researching this subject, I ran across a post by Bret Simmons that I liked very much called 10 Ways to Earn Respect as a Leader in the Workplace.
I recommend you read the full article but I’ll share a few of my favorites here along with some personal thoughts about each one.
Get to know your co-workers and their families.
This is the author’s first point and I think most important one. It is very hard to give respect to someone who has no empathy and does not appear to be genuinely interested in you and your personal circumstances. A little bit of real care can earn a lot of respect.
Communicate clearly and regularly.
If one does not hear from or speak with his manager on a regular basis, it is impossible for the first point to occur. And if a person is left in the dark with respect to what is happening within the organization, an atmosphere of fear and a feeling of neglect can result in poor attitudes and even overt disrespect.
Make generous use of self-deprecating humor.
When I work with someone who refrains from making deprecating remarks about others but has the self confidence to take a jab at himself from time to time in order to put others at ease, I’m more likely to feel comfortable working with that person and will certainly have more respect for him.
Admit when you screw up.
Nothing can destroy the respect you have earned more rapidly than dodging responsibility for your own mistakes. Nothing can more irreversibly damage your own reputation more powerfully than when you throw a subordinate or coworker under the bus rather than owning up and facing the music. At the same time, the opposite is true. If I have a boss who takes responsibility for mistakes made and asks the team for their support as she takes corrective action, I will have just that much more respect for that person.
Stand behind your staff during times of difficulty.
When mistakes are made by subordinates or coworkers, stand by them. Don’t abandon them in an attempt to save yourself. Chances are you will all survive but you will have lost their respect forever. The author writes, “If you can’t stand behind one of your team members, then you don’t belong in management and you’re certainly not a leader.”
In this sixth installment of C# Basics, I want to share a brief snippet of an extension method I’ve found useful that will introduce you to QDD as well. Quick and Dirty Design (QDD) is my name for having multiple tiny console application projects lying around in which I test little code snippets before putting them into something more serious. This is only necessary in projects in which TDD has not been used and no testing framework or tests are available for whatever reason.
But back to extension methods. From MSDN we learn:
“Extension methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. Extension methods are a special kind of static method, but they are called as if they were instance methods on the extended type. For client code written in C# and Visual Basic, there is no apparent difference between calling an extension method and the methods that are actually defined in a type.”
As the MSDN article points out, the most common extension methods you may run into are the LINQ standard query operations. But don’t let that stop you from providing yourself with some very nice little extension methods like this one:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
namespace IOTest
{
class Program
{
static void Main(string[] args)
{
string phone1 = @"8015551212";
string phone2 = @"(8a0d1d)d d5d5d5d-d1d2d1d2";
if (phone1.StripNonNumeric() == phone2.StripNonNumeric())
Console.WriteLine("true");
else
Console.WriteLine("false");
Console.ReadLine();
}
}
static class Ext
{
private static Regex nonNum = new Regex(@"[^0-9]");
public static string StripNonNumeric(this string item)
{
return nonNum.Replace(item, string.Empty);
}
}
}
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!
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));
}
}
}
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.
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.
- if | else if … | else
- switch
- 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>();
}
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.