A Slave, A King, A Chief

Thoughts on the Words of a Slave, a King, and a Chief

Today I awoke thinking on the unrest in our country on this special day in which we celebrate our independence from the British crown. In catching up with notifications on my phone, as is my habit first thing in the morning, I noticed a post linked to an abridged version of the speech given by Frederick Douglass on the 5th of July, 1852, entitled "What to the Slave is the Fourth of July?"

It was a powerful speech but the professor who abridged it, and did so to promote his next book on how to become an anarchist, cut it down to make it incendiary, so I went to the original and read it in full. I encourage you to do the same (https://rbscp.lib.rochester.edu/2945). After reading the speech, I pondered for a long while the state of our republic. I thought about the word "oppression" and its several forms and how we hear that word often in justification for the violent riots we have seen of late.

Oppression is closely related to abuse. It really is just an organized form of abuse of one group by another. As such, and like it's more personal cousin "abuse," oppression becomes cyclical. Those who rise up against their oppressors are often already oppressors or become such upon their liberation, having learned the habits of their current or former oppressors.

Oppression begets oppression. Violence upon others teaches others to be violent. Some who learn this violence, whether in physical or mental and emotional form, choose to visit it upon their teachers until their former oppressors cower in fear and become the oppressed. Some look for new targets of their rage, enacting revenge upon the innocent. We can find examples of these throughout history. No society of which I'm aware is without such sin. No stone is thrown by pure hands.

I cannot think of a single society that has fought and won its freedom from oppression that has not in some part participated in oppressive acts against others. Mr. Douglass's speech is a grim reminder of this. Recent uprisings, protests, and riots are reminders of this. Lives and livelihoods have been destroyed as those who stand against oppression have enacted their own version against others. An eye for an eye continues even after we are all blinded.

In thinking of all this, I then read the parting words and wisdom of a king who lived in this great land about 2,129 years ago. He hoped that his people would avoid the tragedy of a king who would undoubtedly succumb to the future temptations of power and oppress his people, as has so often been the case since the dawn of time. In this hope, he established the first known form of a representative democracy in this great land. Judges were appointed by the "voice of the people," and a system of checks and balances were established to prevent any one judge from wielding power against the will of the people. (See Mosiah 29 in the Book of Mormon.)

That system ultimately failed. Oppression and persecution persisted between groups who differed by belief, by ideology. Violence and war followed. Sin and corruption destroyed the peace. And so it is in our country and our world today. People who feel oppressed are rising up, committing acts of violence, becoming the thing they profess to hate. Where does it end? Who will lose their eye and choose not to take another's in retaliation? Who will be struck by a stone and choose to leave it on the ground?

It seems to me that even in a country such as the United States where we have so much to be grateful for, we have found ourselves in that revolving door of oppression, hate, envy, and revenge. While the vast majority live their lives in quiet peace, there are groups who continue to oppress and be oppressed. In my search, I have failed to find a single example of any people who conquered their oppressors and then set down all the rocks, whips, and chains with which they were oppressed.

For all the great good the United States has done in the world, we have been plagued by our own sins against a number of groups, some of whom are rising up today. We have also worked to deny, ignore, or exacerbate and allow ideological forces to compound the problems and grievances of those who feel oppressed. Groups, divided by race, religion, ethnicity, education, and economic circumstances, have circled their wagons and given in to the temptation to lash out against others or neglect their needs.

If we examine history carefully, we may conclude that we may free ourselves from tyranny by violence but we cannot end the cycle of societal abuse by the continued use of the tools of oppression. If we cannot bring ourselves to drop the stones in our hands and cross identity group boundaries to love one another, we are doomed to a cycle of violence that will destroy us, just as so many societies have done throughout history.

Who then can end this ideological war? The oppressors or the oppressed? No. None can win. All will lose unless we together find the wisdom and humility to stop fighting, to stop the cycle of abuse. And the only way we have a chance of doing so as a society is if we choose to do so as an individual. I choose to leave the stones on the ground.

I love our dear country, even with it's flaws. It is man's greatest hope of overcoming our natural tendencies to do evil, to harm others in retaliation for pain we suffer, even if only by perception. If you feel aggrieved, if you feel like standing up and fighting oppression with oppression, I invite you to consider the cycle of abuse. You have a choice to end it for you. And that is the only choice you have. To surrender yourself to base instincts and follow the mob is to choose to become the oppressor, to become the thing you profess to hate.

In conclusion, consider these words, spoken by Chief Joseph of the Nez Perce, after what must have seemed like multiple lifetimes of being oppressed and fighting, "I want to have time to look for my children, and see how many of them I can find. Maybe I shall find them among the dead. Hear me, my Chiefs! I am tired; my heart is sick and sad. From where the sun now stands I will fight no more forever."

 

Debug Go in Windows Subsystem for Linux 2

I’m starting a new job in two days writing Go for Linux, so I thought I ought to do a little experimentation with debugging Go in VS Code on Windows Subsystem for Linux. I already had WSL enabled but had not used it much. After a little experimentation on my laptop, I discovered that debugging does not work in WSL (v1) but it does in WSL 2.

After a little experimenting, I got it working on my laptop and determined to do the process again while taking some notes on my desktop machine. This is as much to remind myself as to inform others. If you find it useful, so much the better.

Existing Start Point

I started with a current version of Windows 10 Pro with WSL enabled and Ubuntu installed from the Windows Store. I also had Go installed in Windows but not in WSL. This gives you WSL 1 and the Go Delve debugger will not run remotely via VS Code on WSL 1.

Windows Insider Program

You need a newer version of Windows 10 that comes with WSL 2. For that, you need to join the Windows Insider Program.  Once you do that, you can use Windows Update to install the latest version of the OS, currently build 19041.1.

Enable WSL 2

Now you need to open PowerShell in Administrator mode and follow the instructions here.

You run these two commands to enable WSL 2:

dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

Now if you run

wsl --list 

You should see something like this:

PS > wsl --list
Windows Subsystem for Linux Distributions:
Ubuntu (Default)

Now you need to convert to use WSL 2 rather than 1 which is the default by running the following with the output shown:

wsl --set-version Ubuntu 2

wsl --set-default-version 2

wsl --list --verbose

PS C:\WINDOWS\system32> wsl --list --verbose
  NAME      STATE           VERSION
* Ubuntu    Stopped         2

Windows Terminal

This step is optional but I recommend it. Go to the Windows Store and install the Windows Terminal. It makes switching between WSL bash and PowerShell and Windows cmd prompt very easy. You can learn more about it here.

Update Your Ubuntu WSL 2 Environment

Now open the Ubuntu bash shell and run the following commands to update, upgrade and install golang.

$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install golang-go

Once you have updated and upgraded and installed Go, you can run go version and get go1.10.4, the current Ubuntu default which is not the version you need. This version will not run with the new version of the Delve debugger that the VS Code extension uses. But not worry, upgrading to a new Go is easy.

The above install will put the 1.10.4 version in the /usr/lib/go directory. Do a more VERSION in that directory and you’ll see that I’m right.

Upgrade Go to Latest

Now you need to download and install the latest Go version, currently 1.13.5. Execute the following commands:

wget https://dl.google.com/go/go1.13.5.linux-amd64.tar.gz

sudo tar -xvf go1.13.5.linux-amd64.tar.gz

sudo mv go /usr/local

This will put the new version of Go in a different directory allowing you to revert to the previous installed version if you want. After the files are in place, you need only update your environment Go paths. Open the ~/.bashrc file in your favorite editor. For quick stuff like this I use nano. Now add the following lines at the end of the file:

export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH

Either close your bash shell and open a new one to get the udpated settings or execute source ~/.bashrc to update the current session. Then execute go version and you should see go version go1.13.5 linux/amd64.

VS Code from WSL

Open VS Code from Bash Shell with:

code .

VS Code will open after the shell installs VS Code Server for x64. If you have the Go extension installed already, all you need to do is install it to WSL. Just open the extensions and click on the install button.

InstallGoWSL

A reload of VS Code will be required. In fact, I found that a reload was required or at least needed to get some of the following steps to work properly but that was a minor inconvenience.

Create a new directory called gotest and a file in it called app.go using VS Code. Paste in the code from https://github.com/tylerjensen/d-go-rust/blob/master/Go/Hello/app.go and hit F5 to debug after adding a break point. VS Code will require that you install go-outline and the delve debugger, so just click Install on the pop up notifications.

Now you’re up and running, building and debugging Go in Linux in WSL 2.

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.