C#7: Tools

I have spent the first couple of months of 2017 learning about the new features in C#7. This would not have been possible without some tools to help me play around with the new language syntax and associated types. Since we have to wait a little longer until Visual Studio 2017 is released, I thought you might like to know what tools I have been using to tinker in all things C#7.

LINQPad Beta

Link: http://www.linqpad.net/Download.aspx#beta

While early releases of Visual Studio 2017 (scheduled for release on March 7th) support the language, I initially found the release candidate to be unstable and frustrating. Not only that, but it can be cumbersome to spin up a quick example using Visual Studio, so I turned to my trusty friend, LINQPad.

LINQPad Beta showing me my return is missing a ref
LINQPad Beta showing me my return is missing a ref

I cannot recommend LINQPad enough, it is a fantastic tool for prototyping, poking around data sources, and more besides, like tinkering with language features you don't yet understand. While LINQPad's current release only supports the C# language up to version 61, the beta release also supports C# version 7. Not only can you use the language, but with the fantastic analysis window, you can see how Roslyn breaks down each part of the code. If you want to get started quickly, easily play around with the cool new features, and have a powerful tool for digging deeper as the need arises, the LINQPad beta is the tool to get.

Visual Studio 2017 RC

Link: https://www.visualstudio.com/downloads/

Visual Studio 2017 RC splash
Visual Studio 2017 RC splash

Yes, I know I said it was unstable and frustrating, but that was before, way back in January. These days the RC is much, much better and with the release date set for March 7th, there was never a better time to install Visual Studio 2017 RC and get a head start on getting to know some of the new things it can do, including C# 7. Tuples are fun, but poking around with them in the debugger is funner.

OzCode

Link: https://oz-code.com/

Pattern matching in OzCode
Pattern matching in OzCode

It is no secret that I love OzCode, the magical debugging extension for Visual Studio. It is so well-known that they asked me to be part of their OzCode Magician community program. So, it should come as no surprise that I have been using OzCode in my exploration of C#7. As the Visual Studio 2017 RC has matured, the clever people over at CodeValue have been creating previews of OzCode version 3, including amazing LINQ debugging support. Recently, I got to try an internal build that included support for all the cool new things in C#7.

OzCode 3 will be released on March 7th, the same day as Visual Studio 2017.

Documentation

Link: https://docs.microsoft.com/dotnet/articles/csharp/csharp-7

Never underestimate the power of reading documentation, it is one of the best tools out there. For my C#7 posts, I relied heavily on the new docs.microsoft.com site, specifically the .NET articles on C#. Not only is this a fantastic resource, but it has built-in support for commenting on the documentation so that you can ask questions and contribute to their improvement.

In Conclusion

This is the entire list of tools I used for my C#7 investigations. Try them out and get an early start on C#7 fun before the March 7th release of all the C#7 goodness. Happy tinkering and if you stumble on any useful tools, please share in the comments!


  1. It also supports SQL, F#, and VB 

OzCode: Reveal With Reveal

In my last post, I revealed that I am a magician; an OzCode magician1. I also revealed the new LINQ support currently in EAP. Since that was two reveals in one, I thought that I would look at another OzCode feature today coincidentally called Reveal.

I remember this specific feature as "favourites for properties" although I am reliably informed by the OzCode team, their website, and their documentation that it is in fact called "Reveal"2. Reveal was the feature that first lured me into regular use of OzCode and if it is the only feature you use, you will still wonder how you really survived without it.

When debugging, we can spend lots of time drilling down into objects to find the value of various properties and sub-properties. This can get especially tiresome when we're looking at a few similar objects since we repeat the same steps. Although pinning certain values is helpful, it does not really solve the initial issue of drilling down to find the thing to pin.

With Reveal, we can make life much simpler by elevating the details of an object to its summary; like an on-the-fly custom ToString implementation. Not only does this help with looking at one item, but it really helps with collections of similar items. For example3:

Animated GIF showing how to use Reveal in OzCode
Animated GIF showing how to use Reveal in OzCode

