Keyboard Shortcut Shortcuts

This is a short post and hopefully incredibly helpful to some. There is (almost) a standard around finding out basic information about keyboard shortcuts in your favourite apps, and it came to my attention this week that not everyone knows about it. What I am about to tell you may change the way you use some of your most cherished applications forever, or it may not.

Almost every web application supports a keyboard shortcut for seeing more keyboard shortcuts using either + / or + /1. Using these you can quickly get to a summary of keyboard shortcuts for your app of choice. Even some locally installable desktop apps have taken to this "standard" shortcut for showing shortcuts. Go now and try it in something.

For those who aren't into experimenting with shortcuts, here are a few apps and their shortcuts shortcut. Search the table for your app of choice. If you happen to know about any other apps that use this approach should be in this list, let me know in the comments.

Happy keyboarding!

ApplicationShortcut
Asana⌘ + /
Bitbucket⇧ + /
Desmos⌘ + /
Facebook⇧ + /
Github⇧ + /
Google Calendar⇧ + /
Google Docs⌘ + /
Google Drive⇧ + /
Google Hangouts⇧ + /
Google Sheets⌘ + /
Google Sites⌘ + /
Google Slides⌘ + /
Gmail⇧ + /
Inbox by Gmail⇧ + /
Jira⇧ + /
Onedrive⇧ + /
Slack⌘ + /
Trello⇧ + /
Tweetdeck⇧ + /

Featured photo derived from photo by Andrew Worley on Unsplash


  1. By ⌘, I mean either the looped square key on an Apple computer, or the Windows key on a PC 

New Job, New Tech

Hello, world!

You might have noticed I took a little break from my blog recently. It was not intentional; things just got away from me a bit the last few months as I found a new job and had a nice vacation to see family in England (as well as a side trip to Edinburgh and the famous Fringe festival). Perhaps I will post more on the vacation another time; right now, I want to share my job news.

After a fantastic four years with CareEvolution, Inc., I recently accepted a software engineering position with Khan Academy. I am only a few weeks into my new position and I am still incredibly excited to have this opportunity. Not only am I working with some incredible people, we have tasked ourselves with an outstanding mission.

Our mission is to provide a free, world‑class education for anyone, anywhere.1

Leaving CareEvolution, Inc. was a difficult decision. Not only did it mean leaving behind extraordinary colleagues, it also meant leaving behind PowerShell, C#, Angular, and .NET as a part of my day-to-day profession. Instead, I will be working with React, Redux, Apollo, and Python. There is much for me to learn and, I hope, for me to blog about as I learn it. That said, I still love .NET things and will continue to tinker with them in my personal time2.

Of course, like my passion for .NET, some things will remain the same. Most significantly for me, the position is still remote and as such, provides me with great opportunities for personal growth as an offsite colleague and employee. I openly3 struggled with that while at CareEvolution, Inc. I hope that at Khan Academy, I can learn which parts of that struggle were down to the need for personal growth, and which, if any, were organisational. If I can, I will coalesce lessons I learn into a meaningful collection of tips that others might use to adapt their personal and organisational culture around remote work and off-site workers.

Finally, this blog is still my blog, these are my personal musings; nothing I post here represents the views of my employer. Thank you for your readership and your patience during my blog hiatus. As they say at work, onward!


Featured Image by Todd Quackenbush on Unsplash


  1. https://www.khanacademy.org/about 

  2. I have already started developing .NET core on OSX 

  3. perhaps too openly 

Using PowerShell to make BrowserStack local testing easier with Microsoft Edge

BrowserStack has been an incredibly useful resource for tracking down bugs and testing fixes when I am working on websites. This often requires accessing locally deployed sites or sites accessible over a VPN connection, and to do that, BrowserStack needs some local code running to be able to route the traffic accordingly.

BrowserStack logoUp until recently, my browser of choice has been Google Chrome, for which BrowserStack provides a handy extension to add support for local sites. However, since the Windows Creators Update, I have been giving Microsoft Edge a shot1 and no such extension exists. Instead, BrowserStack provides a download, BrowserStackLocal.exe , and a secret with which to run it. This works great, but there are a couple of annoyances.

  1. I have to remember to run it.
  2. It is a blocking process.

There are a variety of ways this problem can be solved. I decided to take the opportunity to expand my PowerShell fu and put together some cmdlets to run the BrowserStackLocal process in the background. Specifically, I wanted to compare PowerShell jobs with plain old processes for this specific purpose.

First: Jobs

