Random Thoughts on Programming Languages

I noted with interest that Microsoft is delving into Rust for some things in the OS where they have memory related security holes. 

We seem to need a language for each of the following:

  • OS
  • Desktop GUI
  • Web front end
  • Web back end
  • Services (web backend without a front end)
  • Data querying 
  • Systems (data serving, near the metal)
  • CLI utils to listen to the GUI or the anti-GUI user or the scripters
  • Script for the scripters

C and C++ remain relevant for the OS but Rust seems to be scratching at the surface.

Javascript rules the browser (written in C++) but WebAssemby (also written in C++) is scratching at the door and will bring many languages to play there once WA has cut ties with JS interop dependency for DOM and HTTP coms.

The web backend and services is a mess of nearly every language on the planet. From JS to Ruby (wretch). Even here JS dominates with Node. The rest of the field is up for grabs.

Data querying is still SQL followed my a mishmash of things for querying noSQL datastores, usually some form of JSON over REST, though binary serialization in gRPC is growing for both data and services.

Systems are still primarily C and C++ but Java and C# play some Part in some database platforms. Go, Rust and others are also knocking on the door. Kubernetes is a good Go example, a tech that is red hot right now.

The CLI world is a free for all. Python is fast becoming a favorite for the automation and ML scripters. This category does seem to favor interpreted over compiled but even that is a pile of chaos and debate.

One thing is certain. There is only one master language in all of computing. Heaven help us. It's English. And there is no consistent compiler, interpreter or IDE for the foul thing.

OOP in D, Go and Rust

Caveat Emptor: I am no expert in any of these languages. DO NOT read this post and assume any such thing.

Picking up where I left off with Hello World in D, Go and Rust in VS Code, this post restarts the thread of my personal learning and exploration of these three programming languages:

Of these three, only D is really an OOP language, but I wanted to see how close I could get in Go and Rust. I started with D and then morphed and adapted as I moved to Go and finally to Rust. The code in this experiment is overly simplistic and meant only to explore basic OOP principles. Nothing in this code is meant to demonstrate best practices in any of these languages.

Update All

First things first. Like my blog, the system on which I wrote the previously noted post has been neglected these past few months. I updated VS Code from June 2019 v1.26.1 to October 2019 v1.40.2. I had Auto Update enabled, so my extensions were updated as well: DLang to v 1.16.7, Go to 0.11.9, and Rust (rls) to 0.7.0.

Next I updated my language environments by downloading and installing the latest releases for Windows:

*dirty: Yeah, I wondered about that too. Apparently it is an artifact of their build system after moving to GitHub. Nothing to worry about. Probably.

The D installer did ask for some VC runtime redistributables or and install of Visual Studio. I already had Visual Studio 2019 installed but would later remember that it had been uninstalled and I had not installed the VC++ dev options. This left no VC redistributables on my machine apparently, as I would soon learn when trying to use the Rust compiler.

dlangvcmingw

Validate Prior Code

The D and Go compilers worked with the prior post’s Hello World code just fine. The Rust compiler complained like this:

PS D:\langc\rust\Hello> rustc app.rs
error: linker `link.exe` not found
   | = note: The system cannot find the file specified. (os error 2) note: the msvc targets depend on the msvc linker but `link.exe` was not found note: please ensure that VS 2013, VS 2015, VS 2017 or VS 2019 was installed with the Visual C++ option error: aborting due to previous error

This was easily resolved by closing VS Code, opening Visual Studio Installer, and adding Desktop development with C++ in Workloads. Opened VS Code again and ran rustc app.rs and the problem was solved.

The app.exe grew by a few bytes for D and Rust but shrunk just a little for Go. I’m not certain why but I thought that was interesting.

Code in GitHub

Rather than listing out all the code in this post, I put the old Hello World code and the new code for this post into https://github.com/tylerjensen/d-go-rust which should make it easier for you to see the effort as a whole. There is nothing special about this repo. It’s just a learning playground and definitely does not purport to be a demonstration of proper practices in any language, let alone best. So reader beware!