Any properties that are "revealed" carry across to the rest of the debug session and beyond; once you have revealed some properties, they stay revealed until you decide you do not want them to be anymore, even across debug sessions.

Animated GIF showing how the revealed properties remain revealed
Animated GIF showing how the revealed properties remain revealed

You can even see (and change) your revealed properties directly within the LINQ analysis window.

Animated GIF of using Reveal inside the new LINQ analysis feature of OzCode
Animated GIF of using Reveal inside the new LINQ analysis feature of OzCode

Finally, revealed properties propagate up the object hierarchy allowing you to surface values from deeper in your object tree. This can really be a huge time saver, especially since the revealed properties are remembered across sessions. No more hovering over multiple things to find what you're looking for and no more writing custom ToString overrides, debug visualizers, or other workarounds.

Hopefully, this overview of Reveal in OzCode has demonstrated not only why I love it so much, but also how valuable it can be. I genuinely believe OzCode to be an essential tool in any .NET developer's kit, but since you may mistake me for some corporate shill, you should not take my word for it; try OzCode out for yourself with a free trial (or take part in the EAP). Stop performing workarounds and start performing magic.


  1. Read as Sean Connery as James Bond 

  2. and apparently it doesn't matter how often I tell them they are wrong 

  3. To demonstrate, I am using the handy demo app from OzCode, which you can find on GitHub 

Octokit, Merge Commits, and the Story So Far

In the last post we had reduced our commits by matching them against pull requests; next, we can look for noise in the commit message content itself. Although I have been using the Octokit.NET repository as the target for testing with its low noise, high quality commit messages, we can envisage a less consistent repository that has some noisy commits. For example, how often have you seen or written commit messages like "Fixed spelling", "Fixed bug", or "Stuff"1?

How we detect these noisy commits is important; if our filtering is too simple, we remove too many things and if it is too strict, we remove too few. Rather than go deep into one specific implementation, I just want to introduce the idea of filtering based on message content. In the long term, I think it would be interesting to apply learning algorithms,  but I'm sure some simple, configurable pattern matching should suffice2.

If I run the filtering I have described so far3 on the Octokit.NET latest release, this is what we get:

The value of this is clearer if we see the commit list before processing:

The work so far has reduced a list of 135 commits down to 58, and so far, it looks like we have not lost any really useful "release note"-worthy information. However, the eagle-eyed among you may noticed that our 58 messages contain duplicate information. This is because each pull request is listed twice; once for the pull request title I inserted in place of its individual commits, and again for the merge commit that merged that pull request. These merge commits are not filtered out because they do not belong to the commits inside the pull request. Instead, they are an artifact of merging the pull request4.

At first, I thought the handy MergeCommitSha property of the pull request would help, but it turns out this refers to a test merge and is to be deprecated5. Instead, I realised that the messages I wanted to remove all had "Merge pull request #" in them, followed by the pull request number. This seems like a perfect use case for our pattern matching filtering. Since we have the pull requests, we could use their numbers to match each merge message exactly, but I decided to do the simpler thing of excluding any message starting with "Merge pull request #".

Filtering for messages that begin with "Merge pull request #" gives us a shortlist of just 31 messages:

I think this is a pretty good improvement over the raw commit list. Combining this list with links back to the relevant commits and pull requests should enable someone to discern the content of a release note much faster than using the raw commit list alone. I will leave that as an exercise or perhaps a future post. As always, thanks for reading. If you find yourself using Octokit to trawl your own repositories for release note information, I would love to hear about it in the comments.


  1. We're all friends here, you can admit it 

  2. The filtering should be configurable so that we can tailor it to the repository we are processing 

  3. excluding the last step of filtering by message content 

  4. Perhaps stating the obvious 

  5. https://developer.github.com/v3/pulls/ 

Octokit and Noise Reduction with Pull Requests