Since the running the command is a blocking operation, I decided to try wrapping it in a PowerShell job so that it would sit in the background. This is useful since the job gets terminated when the PowerShell session ends, which makes it less likely for me to forget. The downside is that each PowerShell session could have its own job, but only the one that started BrowserStackLocal will actually end it, but I was certain I could work with that.

Getting started

The first cmdlet for starting BrowserStackLocal is cunningly named Start-BrowserStackLocal , shown here:

This has basic room for improvement, like having the secret and the path be parameters to the cmdlet, or environment variables; I happened to stop tinkering once it worked for me, so feel free to expand on it.

At the start, we check to see if we already have a job for BrowserStackLocal since we only need one. If we do not, then we get on with making sure BrowserStackLocal can be found where we expect it. If everything looks good, then the job gets started.

To tackle the chance that my script may fail due to the BrowserStackLocal command either getting an incorrect key or discovering it is already running, I added a Wait-Job call. The nice thing here is that since normally BrowserStackLocal blocks, we can assume that if the job did not reach a completion state, then the executable command is running. I take advantage of that fact, so if the Wait-Job returns, we can assume things went wrong and dump the details of the problem back to the console.

Stopping the job

Once the job is running, we need to be able to terminate it.

This is a much simpler cmdlet than the one to start the job. It has two main tasks:

  1. See if the job is actually running
  2. If it is, stop it

I added some helpful output so we could see it working and that was that.

Output from jobs-based cmdlets
Output from jobs-based cmdlets

Problems with jobs

This solution using jobs works great but it is not ideal. Each PowerShell session has its own jobs, so you have to know which session actually started BrowserStackLocal in order to stop it. Not only that, but if PowerShell did not start it at all, you cannot stop it from there with these commands at all. Jobs are great but they are not really the right tool for this…er…job.

Second: Processes

The wise man would have probably started here. I did not because I wanted to learn about jobs. Now that I have, I am wiser and so, I thought I would recreate my success but this time using the Xxx-Process  cmdlets of PowerShell.

Getting started again

Using processes, the start cmdlet looks like this:

Since the BrowserStackLocal executable starts more than one process, I added some loops to output information about those processes. Now if we try to start the command and it is already running, we will get the same feedback, regardless of where the command was started.

Stopping the process

Switching to processes makes the stop code a little more complicated, but only because I wanted to provide some additional detail (we could have just called Stop-Process BrowserStackLocal and it would stop all matching processes).

Output from process-based cmdlets
Output from process-based cmdlets

Helpful aliases

Finally, to make the task of starting and stopping a little less arduous, I added some aliases (inspired by the helpful sasv and spsv aliases of Start-Service and Stop-Service).

Conclusion

TL;DR: Use processes to start processes in the background2.

The rest

I am pretty pleased with how this little PowerShell project worked out. I get to keep using Microsoft Edge with minimal effort beyond what I had when using Google Chrome for my BrowserStack testing, enabling me to take advantage of the performance and battery-life improvements Edge has over Chrome. Not only that, but I got to learn some new things about PowerShell.

  1. You don't get closures entirely for free in PowerShell. I suspected this, but I learned the hard way. However…
  2. We can pass local variables into script blocks using the $using:<variable> syntax instead of passing an argument list and adding parameters to our script.
  3. Debugging jobs can be a pain until you learn the value of Receive-Job for getting error information.
  4. Use Wait-Job with a little time out to give your job chance to fail so that you can spit out some error information.
  5. You have to stop a job before you can remove it.
  6. Don't use jobs to control background processes; use processes instead