Object Oriented Programming

There is no shortage of opinions available on the web as to what constitutes “Object Oriented Programming” but there are certainly some comment themes. Here are the few principles that I selected to use in my attempt to build and compare some OOP code in D, Go and Rust. This is not a comprehensive list and definitely not an attempt to authoritatively define OOP.

  • Objects / Classes — data structures and methods (or functions)
  • Encapsulation — data and logic protection (private vs. public)
  • Composition — support for “has a” relationships
  • Inheritance — support for “is a” relationships
  • Polymorphism — an object that “is a” thing can be used as a thing
  • Open Recursion — a thing can call itself and access its data (this or self)

There may be many other elements of OOP and some of them may be important to you, but for now, let’s see if we can limit it to the scope defined in the bullets above, at least for this foray into learning three new languages.

General Approach

To keep things simple, I’m limiting each effort to one or just a few files. Implementation of methods/functions are simplistic console outputs. Only one complexity was added because I wanted to see how each language deals with date and time. As simple as date/time may seem to humans, it’s another thing entirely to a computer and each language has its own way of dealing with the variety of RFC standards for date/time data.

Another effort I’ve made to keep this simple is that each example is built as a simple console application. No libraries built. No HTTP listener. No windows. No command line arguments. No real architectural organization or realistic naming or code documentation. This is an effort to learn the basics of the languages rather than their best practices. I’ll leave that to the experts in each language.

I’ve tried to write the same code in each language. Mostly. There are differences, especially with the Rust code. The Rust compiler is rather opinionated and to eliminate warnings, I’ve complied with its suggestions.

Here’s the list items I’ve tried to create in each code base:

  • Interface Printable with Print method
  • Abstract class Person that implements Printable interface
  • Demographics class that has a DOB date and encapsulates age behind a GetAge method
  • An Employee class that inherits from Person and composes a Demographics instance
  • An overridden Print method in the Employee class
  • Overloaded methods that take a Person, Employee and Printable as an argument to examine polymorphism

OOP in D

I chose to start in D because it really is an OOP language where Go and Rust, technically speaking, are not. This would give me a simpler entry point into building some code that looks like the kind of OOP that I’m used to seeing in C#. This would allow me to cover most of the elements of OOP that I wanted to explore.

The D code is split into three files, each defining a “module” because within a given module, all private and public class members are accessible to all others. This means that to ensure encapsulation, you have to use separate modules which are defined by the module keyword and follow the convention that the module name is the same as the file name.

I’m not going to show all the code here, but here’s the “per” module which has the interface, abstract class, and the composable class defined. It’s not all that different from my C-based languages including my favorite C#.

module per;

import std.stdio;
import std.datetime;

public interface Printable 
{
  void Print();
} 

public abstract class Person : Printable
{
  public void Print() 
  { 
    writeln("Person printed.");
  }
  public string Name;
}

public class Demographics
{
  private int age;
  public Date DateOfBirth;

  this(Date dob)
  {
    DateOfBirth = dob;
  }

  public int GetAge()
  {
    SysTime today = Clock.currTime;
    
    // Example of open recursion - 'this'
    this.age = today.year - DateOfBirth.year;
    
    return age;
  }
}

The rest of the code can be found here: https://github.com/tylerjensen/d-go-rust/tree/master/D/oop

It’s rather self explanatory for anyone familiar with C-based languages. I won’t spend much time explaining the code. My lazy approach to looking at overloading and polymorphism can be found in the app.d file in the poly methods.

OOP in Go

The first thing an OOP developer runs into with Go is that it has no concept of a class. Rather data defined in a “struct” and those structs can have functions added to them outside the scope of the struct using what Go calls a “receiver” meaning that the function extends the struct with behavior. Encapsulation is easy. A struct member that begins with a capital letter is public. A lowercase letter is private. But similar to D, unless that struct lives in a separate package, the private member is accessible. Unlike D, a package must be in it’s own directory, so you will find the per.go and emp.go files in their own subdirectories.