Last time in this series on Octokit we looked at how to get the commits that have been made between one release and another. Usually, these commits will contain noise such as lazy commit messages and merge flog ("Fixed it", "Corrected spelling", etc.), merge commits, or commits that formed part of a larger feature change submitted via pull request. Rather than include all this noise in our release note generation, I want to filter those commits and either remove them entirely, or replace them with their associated pull request (which hopefully will be a little less noisy).

Before we filter out the noise, it seems prudent to reduce the commits to be filtered by matching them to pull requests. As with commits, we can query pull requests using a specific set of criteria; however, though we can request the results be sorted a certain way, we cannot specify a date range. To get all the pull requests that were merged before our release, we need to query for all the pull requests and then filter by date locally.

This query can be slow, since we are getting all closed pull requests in the repository. We could speed it up by providing a base branch name in the query criteria. However, to remove as much commit noise as possible, I would like to include pull requests that were merged to a different branch besides just the release branch1. We could make things more performant by managing a list of active release branches and then querying pull requests for each of those branches only rather than the entire repository, but for now, we will stick with the less optimal approach as it keeps the code examples a little cleaner.

Before we can start filtering our commits against the pull requests, we need to get the commits that comprise each pull request. When requesting a collection of items (like we did for pull requests), the GitHub API returns just enough information about each item so that we can filter and identify the ones we really care about. Before we can do things with other properties on the items, we have to request additional information. More information on each pull request can be obtained about a specific pull request by using the Get, Commits, Files, and Merged calls. The Get call returns the same type of objects as the GetAllForRepository method, except that all the data is now populated instead of just a few select properties; the Merged call returns a Boolean value indicating if the PR has been merged (equivalent to the Merged property populated by Get); the Files method returns the files changed by that pull request; and the Commits method returns the commits.

At this point, things are looking pretty good: we can get a list of commits in the release and a list of pull requests that might be in the release. Now, we want to filter that list of commits to remove items that are covered by a pull request. This is easy; we just compare the hashes and remove the matches.

Using the collection of commits for the latest release, we join the commits from the pull requests using the SHA hash and then select all release commits that have no matching commit in the pull requests2. However, we don't want to lose information just because we're losing noise, so we have to maintain a list of the pull requests that were matched so that we can build our release note history. To keep track, we will hold off on discarding any information by pairing up commits in the release with their prospective pull requests instead of just dropping them.

Going back to where we had a list of pull requests merged prior to our release, let us revisit getting the commits for those pull requests and this time, pairing them with the commits in the release to retain information.

Now we have a list of commits paired with their parent pull request, if there is one. Using this we can build a more meaningful set of changes for a release. If I run this on the latest release of the Octokit.NET repository and then group the commits by their paired pull request, I can see that the original list of 135 commits would be reduced to just 58 if each commit that belonged to a pull request were bundled into just one entry.

Next, we need to process the commits to remove those representing merges and other noise. These are things to discuss in the next post of this series where perhaps we will take stock and see whether this effort has been valuable in producing more meaningful release note generation. Until then, thanks for reading and don't forget to leave a comment.


  1. often changes are merged forward from one branch to another, especially if there are multiple release branches to support patch development and such 

  2. The join in this example is an outer join; we are taking the join results and using DefaultIfEmpty() to supply an empty collection when there was nothing to join 

Use Inbox, Use Bundles, Change Your Life

I love Google Inbox. At work, it has enabled me to banish pseudo-spam1, prioritize work, and be more productive. At home, it has enabled me to quickly find details about upcoming trips including up-to-date flight information, remind myself of tasks that I need to do around the house, and generally be more organized. While Inbox doesn't replace Gmail for all situations, it does replace it as a day-to-day email client. Gmail is awesome; Inbox is awesomer.

The main feature of Inbox that has enabled me to build a healthier relationship with my email (and achieve virtual Inbox Zero without having to make email management my day job) is Bundling. Bundles in Inbox are a lot like filters that label emails in Gmail; they allow you to group emails based on rules. Not only can you define filters to determine what emails go in the bundle, but you can also decide if the bundled messages go to your inbox (and how often you see the bundle) or if they are just archived away.

Inbox Sidebar
Inbox Sidebar