I have not gone so far yet as to start the BrowserStackLocal service automatically, but I can see value in doing so, especially if I did a lot of BrowserStack testing on local sites every day (of course, I'd probably want to redirect the output to $null in that scenario rather than see feedback on the running processes with every shell I opened).

What are your thoughts? Do you use PowerShell jobs? Do you use BrowserStack? Will you make use of these cmdlets? Fire off in the comments.


  1. Yes, the battery life is noticeably better than when using Chrome; yes, I am frustrated that I cannot clear cookies for a specific site 

  2. Well, duh. But if I had taken that attitude, I would not have learned about jobs. 

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 

C#7: Tuples

Well, here we are; the final post in this series on the new C#7 features. Over the last six weeks we have covered all but one, including:

While pattern matching is exciting, local functions are useful, and some of the other enhancements are nice, I personally feel that I have saved the best for last, because this week it is time to look at tuples.

Tuples

Wait, don't we already have tuples in C#? I mean, we totally have a type called Tuple so it sure seems like it. In fact, we have at least one other tuple-type too, KeyValuePair<TKey,TValue>. However, these are not C# concepts, they are .NET types and they fall pretty short of being the kind of tuples we want. I did not know what was really wrong with them until I learned about the tuples we get with C#7.

It turns out, the old Tuple type is limited; the members have fixed names ( Item1, Item2, etc.) which do not communicate their purpose, it is a reference type and as such can have a measurable impact on performance due to object allocations, and it has no syntactical support within the language1. To support the new C#7 feature, there is a new tuple type that is more performant and better suited to the awesomeness that is C#7 tuples; it is a value-type called ValueTuple and it comes with some friends like TupleElementNamesAttribute to give us something wonderful.

If you want to play with C#7 tuples in Visual Studio 2017 RC, you'll need to grab the NuGet package so that the appropriate types to support tuples are available for the compiler. LINQPad Beta already includes everything you need.

Syntax

To define a new tuple in C#7, we use parentheses in an assignment like this:

This creates a new tuple that looks an awful lot like something we might have created using Tuple.Create("John", "Smith", 45, ConsoleColor.DarkRed), since the values of the tuple are referenced via Item1, Item2, Item3, and Item4. That does not seem like a particular useful addition. However, we can make this tuple so much better with some simple changes to our assignment, like this:

Now, instead of the ItemX members, we can access our values using FirstName, LastName, Age, and FavouriteConsoleColor, as if we had instead created an anonymous type. Of course, the great thing is that we did not introduce a new type to do this; the C# compiler pulled some magic along with the new ValueTuple type2 . Of course, it does not end there; we can take advantage of a new feature called deconstruction to name the fields on the left of the assignment instead:

In fact, we can provide names on both sides although the ones provided on the left take precedent and you will get a compiler warning. However, being able to provide names via the right-hand side of an assignment is useful when a method returns a tuple and you want to provide some meaningful names locally. This is even more useful when you find out that you can drop the tuple variable name:

We basically just assigned values to four local variables that we can then use in the rest of our code, but if we had a method like this:

We could do this on the right-hand side of that assignment:

What we did there was deconstruct the returned tuple into four separate fields. Our method declares its return type as ValueType<string, string, int, ConsoleColor>  and returns a tuple, then we assign that tuple to four variables by using the deconstruction syntax. In this example, I even switched to using var instead of explicitly typing the deconstruction. The var keyword can be used for all of the deconstructed fields, just a couple with the remainder strongly typed, or none; it's up to you and your code reviewers.

Deconstruction is going to change the way you write methods and some of your types, and will probably mean a lot less uses for out variables. That said, do not get carried away. Tuples are best for internal and private methods rather than public APIs where a static type is much more helpful to the consumer of your API.

The Deconstruct Method

If a method returns a tuple (e.g. return ("John", "Smith")), we can use deconstruction to assign its parts to different variables if we wish. However, deconstruction is not reserved for just tuples. We can also define how our own types can be deconstructed into separate variables. To do this, we define a Deconstruct method on our type that tells the compiler how to deconstruct it into separate values. For example:

With this type defined, we can use the deconstruction syntax with it just as we would with a ValueTuple:

I am not sure when I will use this ability to define deconstruction for my types, but I can imagine when the moment arises I will know. Also, you can see from its extensive use in the Deconstruct method, out is certainly not redundant.

Anonymous Types

Tuples in C#7 seem to out-do anonymous types in every way; tuples don't define a new type, they can be returned from methods without the overheads of object or dynamic, they support deconstruction, and they take up less typing; yet as far as I can tell they can be used everywhere that anonymous types can be used. It is likely that I am missing something important, but from my perspective thus far, I think tuples in C#7 not only kills off any new uses of the Tuple type, but also anonymous types.

In Conclusion

I really like this feature and the simplicity of its usage. It is light on extra syntax, adding the concept of a parenthetically-typed variable, but powerful in what it allows us to do with method returns and type deconstruction. I would like to give it some more thought and use it in more scenarios, but I also think tuples in C#7 will render anonymous types obsolete.

You can skim the overview of tuples in the What's new in C# 7 document, however, this is a simple feature with a complex background, so I highly recommend reading the more in-depth coverage on the Tuples official documentation, especially with regards to assignment of tuples with explicit member names3. It is a shame that it took two attempts to get tuples to be where they should be in C#, leaving yet another type4 by the wayside, but they are here at last and we will all be grateful.

What do you think? Are anonymous types relegated to legacy code only? Will Tuple.Create ever get used again? Is there something I should cover that is missing here or in the official documentation? Sound off in the comments and let me know.

 


  1. C# Concepts: Tuples 

  2. Actually, like dynamic, the field names use an attribute to communicate the names of each tuple field 

  3. Hint: member names are not attached to the value, but instead stay with the variable for which they were declared 

  4. Tuple.Create may never get used again