The Daily Parker

Politics, Weather, Photography, and the Dog

E is for Encapsulation

Blogging A to ZWelcome to day 5 of the Blogging A-to-Z challenge.

In object-oriented design, we talk about a number of basic concepts that make code easier for humans to read and maintain. Encapsulation is fundamental, by hiding the internal data of a class so that only the class can use it. To access data within the class, you can't just reach in and grab it; you need to use the public properties and methods of the class.

Here's a stupid class:

#region Copyright ©2018 Inner Drive Technology

using System;
using System.Collections.Generic;


namespace InnerDrive.DailyParkerAtoZ.WeekOne
	public class Encapsulation
		public string Name { get; private set; }

		public void ChangeName(string newName)
			if (string.IsNullOrWhiteSpace(newName))
				throw new ArgumentException("Name must have a value", nameof(newName));
			Name = newName;

		internal void Clear()
			Name = string.Empty;

		public IEnumerable<string> NameList => new List<string>(_names);

		private readonly List<string> _names = new List<string>();

Seriously, this is dumb. But it demonstrates some of the ways C# encapsulates data.

Line 12 creates a property called Name that any code anywhere can call, because it's public. But it also declares a setter method that is private, meaning only the Encapsulation class itself can set the value of Name.

Lines 14-22 show how this works. The ChangeName method first makes sure you are giving it a real value, then changes Name and adds the new name to a list of names that is itself private. So the only way to change Name is to use the ChangeName method. (There's another way to do this in the property setter, but I wanted to show how this works exactly.)

Lines 24-27 provide you a way of clearing Name, but the method is marked internal. That means only classes in the same assembly can use this method, which has consequences for our unit tests, below.

Line 29 does a nifty trick where, instead of actually giving outside code access to its private list of _names (line 31), it creates a copy of the list and sends that out. Otherwise, anyone would be able to change the contents of _names just by using the NameList property.

Now here's the unit test code:

#region Copyright ©2018 Inner Drive Technology

using System.Linq;
using InnerDrive.DailyParkerAtoZ.WeekOne;
using Microsoft.VisualStudio.TestTools.UnitTesting;


namespace InnerDrive.DailyParkerAtoZ.UnitTests
	public class EncapsulationTests
		public void CanSetNameOfObject()
			var thing = new Encapsulation();
			//thing.Name = "This won't compile";
			//thing._names.Add("This won't compile either");
			Assert.AreEqual("Ernie", thing.Name);
			Assert.AreEqual(1, thing.NameList.Count());

		public void CanClearNames()
			var thing = new Encapsulation();
			Assert.AreEqual("Ernie", thing.Name);
			Assert.AreEqual(1, thing.NameList.Count());

			// thing.Clear(); // oops—won't compile!

			// Assertions fail!
			Assert.AreEqual(1, thing.NameList.Count());

The comments explain what's going on.

So how can we test the Encapsulation.Clear() method? By adding this line to the InnerDrive.DailyParkerAtoZ.WeekOne.AssemblyInfo.cs file:

[assembly: InternalsVisibleTo("InnerDrive.DailyParkerAtoZ.UnitTests")]

Now all of the objects, properties, and methods in the WeekOne assembly marked internal are visible to the unit test class, and the tests pass.

Cool, right?

As always, the growing Visual Studio solution is here. The ZIP file contains the complete Git log of the project, by the way. Enjoy.

Parker update: home but on drugs

Cone of shame, shaved leg, drugged out of his mind: that's my boy. But at least he's home:

As I've been saying, the next few weeks will be rough. But he's going to get lots of attention, especially between now and Monday.

And then there's this:

He has physical pain, I have psychic pain. All because he ran up some stairs too fast.

Again: ouch.

D is for Database

Blogging A to ZWelcome to day 4 of the Blogging A-to-Z challenge. After yesterday's more theoretical post on the CLR, today will have a practical example of how to connect to data sources from C# applications.

Almost every application ever written needs to store data somewhere. If you're deploying a .NET website into Microsoft Azure (like this blog), you will probably connect it to an Azure SQL Database. Naturally, Visual Studio and C# make this pretty easy.

Here's the code that opens up a database connection and prints out to the Trace window what it's opened:

#region Copyright ©2018 Inner Drive Technology

using System.Configuration;
using System.Data.SqlClient;
using System.Diagnostics;


namespace InnerDrive.DailyParkerAtoZ.WeekOne
	public static class DataConnections
		private static string ConnectionString => ConfigurationManager.ConnectionStrings["Database"].ConnectionString;

		public static void Connect()
			using (var connection = new SqlConnection(ConnectionString))
				Trace.WriteLine($"Connected to {connection.DataSource}");

Let's take a look at that line by line.

Lines 3-6 tell the compiler that the objects referenced in the executable code come from those four namespaces (which I'll talk more about on April 16th). The SqlConnection class, for example, lives in the System.Data.SqlClient namespace. If I didn't have the using statement on line 5, I'd have to reference the class and its namespace as System.Data.SqlClient.SqlConnection, which is cumbersome.

Line 13 creates a ConnectionString property that gets its value from a configuration setting. More on that below.

Line 17 first sets up a different kind of using statement, which makes sure that whatever the expensive SqlConnection class does while its alive, it gets cleaned up when it finishes on line 21—even if it throws an exception. Then the same line creates a new SqlConnection object and assigns it to the variable connection.

Line 19 attempts to open the connection to the database. If it succeeds, line 20 prints out the name of the data source. If it fails, it throws an exception that whatever method called this one can catch.

The configuration file looks like this (but with a real database, user ID, and password):

<?xml version="1.0" encoding="utf-8" ?>
			connectionString="server={server name};initial catalog={database name};persist security info=True;user id={user ID};password={password};"

Notice that the name on line 5 corresponds to the configuration setting name on line 13 of the C# code. That's how the code knows which connection string to read from configuration.

Finally, there's also a unit test, which looks like this:

#region Copyright ©2018 Inner Drive Technology

using InnerDrive.DailyParkerAtoZ.WeekOne;
using Microsoft.VisualStudio.TestTools.UnitTesting;


namespace InnerDrive.DailyParkerAtoZ.UnitTests
	public class DataConnectionsTests
		public void CanConnectToDataSource()

If the call to DataConnections.Connect() succeeds, the test passes. If the call fails, the test fails and shows the exception that gets thrown.

You can download the code for all of these posts here. You'll have to change the configuration information in the unit test project's app.config file to make it work, of course.

Parker post-surgery update

Whew. Parker is just fine.

The surgeon said everything went very well. She reported he completely tore his meniscus and his right CCL (the doggy equivalent of a human's ACL), and it looked like the result of an acute injury, not age-related deterioration. This is good news because it means he has a much lower risk of doing this to his left leg than we worried about.

He's recuperating from the operation right now and will remain overnight for observation. He should be home after lunch tomorrow, with a healthy quantity of drugs and probably a really sharp appetite.

Recovery should take 6-8 weeks, though he should be able to go for actual walks within about 2 weeks. But wow, he's not going to like those two weeks.

Stay tuned. Photo tomorrow, I expect.

C is for Common Language Runtime

Blogging A to ZDay 3 of the Blogging A-to-Z challenge brings us to the heart of .NET: the Common Language Runtime (CLR).

Microsoft defines the CLR as the run-time environment which "runs the code and provides services that make the development process easier." That isn't the most helpful definition, so let me try to elaborate.

As I described Sunday and yesterday, the .NET compiler takes your source code from C# or whatever other language you use and compiles it down to one or more managed modules containing intermediate language (IL), which get further compiled into assemblies.

When your program runs, the CLR is the thing running it. It loads your assemblies and then handles all the tasks your program needs to survive, like memory management, thread synchronization, exception handling, security, etc. It actually does this through Just-in-Time compilation (JIT), when it translates the IL into your machine's own language. This means that when an IL instruction is executed for the second time, it runs in native CPU code.

The CLR also manages .NET's common type system (CTS), which "defines how types are declared, used, and managed in the common language runtime," according to Microsoft. Types (my topic for April 23rd) are therefore a part of every .NET program, even (gasp!) Ruby.NET. I'm picking on Ruby because in that language, ever instruction gets interpreted at run time, making it possible to use types that you haven't defined. The CLR and the CTS prevent you from doing that.

To learn a lot more about the CLR, I strongly recommend Jeffrey Richter's CLR via C#, which I mentioned Sunday.

B is for BASIC

Blogging A to ZFor day 2 of the Blogging A-to-Z challenge, I'm going to talk about the first computer language I learned, which is still alive and kicking in the .NET universe decades after it first appeared on a MS-DOS 1.0 system disk: BASIC.

BASIC stands for "Beginner's All-Purpose Symbolic Instruction Code." The original specification came from John Kemeny and Thomas Kurtz at Dartmouth College in 1964. Today it's one of the core .NET languages included with Visual Studio as "VB.NET" (for "Visual BASIC," Microsoft's dialect of BASIC released in 1991).

Yesterday I showed you a "Hello, World" application written in C#. (You can download the source code here.)

Here's the VB.NET version:

Module Program

	Sub Main()
		Console.WriteLine("Hello, World!")
	End Sub

End Module

What's different? Well, a lot of things: no braces, no include lines, no semicolon line endings...and that's just for a 2-line program.

But look at what's the same. Because this is a .NET program, the actual guts of it look almost exactly the same. There are two calls to different methods on the Console object, and except for the missing semicolons, they are identical to the calls in C#.

Here's the IL:

.method public static void  Main() cil managed
  .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       19 (0x13)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldstr      "Hello, World!"
  IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_000b:  nop
  IL_000c:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
  IL_0011:  pop
  IL_0012:  ret
} // end of method Program::Main

Wow. The IL is exactly the same. So both the VB.NET and C# code compile down to functionally identical assemblies.

And that's one of the most important characteristics of .NET: it lets you write code in any language you want (as long as someone has written a compiler for it), and run it on any platform you want (as long as there's a CLR for it).