Inbox comes with some standard bundles: Purchases, Finance, Social, Updates, Forums, Promos, Low Priority, and Trips. Trips is a magic bundle that you cannot configure; it gathers information about things like hotel stays, flight reservations, and car rentals, and combines them into trips like "Weekend in St. Louis" or "Trip to United Kingdom". The other bundles, equivalent to the tabs that Gmail added a year or two ago, automatically define the filters (and as such, those filters are uneditable), but do allow you to control the behavior of the bundle.

When bundled emails appear in your Inbox, they appear as a single item that can be expanded to view the emails inside. You can also mark the entire bundle as done2, if you desire. These features mean you can bundle emails in multiple bundles and have those bundles appear in your Inbox as messages arrive, once a day (at a time of your choice), once a week (at a time and day of your choice), or never3 (bundling some of the pseudo-spam and only having it appear once a day or once a week has drastically improved the signal-to-noise ratio of my email).

Trips
Trips
Trip to NYC
Trip to NYC

While the default bundles are useful, the real power is in defining your own. You can start from fresh or you can use an existing label. Each label is shown in Inbox as unbundled and has a settings gear that allows you to setup bundling rules. In my example, I added a rule to label emails relating to Ann Arbor .NET Developers group.

Label settings without any bundle rules
Label settings without any bundle rules
Adding a filter rule
Adding a filter rule
Label settings showing bundling rules
Label settings showing bundling rules

With the bundle defined, every email that comes in matching the rule will be labelled and added to the bundle, which will appear in my inbox whenever a message arrives. Any messages I mark as done are archived4, removing them from the main inbox. However, they can be seen quickly by clicking the bundle name in the left-hand pane. This is great, except for one thing. The bundle definition only works for new emails as they arrive. It does not include messages you have received before the bundle was setup.

This just felt untidy to me so I was determined to fix it. As it turns out, Gmail provides all the tools to complete this part of Inbox bundles. Since each bundle is a set of filter rules and a label, you can actually edit those filters in Gmail, and Gmail includes the additional ability of applying that rule to existing emails.  To do this, go to Gmail and click the Settings gear, then the Filters tab within settings.

Bundling filters in Gmail
Filters that define my bundle in Gmail

Find the filters that represent your new bundling rules, then edit each one in turn. On the first settings box for the filter, click continue in the lower right. On the following screen, check the "Apply to matching conversations" checkbox and click the "Update filter" button.

First filter edit screen
First filter edit screen
Last filter editing screen
Last filter editing screen
Apply to existing messages
Apply to existing messages

After performing this action for each of my bundles, I returned to Inbox and checked the corresponding bundles; all my emails were now organised as I wanted.

In summary, if you haven't tried Inbox (and you have an Android or iPhone; a strange limitation that I wish Google would lift), I highly recommend spending some time with it, getting the bundles set up how you want, and using it as your primary interface for your Google email. The combination of bundling with the ability to treat emails as tasks (mark them as done, snooze them, pin them) and see them in a single timeline with your Google reminders makes Inbox a powerful yet simple way to manage day-to-day email. Before Inbox, I abandoned Inbox Zero long ago as a "fake work" task that held no value whatsoever, my Gmail inbox had hundreds of read and unread emails in it. Now that I have Inbox, I reached Inbox Zero in a day with minimal effort that one might consider to be just "reading email". I'm not saying Inbox Zero is valuable, I'm just saying that it is realistically achievable with Inbox because Inbox gets daily email management right.

Use bundles, change your life.


  1. I use the term "pseudo-spam" to describe those emails that you don't want to necessarily totally banish as spam so that you can search them later, but that aren't important to you at all such as support emails for projects you don't work on, or wiki update notifications 

  2. One of the great features of Inbox is the ability to treat emails as tasks, adding reminders to deal with them later or mark them as done; this makes drop,delegate,defer,do a lot easier to manage 

  3. If a bundle is marked as never, it is considered "unbundled" and works just as a filter that applies a label 

  4. This can be changed to "Move to Trash" in the Inbox settings