Go does have a concept of an interface but it does have have an explicit declaration of an object implementing that interface. There are some advantages to this and if you assign a pointer of an instance of a struct to an interface variable and your struct does not implement receiver functions that comply with the interface, the compiler will spit that back out at you.

Here’s the same code as shared above for D. The per.go file is fairly easy to read. In fact, I quite like Go’s readability.

package per

import (
  "fmt"
  "time"
)

type Printable interface {
  Print()
}

type Person struct {
  Name string
}

func (p Person) Print() {
  fmt.Printf("Person printed.\n")
}

type Demographics struct {
  age         int
  DateOfBirth time.Time
}

func (d Demographics) GetAge() int {
  t := time.Now()
  d.age = t.Year() - d.DateOfBirth.Year()
  return d.age
}

And honestly, I’m not missing those semi-colons.

As you peruse the code https://github.com/tylerjensen/d-go-rust/tree/master/Go/oop, you will see that in app.go that Go does not support overloaded functions (methods), unless they are receiver functions for different types but that’s outside the scope of this post. It does allow you to declare a variable of type interface and then assign it a pointer to a struct variable that implements that interface in receiver functions.

OOP in Rust

Of all three languages, I had more trouble with Rust. It’s paradigms are more foreign to my C# mind, but that’s okay. In most respects, it is very similar to Go but has no garbage collector and relies on a lighter, faster approach called ownership and borrowing. I’m not sure if we call that OB or BO. Either way it is a constraint that does make you think more about resource usage and what you’re doing with your data structures.

Rust does support a concept of an interface but they call it a trait. Encapsulation was easier but I ran into trouble thinking I needed to do something similar to Go’s packages using Rust modules (“mod” keyword). I could not get the trait defined in one module and used in another. I did find some documentation and feature requests that indicate that this is not supported. So I dropped back to a single file and one module.

Here’s a partial listing of app.rs found here https://github.com/tylerjensen/d-go-rust/blob/master/Rust/oop/app.rs 

pub trait Printable {
  fn print(&self);
}

pub struct Person {
  pub name: String
}

impl Printable for Person {
  fn print(&self) {
    println!("Person Print {}", self.name);
  }
}

pub struct Demographics {
  // Cannot make this private and not require initialization 
  age: i32,
  pub date_of_birth: chrono::DateTime<chrono::offset::Utc>
}

impl Demographics {
  pub fn calc_age(self: &mut Self) -> i32 {
    self.age = Utc::now().year() - self.date_of_birth.year();
    return self.age;
  }
}

You can see that Rust does have explicit implementation for a trait (interface) and that you must pass a reference of the struct to a function of an “impl” code block for a given struct. This is definitely different than Go. But if you look carefully, you’ll see that if the implementation is going to change data in the struct, you must pass “self” as a mutable pointer. This means that calling the “calc_age” function can only be done by an instance that is declared at mutable using the “mut” keyword. If you mess up on this, the compiler will let you know.

Conclusion

I don’t know what’s next but I’m having fun. I don’t think I will continue to try to push Go and Rust into the OOP hole. They have strengths that are worth exploring without being constrained by an approach the languages were not designed to support. Exploring and learning their best practices could be fun.

Each language has its strengths and quirks. Go is certainly more popular and Rust is growing. The D language remains rather small in terms of market penetration and is nurtured by a smaller group of very dedicated computer scientists. I do not know if it will survive. Go and Rust definitely will as their communities are much larger.

More fun to come. Stay tuned.

Reference Architectures for Cloud Computing

AWS Architecture and Azure Architecture sites provide a variety of resources for architects including reference architectures. With AWS you get a brief one page PDF diagram for each scenario. With Azure you get a more in-depth documentation style following the infographic. Here are two examples. The first is an AWS financial services grid computing architecture.

image

The second here is an Azure machine learning architecture.