I worked with Visual BASIC from versions 1 to 6, and then did one project in VB.NET before switching to C# in 2002. You really would need to pay me a lot of money to go back to it. I believe C# is more expressive, more concise, and more able to reflect my intentions than VB.NET.

But there is nothing wrong with VB.NET. If you want to use BASIC, enjoy. With the .NET ecosystem, it's up to you.

April come she will

Blogging A to ZThe A-to-Z Challenge starts tomorrow, and I'm all set to go with a list of 26 topics on programming with Microsoft .NET.

Now I just need to write the actual posts.

It's interesting to me how vacations don't actually lend themselves to much productivity, even when that's the explicit purpose of the vacation.

Anyway, if I do my job today, the first post will hit at noon UTC tomorrow. If I don't do my job today, it'll hit sometime later than that.

Still churning through my to-do list

On the one hand, I've been really productive on my staycation, having checked off 38 to-do items including a few that came from my need to get Parker repaired.

On the other hand, I've done none of the reading and writing I set out to do. With the A-to-Z challenge starting in two days, I really need to get on that.

But, you know, it's still a vacation. So why not vacate a bit?

Parker update

I mentioned yesterday that Parker stopped putting weight on one of his legs after hurting himself running up the stairs Saturday night. Turns out, it's pretty bad.

