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:

function Start-BrowserStackLocal()
{
    $browserStackSecret = "<YOUR-SECRET-HERE>"
    $browserStackLocalDir = "F:\Program Files (x86)\BrowserStackLocal"
    $bslocal = Get-Command "$browserStackLocalDir\BrowserStackLocal.exe" -ErrorAction SilentlyContinue

    $job = Get-Job BrowserStackLocal -ErrorAction SilentlyContinue
    if ($job) {
        Write-Host "BrowserStackLocal already started: " -ForegroundColor Yellow -NoNewline
        Write-Host "$($job.ID):$($job.Name)" -ForegroundColor Cyan
        return
    }
    
    if (-Not $bslocal) { throw "Cannot find BrowserStackLocal" }

    Write-Host "Starting BrowserStackLocal..." -ForegroundColor Yellow
    $job = Start-Job -Name BrowserStackLocal -ScriptBlock {
        try {
            Push-Location $using:browserStackLocalDir
            & $using:bslocal.Path $using:browserStackSecret
        }
        finally {
            Pop-Location
        }
    }

    if2
    {
        Write-Host (Receive-Job $job)
        Remove-Job $job
    } else {
        Write-Host "Started " -NoNewline -ForegroundColor Yellow
        Write-Host "$($job.ID):$($job.Name)" -ForegroundColor Cyan
    }
}

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.

function Stop-BrowserStackLocal()
{
    $job = Get-Job BrowserStackLocal -ErrorAction SilentlyContinue
    if (-Not $job) {
        return
    }
    Write-Host "Stopping BrowserStackLocal: " -ForegroundColor Yellow -NoNewline
    Write-Host "$($job.ID):$($job.Name)" -ForegroundColor Cyan -NoNewline
    Write-Host "..." -ForegroundColor Yellow
    Stop-Job $job
    Remove-Job $job
}

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:

function Start-BrowserStackLocal()
{
    $browserStackSecret = "<YOUR-SECRET-HERE>"
    $browserStackLocalDir = "F:\Program Files (x86)\BrowserStackLocal"

    $processes = Get-Process BrowserStackLocal -ErrorAction SilentlyContinue
    if ($processes) {
        Write-Host "BrowserStackLocal already started: " -ForegroundColor Yellow
        foreach ($process in $processes) {
            Write-Host "    $($process.ID): $($process.Name)" -ForegroundColor Cyan
        }
        return
    }

    $bslocal = Get-Command "$browserStackLocalDir\BrowserStackLocal.exe" -ErrorAction SilentlyContinue
    if (-Not $bslocal) { throw "Cannot find BrowserStackLocal" }

    Write-Host "Starting BrowserStackLocal..." -ForegroundColor Yellow
    Start-Process -FilePath $bslocal.Path -WorkingDirectory $browserStackLocalDir -ArgumentList @($browserStackSecret) -WindowStyle Hidden

    Wait-Process -Name BrowserStackLocal -Timeout 3 -ErrorAction SilentlyContinue
    $processes = Get-Process BrowserStackLocal -ErrorAction SilentlyContinue
    if ($processes)
    {
        foreach ($process in $processes) {
            Write-Host "    $($process.ID): $($process.Name)" -ForegroundColor Cyan
        }
    }
}

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).

function Stop-BrowserStackLocal()
{
    $processes = Get-Process BrowserStackLocal -ErrorAction SilentlyContinue
    if (-Not $processes) {
        Write-Host "BrowserStackLocal is not running"
        return
    }
    Write-Host "Stopping BrowserStackLocal..." -ForegroundColor Yellow
    foreach ($process in $processes) {
        Write-Host "    $($process.ID): $($process.Name)" -ForegroundColor Cyan
        Stop-Process $process
    }
}
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).

Set-Alias sabs Start-BrowserStackLocal
Set-Alias spbs Stop-BrowserStackLocal

Conclusion

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

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. Wait-Job $job -Timeout 3 []
  3. Well, duh. But if I had taken that attitude, I would not have learned about jobs. []