image

The reference architectures and additional architectural helps provided by your cloud provider can be very valuable.

And here's the BUT.

But you should not simply copy and paste. Use these guidelines to provide you with ideas and help you to think of things that you are missing in your own cloud architecture solutions. Take the good ideas and use a skeptical eye to pick and choose what works best for your organization's use cases.

Think of it as if you're building a car. Do you look at how other cars are built? Or do you put on blinders and make the same mistakes as everyone else had to make before you came along?

Wrapping Up and Moving On

I've been laid off and the reasons don't matter. It's just business. My last official day is tomorrow. My soon-to-be former employer has a product that enterprises need and good people to back it up. Happily the future is bright and there are opportunities in the world of technology for the taking.

I'm excited for the future and know that soon I'll be doing something new, interesting and challenging. The friends and colleagues I leave behind will do well in the technology economy no matter where they go.

It's a prosperous time to live if you have valued technical skills. I'm grateful for all of the experience I've had that has brought me to this point. I look forward to utilizing it to help other organizations solve their technology problems and advance their organizational goals.

I believe that whatever changes the future holds, I will continue to blog from time to time and work on my personal OSS projects. Stay tuned.

Hello World in D, Go and Rust in VS Code

A few days ago a friend asked me what languages I’m learning. I told him I had been rather lazy of late and was not currently studying any new languages in my programming repertoire. So he said something like this:

每天早上刷牙后研究一种新语言。
Měitiān zǎoshang shuāyá hòu yánjiū yī zhǒng xīn yǔyán.

When I told him I had no idea what he just said, he laughed and explained that he is learning Mandarin and had just told me, “Study a new language after you brush your teeth every morning.” To be honest, I pulled the above Mandarin from Google Translate because I had no way to remember exactly how he had said what he said. But he had successfully goaded me into getting back on the polyglot track. We talked about Rust and Go and D. I’ve played with D some years ago, but have never done anything real with Rust, Go or D.

Here’s Part 1 of my journey through these three languages. The Hello World with a tiny input twist looks like this:

image

I decided to get each of them working in Visual Studio Code. I’m a Windows user, so if you’re on a Mac or using Linux, your mileage will vary. Hopefully what I’ve found here will help you get a start on one or all of these languages as well.

Visual Studio Code

First things first. If you don’t already have it installed, follow the link in the header above and get and install it. It’s simple so I won’t walk you through it here. My first love is the big old fashioned Visual Studio and I’ll continue using it for most of my work, but I wanted to learn more about VS Code as I learn more about these three programming languages. Here’s the version I’m using:

image

Of course you can use your own favorite editor. We’re not going to use any special integrations in VS Code for the Hello World examples here.

Hello in DLang

You can get a pretty good history of DLang here. There are three compilers that support D. In this post, we will only use the DMD compiler, the reference compiler for the language. Download and install DMD. Once installed, open a new console and enter the command DMD. You should get something like this:

[path]>dmd 

DMD32 D Compiler v2.086.0
Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved written by Walter Bright

Once you have the compiler installed, install the DLang VS Code extension for D. (There are several. After some experimentation, I found that I liked this one the best but this is by no means a comparison of them, so I’m not mentioning the ones I decided not to use.)

I created the following Hello World in app.d and ran the DMD app.d command in the terminal window in VS Code.

import std.stdio;

void main()
{
	string name;
	write("Hello, what's your name? ");
	readf("%s\n", &name);
	writeln("Hello, ", name);
}

The app.exe produced was 312KB in file size. At run time, it consumed 1,728KB.

Hello in GoLang

I downloaded and installed Go and then the Go VS Code extension. The extension is built by Microsoft, so I expected the VS Code experience to be superior to the other two languages. I was right. This included the automatic suggestion to install several additional Go related extensions which I did.

I was able to run the following code through the debugger, but rather than get into debugging these languages for this post, I wanted to focus on building an executable that would be as close to the same modified Hello World as I could get.

package main