His primary vet says my aging mutt tore his ACL and meniscus, which will require surgery. He's getting X-rays on Monday to confirm the injury but she has very high confidence in the diagnosis. Surgery is scheduled for Tuesday.

He doesn't seem to be in any pain when he's lying down (which, as an old dog, he does 20 hours a day). Walking up and down stairs is not possible, however. (Did I mention he weighs 30 kg?) And he has some discomfort in his usual sitting posture. I've got him on pain meds and a joint supplement, but he's not going to be a happy dog for the next couple of months. No day care, no long walks, and definitely no running, probably until the end of May.

Poor doggie.

Whisyfest 2018 summary

I mentioned physical items on my desk that needed sorting. My tasting notes from Whiskyfest comprise some of them.

I'm not going to go into details about the whiskies I tasted; here, instead, is a summary table:

Distillery Expression Verdict
Ardbeg 10 year Drink
Ardbeg An Oa Buy
Ardbeg Dark Cove Committee Release Buy
Ardbeg Kelpie Committee Release Drink
Ardbeg Grooves Committee Release Drink
Balvenie 21 year portwood Buy
Balvenie Peat Week Drink
BenRiach 10 year Buy
BenRiach 10 year Curiositas Drink
BenRiach 21 year Drink
BenRiach 21 year Temporis Buy
BenRiach 12 year Triple-Distilled Horizons Drink
BenRiach Cask Strength Batch 2 Drink
BenRiach 2005 Peated Port Single Cask #2683 Buy
Bowmore 18 year Manzanilla Buy
Bowmore 25 year Buy
Four Roses 2017 Limited Edition Small Batch Skip
Glenmorangie Spios Rye Cask (2018 private edition) Buy
Lagavulin Distiller's Edition 2001 Buy
Laphroaig 25 year Buy
Laphroaig 27 year Buy
Linkwood 19 year cask strength Skip
Maker's Mark Cask Strength Skip
Maker's Mark Private Select Skip
Oban Distiller's Edition Buy
Old Rip Van Winkle Pappy 20 year Skip
Old Rip Van Winkle Pappy 23 year Skip
The Tyrconnell 15 year Madeira cask Buy
The Tyrconnell 7 year Drink
The Tyrconnell Madeira cask (no age) Drink
The Tyrconnell Sherry cask Skip
The Tyrconnell Port cask Skip

It's important to note that while I tasted all of these whiskies, but I did not drink all of these whiskies. I went with a friend, and we shared tastes; the pours were generally very small; and we went to seminars for three distilleries, spreading those tastings out over 45 minutes each. The whole event lasted four hours.

Also, Whiskyfest provides a metric shit ton (a shite tonne) of food. Good food. Heavy, fatty food.

But now you have more context for why I did nothing of commercial or professional value over the weekend.

And yeah, as much as I want to buy some of these, I'm not likely to shell out the $1,000 for the Laphroaig 27 next time I'm at Binny's.