Lessons from an ever changing career in software development

At the end of last year I came to a terrifying conclusion; it was time to look for a new job. I was terrified because I had not been through the process of proper job hunting in over 12 years and because, though I had a job, I knew I would not be happy if I stayed in it. I had worked in the same organisation for over a decade and though I had worked several different jobs and faced many challenges, this felt like the biggest (yes, even bigger than when I moved to the US).

The story of my career and this move is too long for this post1, but after transitioning from university to a job, from Motorsport to automotive and now healthcare IT, and from the UK to the US, I have learned a few things along the way and I believe they are universal. Perhaps you feel something is wrong and you can't put your finger on it, or maybe you want to try something new but are frightened of what where that might lead; just knowing others go through similar emotions can be incredibly helpful, so I'm sharing what I've learned so far.

  1. Look for opportunity

    It seems strange and I certainly didn't get this for a long time, but you won't recognise an opportunity unless you are already looking for it. I look back on every major change I made in my life and can see how this was true for each and every one, whether it was going to university, farming Ostrich, or moving to the US.

  2. Know what you want

    In order for you to recognise that opportunity, you have to know what it looks like and more importantly, what it does not. List the things you want in a job and take note of the things you don't want. Don't just think about the technical side of things, be sure to consider the culture you'd like to work in too. This also helps in recognising when it is time for a change.

  3. Learn the signs that it's time to change

    Too often we can ignore the little things that indicate a bigger problem and pass them off as having a bad day or working with annoying people. In reality, these are often signs of a wider dissatisfaction that needs to be addressed. It's easy to ignore the little problems when you're enjoy what you do, but once the enjoyment is gone, those little problems get bigger. Has there been a cultural change within you or the organisation? Are you not getting things from your work that you used to? Take stock of your situation and work out what you do and don't want from your job then see if it matches. If it doesn't, work out what you need to do to fix it. Sometimes all you need to do is make some simple changes to the way you work, sometimes you'll need a whole new workplace, but recognising this before you start burning bridges is really important, for you and your colleagues.

  4. Don't burn bridges

    It is tempting when making a change (or in the throes of realising that you need to) to tell people what you really think of them or their job. Resist this urge. Unless you are truly coming from a well-intentioned place and you are certain that the other party is willing to hear what you have to say, it is best to keep it to yourself. Usually, it is best to keep it to yourself. I was once told to be nice to people you meet on your way up in your career because you never know who you'll need when you find yourself on the way back down. I didn't listen. I have one less bridge.

  5. Don't be afraid to ask questions

    Whether in an interview or just in your every day work, ask questions. If you don't know something and you want to know it, ask someone. I have learned this the hard way. Knowing when it's time to ask instead of continuing to blunder around in the dark is really important. You may feel like you're stupid or weak somehow for asking, but asking is far better than finding yourself in a job you hate or without a job because you spent too long not knowing what you were doing. Sometimes, this can even help avoid the need to change your job in the first place.

  6. Know your own mind

    Learn to recognise when fear is clouding your judgement. When we're afraid to try something, we're great at convincing ourselves that we're right to just not. For example, some people turned down the same opportunity I took when I ended up moving to the US because they "owned houses" or "had a family"2. While compelling, these excuses aren't truly impassable obstacles like those who utter them would have us believe. A person who is content and doesn't want an opportunity is surely more likely to just say, "no", but those who are afraid will find excuses instead. If I had let my fear of the unknown take hold, I could have found a hundred reasons why I just couldn't move to the US (it was only for a month or so originally, anyway), but instead I identified what might make the move difficult and I addressed it.

While I've focused on career change here, many of these things apply to life in general. I hope that you find them useful. Perhaps you have some tips of your own. Please feel free to comment and share them with the rest of us.

  1. perhaps another as I did just write it while prepping this one []
  2. As if I'm some mutant who just appeared one day, parentless and alone. Apparently, this phrase "have a family" only has true meaning if you're married with kids…please… []