import "fmt"

func main() {
	var name string
	fmt.Printf("Hello, what's your name? ")
	fmt.Scanf("%s\n", &name)
	fmt.Printf("Hello, %s\n", name)
}

The command line to build the executable was a little more tricky but not bad. There are many sites that can help you here. The command go build -o app.exe app.go produced an app.exe that 2,164KB file size but only consumed 1,424KB at runtime. That surprised me a bit. I expect that Go is packing in a whole lot of things into the executable that my little code base is not using.

Hello in Rust-Lang

Next I downloaded and installed Rust for Windows and then added the Rust(rls) VS Code extension. When I first tried to compile this bit of code, I got an error error[E0601]: `main` function not found in crate `app` which seemed odd since there was definitely a main function. After closing and starting VS Code again, the rustc app.rs command line compiled the executable just fine. Perhaps a path had not been picked up.

use std::io;

fn main() {
	let mut name = String::new();
	println!("Hello, what's your name? ");
	io::stdin().read_line(&mut name).expect("Failed to read line.");
	println!("Hello, {}", name);
}

The Rust compiler wins the size competition with an executable coming in at on 154KB for a file size and only 324KB at runtime. Call me impressed.

Video Tutorials

If you like to learn by watching, here are three fairly good YouTube tutorials that I’ve found. There are many more of course. I’m not saying these are the best, but I liked them. I will return to them a few more times as I continue to learn each of these languages.

What’s Next

Most programming language documentation will take you on a journey of variables, control flow, etc. I figure you can read those on your own. Google works just as well for you as it does for me. So next I want to explore the following. Hold me to it.

  1. How to write object oriented code
  2. How to write SOLID code
  3. How to write a RESTful service client and server
  4. How to write scalable code (threading, message passing, etc.)

That seems like a fair number of things to explore. There are a multitude of others that may emerge as I walk down these three learning paths.

Update

In preparation for more on this language exploration, I have create a GitHub repo here.

HttpContext and Logging to Elasticsearch on a Background Thread

“HttpContext is not thread-safe. Reading or writing properties of the HttpContext outside of processing a request can result in a NullReferenceException.” (from docs.microsoft.com)

image

I am a big fan of Elasticsearch (ELK) logging and have built this into the Ioka.Services.Foundation using the Serilog libary, my current favorite .NET Core logging library. There are many ways to approach this and my intent is not to explore those but to show one way of taking on the task of logging in a background thread while preserving some request context detail in your log.

Following the recommendation on the above docs page, we copy the elements of the HttpContext that we need for our background thread logging using the LogContextFactory. Here’s a snippet of that code. For your scenario, you’ll want to modify what values you wish to preserve and you may wish to remove the fairly heavy duty user agent parser if you don’t care about seeing user agent data broken down in the log message.

public static LogContext Create(HttpContext context)
{
   return CreateFactory(() => context)();
}

public static Func CreateFactory(Func httpContextFactory)
{
   if (null == httpContextFactory) throw new ArgumentNullException(nameof(httpContextFactory));
   return new Func(() =>
   {
      try
      {
         var httpCtx = httpContextFactory();
         var httpRequestFeature = httpCtx.Request.HttpContext.Features.Get();
         var context = new LogContext();
         context["_ThreadId"] = Environment.CurrentManagedThreadId.ToString(); 
         context["_Source"] = Assembly.GetEntryAssembly().GetName().Name;
         context["_IpAddress"] = httpCtx.Connection.RemoteIpAddress.ToString();
         context["_UserId"] = httpCtx.Request.Headers["APPUID"].Count > 0 
            ? httpCtx.Request.Headers["APPUID"][0] 
            : context["_UserId"];
         context["_HttpMethod"] = httpCtx.Request.Method;

In the controller we call the Create method to get a copy of what we need to pass into the background thread async method called DoMathWithLogging (cheesy name for demo purposes only) like this:

public async Task<ActionResult<IEnumerable<string>>> Get()
{
    var msg1 = "Another message";
    var msg3 = new CustomError { Name = "Second", Message = "Second other message" };
    _logger.Debug("This is a debug message. {msg1}, {@msg3}", msg1, msg3);

    var logContext = LogContextFactory.Create(this.HttpContext);
    var result = await _mathDemoProvider.DoMathWithLogging(logContext, _logger);

    return new string[] 
    {
        logContext["_UserId"],
        logContext["_RequestId"],
        result.ToString()
    };
}

Now in the DoMathWithLogging method, we use the ILog interface With method to pass the LogContext object into the logger to preserve what we have copied from HttpContext to the LogContext object.

public async Task<long> DoMathWithLogging(LogContext logContext, ILog logger)
{
    long x = 0;
    try
    {
        var rand = new Random();
        for (int i = 0; i < 10; i++)
        {
            x = 1000 * (long)rand.NextDouble();
            Thread.Sleep(10);
        }
        Thread.Sleep(100);
        var c = 0;
        x = 77 / c;
    }
    catch (Exception e)
    {
        //uses new logger with saved context as this 
        //is not on the request background thread
        logger.With(logContext).Error(e, "Error: value of {LargeValue}", x);
    }
    return x;
}

Note that in our demo code, we deliberately throw a divide by zero error and log it. And now in the implementation of the With method looks like this, capturing the current thread in the “_ThreadId-With” property on the context.

public ILog With(LogContext context)
{
    context["_ThreadId-With"] = Environment.CurrentManagedThreadId.ToString();
    var list = _enrichers.Where(x => x.GetType() != typeof(LogEnricher)).ToList();
    list.Insert(0, new LogEnricher(context, null));
    return new Log(_config, _level, () => _index, _failureSink, _failureCallback, list.ToArray());
}

In the With method, we insert a new log enricher for the Serilog logger. This allows us to capture the copied context values in the log messages, such as the Error logged like this:

{
  "_index": "test",
  "_type": "logevent",
  "_id": "JAdXF2oB9fWPG6gy8H_9",
  "_version": 1,
  "_score": null,
  "_source": {
    "@timestamp": "2019-04-13T15:36:40.2296224+00:00",
    "level": "Error",
    "messageTemplate": "Error: value of {LargeValue}",
    "message": "Error: value of 0",
    "exception": {
      "Depth": 0,
      "ClassName": "",
      "Message": "Attempted to divide by zero.",
      "Source": "Ioka.Services.Demo",
      "StackTraceString": "   at Ioka.Services.Demo.Providers.MathLoggingDemoProvider.DoMathWithLogging(LogContext logContext, ILog logger) in D:\\Code\\Github\\Ioka.Services.Foundation\\src\\Ioka.Services.Demo\\Providers\\MathLoggingDemoProvider.cs:line 30",
      "RemoteStackTraceString": "",
      "RemoteStackIndex": -1,
      "HResult": -2147352558,
      "HelpURL": null
    },
    "fields": {
      "LargeValue": 0,
      "_UserId": "root",
      "_IpAddress": "::ffff:172.18.0.1",
      "_Source": "Ioka.Services.Demo",
      "_MachineName": "6cf7fdb5f3cf",
      "_ThreadId": "14",
      "_HttpMethod": "GET",
      "_RequestId": "50d32de9-df69-4aee-ae48-075f22b8ac2d",
      "_Url": "https://localhost:44370/api/Values",
      "_Query": "Microsoft.AspNetCore.Http.Internal.QueryCollection",
      "_WebUser": null,
      "_Browser": "Chrome 73.0.3683 Windows 10",
      "_Header_Connection": "keep-alive",
      "_Header_Accept": "text/plain",
      "_Header_Accept-Encoding": "gzip, deflate, br",
      "_Header_Accept-Language": "en-US,en;q=0.9",
      "_Header_Host": "localhost:44370",
      "_Header_Referer": "https://localhost:44370/api-docs/index.html",
      "_Header_User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36",
      "_ThreadId-With": "14"
    }
  },
  "fields": {
    "@timestamp": [
      "2019-04-13T15:36:40.229Z"
    ]
  },
  "sort": [
    1555169800229
  ]
}

Note the "_ThreadId-With" property above has the same vs!he as the request thread is. This is because not all async methods will run on a background thread. In previous versions of this code, I forced a long running task to spin up on another thread to verify this. Generally I would not recommend that in practice.

Also note the "_RequestId" property which would allow you to filter in Kibana for all entries with that value in order to trace all log entries for a given request. This can be a very useful tool when you're trying to figure out what happened.

This is the first of many upcoming posts on the code and use of the Ioka.Services.Foundation. The code base is not intended for production use but to provide a guide when you create your own internal libraries to spin up a set of .NET Core microservices that have a common set of fundamental elements that will make working on them, supporting them and using them easier.

How Photography Helps Me Be a Better Software Architect


arizonahighways

I want to share with you how my efforts to perfect my semi-commercial hobby of photography help me be a better software architect.

My first camera was a Kodak Pony 135. I had no idea what I was doing, but I learned a lot by experimenting with that camera. My first computer was a Commodore 64. I was only slightly more informed about computing, having learned BASIC on a Commodore PET over two years prior. Again through experimentation and reading every Creative Computing magazine that I could get my hands on, I learned much more about computing and programming.

So now you know that I've been doing photography and computing for longer than many of my colleagues in this business have been alive. Let's see if my insights are of any use to you.

Patterns in Composition

In photography one must always be aware of the composition of the shot. How do the elements of the shot work together to draw the eye to the subject, to the story you want to tell? Learning the rule of thirds can be quite useful in understanding that, as in photography, so too in software we must look for patterns of composition to focus the user experience on the desired outcome. These patterns are often not visible to the untrained eye, just as in photography our audience may not really know why they like the photo, but they do. Software users will know they love or hate the software, but only you will know they love it because you composed it using patterns that make the magic happen.

Following a Process

We rarely get something right the very first time we try it. We're more likely to get something right when we follow a process that has led to success in the past. In photography I have learned that I must follow a process of preparation, analysis, exploration, decision taking and execution. A well thought out process in software development is equally crucial to success.

Breaking the Rules Sometimes

Once you know the rules of your process and craft, you can begin to take some risks in breaking the rules to achieve a desired effect. Only after understanding the rule of thirds in photography and knowing how and why this rule will help you compose your shot in a way that will present your subject well can you begin to experiment with breaking that rule to tell a slightly different story. The same is true in software architecture. Knowing how the rules of SOLID and design patterns will help you achieve the best outcome is crucial. Only then can you begin to experiment with small deviations to the rules to find new an innovative ways to achieve your goals.

Knowing Your Subject

In photography one must know something about the subject of the photograph. The more you know about the subject, whether this is a person, a landscape, a flower or a bug, the better you will understand how to draw out the character of your subject in your photograph. Being a software architect means knowing your subject, your users, stakeholders, the data and systems and the processes needed to make things work. The more you know about that, the better your architecture and design will be and the happier your customer will be.

Best Tools Don't Always Make the Best Work

Some photographers believe they must have the best, most expensive equipment to achieve the greatest possible result. This just is not true. I once shot with a full frame camera and now shoot with a Micro Four Thirds. Some day I'll move to medium format for other reasons, so don't discount having great tools, but don't assume that without the best you cannot produce great work. The same is true in software. We do not always need the best IDE or the most powerful laptop or the biggest amount of RAM to achieve the best result. Indeed if one focuses only on the tools, one might overlook the fact that one's work is to produce something great with the tools you have. Focus on the finished product and whine less about the tools you have been given.

Always Something Beyond Your Control

In photography you cannot control the weather or an unruly portrait subject. You cannot decide when your SD card will fail. You cannot guarantee that every shot will be perfect. There are always elements of the work that are out of your control. To succeed one must embrace the unknown and unexpected. In software architecture this is also true. There are many aspects of a project which you will have the ability to control. Time and business demands are not among them. Resource availability or team skills are not always within your control. You must learn to embrace the things that are not under your control and work as well as you're able to achieve your goals in spite of these.

Try Again Tomorrow

When I'm shooting landscapes, I often think that I've nailed it only to learn in post processing my RAW images that I failed to capture what it was I thought that I had seen when I was in the moment. These failures fall to the digital cutting room floor and push me to go back out and try again. There is a reason we have iterative processes in software development. We don't always get it right. We must continue to hone our craft and work and rework until we do get it right. Even then there is always more we can do. Sometimes the most important aspect of courage is simply to say to oneself, "I'll try again tomorrow." (Taken from a favorite saying borrowed from a friend of mine who passed away recently.)

People and Love Are The Most Important Ingredients

In photography and software architecture and development, I have learned that the most important aspect and ingredient to success is people. The people we work with will come from many different backgrounds. They will have different needs and desires. We must learn to love them and work with them. Only when we do this can we achieve our greatest success because our success depends on their success. When you love the people with whom you work, you will want to see them succeed. You will be kind but honest. You will be patient but urge them to do their best work. You will put their needs ahead of your own. Miraculously you will produce your very best work and so will they.

How System.Net.Http 4.3.0 Ruined Everyone's Day

I have not updated the MessageWire library for about a year now. But it still works just fine. Mostly. New Year's resolution #1: Update MessageWire.

trustme

Dependency Hell

I'm cleverly using MessageWire to create a customized shared session service for a hybrid set of web applications that include old ASP.NET Web Forms running in .NET Framework 4.6.1 and newer, upcoming, web sites built on ASP.NET Core 2.0. So first it had to work with the older Web Forms site. And it did work. Very well. I'll share some of that fun code on another day in another post.

What did not go well is that my Web Forms site using a library that uses HttpClient in System.Net.Http to call an internal web service suddenly failed.

Here's the HTTP request before pulling MessageWire into the project.

POST http://localhost:53739/api/ProfileDetail HTTP/1.1
Accept: application/json
Content-Type: application/json; charset=utf-8
Host: localhost:53739
Content-Length: 592

{"Id": "…removed actual data…"}

And here's the same request after pulling MessageWire into the project with no other code changes.

POST http://localhost:53739/api/ProfileDetail HTTP/1.1
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Accept: application/json
Accept-Encoding: gzip, deflate
Host: localhost:53739
 
250
{"Id": "…removed actual data…"}
0

See the problem? Yikes, my web service was unable to deserialize the second request created with HttpClient v4.3.0, so of course, that led to a huge failure.

Everyone's Worst Nightmare

What's worst about this is that I did not know about this side effect and this code made it into production causing a nightmare during a critical moment of the day and the month. Of course we rolled it back to stop the bleeding, but damage was done and folks were not happy with me in the least. It took me the rest of the day to find the symptoms of the cause which precipitated the failure.

The fact that it took me so long felt like another failure. Even with the final discovery that the HTTP request was borked, I was clueless as to its exact cause. I even engaged several team members to pour through my code to find the problem with the code I had committed. They could not find it.

So today, with less pressure on, I began methodically thinking of it and tracing back the code that generates the HTTP request. Ultimately it came down to HttpClient in System.Net.Http. This led me to discover that pulling in MessageWire into my ASP.NET Web Forms application on .NET Framework 4.6.1 also pulled in the flawed System.Net.Http version 4.3.0 package.

Light bulb moment! Check for updates. Sure enough, there was a System.Net.Http 4.3.3 available. And boom goes the dynamite! The request was back to looking normal and working just fine with the service being called.

MS OSS Buyer Beware!

When you pull in any new NuGet package which brings with it some dependencies, be sure you check out any updates to those dependencies. Shocking as it may seem, even Microsoft's packages can contain nasty little bugs. And test your assumptions.