RSSAmplifier

Blog

Your Website

nichesoftware.co.nzRSS feed ↗50 posts

Latest posts

Superpowers for your AI

If you want to take your use of AI for software development to the next level, you could do worse than superpowers , a set of interrelated AI skills that bring some process and rigor into play. I’ve been somewhat reluctant to post about the wave of AI tooling that’s changing the way we develop software, primarily because anything I say is likely to become obsolete within months, possibly weeks -…

Autotitling Windows Terminal Tabs

I make use of Windows Terminal a lot. It’s great for having multiple different pieces of work open at the same time. Problem is, I’ve been forever getting lost, not knowing which tab is which. With every tab looking the same, going back to the right one always took a few seconds. Fortunately, there’s a better way: a clever script that automatically sets the tab title to the name of the current…

Don't assume shared understanding

Over a decade ago, a project manager and my work approached me with a proposal. You see, we had a minor quality problem, and he wanted us to do better. Some background: We were working on an internal data management product, a crucial tool that was used across many deparments for key business functions. We were releasing new versions three to four times each year, and had been consistently…

Better Table Tests in Go

Table-driven tests are a cornerstone of good unit testing in any language, Go included. They allow us to group related test cases, making it simple to cover numerous inputs, outputs, and edge cases in a concise and readable way. When you have functionality that needs to be exercised in a variety of ways, a table test is often the right tool for the job. The Standard Approach A common and idiomatic…

Error assertions

When writing a Go test, don’t just assert that an error occurred - assert that the error you have is the one you expect. I’ve seen a bunch of test code recently that simply asserted that an error happened: g . Expect ( err ) . To ( HaveOccurred ()) (I’m using gomega for my assertion library here, but I’ve seen this pattern in tests using testify as well as in tests using no assertion library at…

Browsers and WSL

The integration between the Windows Subsystem for Linux (aka WSL) and Windows works spectacularly most of the time, but occasionally things get a little troublesome. One such case was a change in browser behaviour that I noticed recently after upgrading to a new laptop. On my old machine, I had an Ubuntu environment running under WSL2 and any time a browser was needed, it would open in the Windows…

Factory methods and functions

As discussed last time, usually a proper constructor is the best way to create a new instance . But what do you do if a constructor doesn’t fit your needs? This might happen if you need to do something asynchronous during creation - and C# doesn’t have asynchronous constructors. In C#, your declaration might look like this: public class ImportOperation { public static async ImportOperation Create…

Using Constructors

The API we presented last time had a problem - it required users to remember to call Initialize() before an instance could be used without problems occurring. Sometimes this is called temporal coupling , because the ordering, or timing, of calls need to be just right. In C#, our object may have a declaration like this: public class ImportOperation { public ImportOperation () { // ... elided ... }…

An Inconvenient API

Imagine that you’re working on an unreleased project, and you discover a need to extend one of your custom types. There’s some complex initialization required before methods will work properly. You end up with client code that looks like this in C#: var operation = new ImportOperation (); operation . Initialize ( client ) or like this in Go: var operation ImportOperation operation . Initialize (…

Method Archetypes

How do you decide what methods or functions to write as you’re coding? Here’s a technique that I learned about years ago that guides you towards software with great reusability and easier testability. As far as practical, I try to write methods and functions that conform to one of three specific method archetypes: Queries , Commands , or Orchestrations . Aside: I no longer remember where I learned…

A bash puzzle, solved

When we finished last time, I’d just run a simple bash script with some surprising output. $ ./provision.sh --XISTS = --false resource group exists Seeing the -- show up at the start of the line is odd - where do those characters come from? I expected to see -- at the end of the line, not the start. What’s happening? The -- showing up at the start of the line is actually written last , overwriting…

A bash puzzle

Here’s a bit of a puzzle - all of the clues in this post, and the answer will follow in the next one. It starts with trying to write a simple bash script to create an Azure Resource Group. Working in my Ubuntu WSL2 environment, I wanted to write a bash shell script that created an Azure Resource Group if a group with that name doesn’t already exist. The idiomatic way to test whether a resource…

Improve your troubleshooting by aggregating errors

In the early days of the web, circa 1995 or so, it was common for the forms on websites to return a single error on submission, identifying only the first field that needed attention. This resulted frequent failed submissions as users would only be able to fix one thing at a time. To say that this made for a laborious and frustrating process would be a massive understatement. Some of those…

Improve your troubleshooting by wrapping errors

When managing errors in your code, help out your future self (and anyone else who will be supporting your code in the future) by doing more than the simplest possible thing. A common approach in Go code is to detect an error and simply pass it up the chain: err := manager . Process () if err != nil { return nil , err } We relearned while working on Azure Service Operator (ASO) that this approach…

Keep your promises

One of the best ways to disappoint someone is to break a promise - and this applies both to the software we write and the applications we use as well. When running tests, the Go compiler has a -json option allowing you to request output in JSON format. This is useful as it allows those test results to be easily processed by a separate application. The implied promise is that using the -json option…

When are you done?

How do you tell when you are finished working on a change you are making to the code on your current project? Do you decide you are finished because you are bored and tired? Or are you done because the work is tedious, and every change is time consuming to test? Is it done because you are impatient to get on to the next task and you just can’t be bothered to invest more time in this one? These are…

Fixing GitHub Authentication

Returning to a project that had lain fallow for several months, I found I was unable to push changes from my work in progress branch up to GitHub. When I tried to push my branch, I got the following error: C:\GitHub\wordtutor\ [ feature/update-packages-dotnet6 + 2 ~0 -0 ! ] 11 : 36 : 24 PS > git push --set-upstream origin feature/update-packages-dotnet6 remote: Support for password authentication…

Sharpen The Saw - August 2021

In today’s post: An obsession with primitive types can be a problem; Ways to refactor to introduce semantic types; WSL now supports GUI apps and it’s wonderful; Lessons from Japanese martial arts; How to prepare to break a habit; Spam blogs; Why your sleep excuses are wrong; Morning habits and happiness; and Phil Haack’s most excellent CodeMania 2012 keynote. Sharpen the Saw used to be an email…

Gesticulation Driven Development (GDD)

Imagine this: While tackling a subtle bug in a complex application, you make a simple change that you think will address the issue. But when you run the tests, a whole bunch of seemingly unrelated tests start to fail. You reverse the change, and they pass again, so it’s most certainly your change causing the problem. You reapply your fix, run the tests, and a distinct set of unrelated tests start…

Magpie Driven Development (MDD)

Imagine this: Your team has a big release date coming up next month. This is a big deal, as you’re releasing a bunch of new features just prior to the industry’s biggest trade show. This morning you found out to your surprise that one of your senior developers has just about finished developing a critical new web-service. Using Rust. Literally every other component in your back-end systems has…

Sharpen The Saw - July 2021

In today’s post: Building a better UI by decomposing CRUD screens; check your certificate expiries in your CI builds; Windows 11 is coming; Visual Studio 2020 is 64 bit; INVEST in your backlog; 7 virtues of software design; PHPs Git server was hacked; Malware targeting Windows containers; FreeBSD’s close call; Space X torment; and What’s new in C# 9. Sharpen the Saw used to be an email newsletter…

Rockstar Driven Development (RDD)

Imagine this: You come into work on Tuesday morning after a four-day holiday weekend to find a cryptic email from one of your best developers describing some changes they just checked into your main branch. In the approximately 112 hours since you thought everyone went home on Thursday afternoon, they’ve been on a kind of technological bender, ripping out the workflow engine your team has…

Distraction Driven Development (DDD)

Imagine this: You’re working a critical new feature, one your team anticipates will not only be really popular with your existing users, but which will organically drive growth by attracting a large number of new users. While you’ve been working on this over the last couple of weeks, you’ve noticed a couple dozen minor issues that you fixed as you encountered them. Now your development work is…

Sharpen The Saw - June 2021

In today’s post: Avoiding shotgun surgery; why too many parameters is a bad thing; upgrading to .NET 5; Creating a DSL using a Source Generator; Common sense practices to avoid; Why people write bad code; Rethinking passwords; The curious case of the Great Suspender; The importance of checking in with people; and how reviewing a Strangers’ Code can make you smarter. Sharpen the Saw used to be an…

Promotion Driven Development (PDD)

Imagine this: You’re the manager of a development team and you normally give your developers a fair amount of autonomy. There’s a shared backlog of tasks and developers are free to select whatever they like. Your expectation is that they’ll work on a mix of bugs, features, and general product quality improvements – but you’ve noticed some of your mid-level developers are exclusively working on new…

Complaint Driven Development (CDD)

Imagine this: You are developing a new product feature, requested by one of your company’s most important customers. After nearly a fortnight of work, you’ve almost finished the work – a couple more days and it will be ready for release. This morning your manager asked you to temporarily drop that work so that you can urgently work on a different feature, for a different customer. When you look at…

Profanity Driven Development (PDD)

Imagine this: You’ve just started working on a new team and you’ve your first task, a simple bug fix to address a problem recently experienced by multiple customers. After pulling the code down onto your development machine, you’ve opened it in for the first time and you can’t quite believe what you’re seeing on screen in front of you. The code is bad. Everywhere you look, you see problems. Local…

Hype Driven Development (HDD)

Imagine this: You’re the manager of a successful development team and your CFO has just come back from a conference. She walks into your office, slams a magazine down in front of you on your desk, and announces that you’re reimplementing your entire product suite in Rust and Blockchain. Your company specialises in developing custom e-commerce websites for small businesses using WordPress, a…

The Other Development Methodologies

We’ve all heard of Test-Driven Development (aka TDD), and those of us who’ve been around the block a few times have no double heard of Behaviour Driven Development (BDD) and Domain Driven Development (DDD) as well. But have you heard of their dodgy cousins? In this series I want to explore a handful of these lesser-known development methodologies, exploring both what they are, and what you might…

Don't be that person

Nearly 15 years ago, I found myself with a particular problem at work. I felt like I was not being very productive, so I started closely tracking where my time was going. I used the emergent task timer from David Seah ’s Printable CEO collection as a way to keep track of what I was doing for each 15-minute interval of my day. I had some idea of what I might find, but tracking reality was the best…

Weapons of mass (privacy) destruction

It seems that the details of the eighteen people in New Zealand with positive COVID-19 tests have been disclosed, and officials are speculating that it may have been due to human error: “I have been advised by the Ministry of Health that at this stage it cannot be confirmed beyond doubt whether a deliberate leak was involved or if this was simply human error,” Chris Hipkins, who is also States…

Caching without Race Conditions

It wasn’t very long after my prior update on caching that a friend informed me that the code has a race condition. Yes, the same friend who persuaded me to update it last time. Worse, during a Skype call, we identified code that would outright fail for an independent reason. Here’s the code, for your consideration. Do you see the problem? I didn’t see it until it was pointed out to me. lock (…

Sharpen The Saw - June 2020

In today’s post: Reducing the scope of each pull request; rules for better powerpoint presentations; a welcome to C# 9.0; Chrome has a new feature to manage your tabs; we’re all bad programmers; five ideas for eliminating bad code; thunderbolt ports are insecure; an unattributable data breach; kudos for Ashley Bloomfield; and The Clean Code Talks. Sharpen the Saw used to be an email newsletter of…

Automated Inbox Cleanup with PowerShell

This week I discovered that my Inbox had ballooned to over 20k messages. It was in desperate need of a clean-up. Here is how I automated that clean-up, getting it down to just under 1500 messages. How did this happen? I normally use the Windows 10 Mail app, configured to download just the most recent month of messages. This keeps the number of visible messages down, and I can always open the full…

Don't Gloss Over Complexity

We have a poor habit in the tech industry of glossing over the complexity of things. Sometimes this is done deliberately, but very often it happens accidentally, as the result of skipping due consideration, or at a subconscious level. I saw this play out on Twitter this week in a scenario that’s all too common. An early career developer, enthusiastic about what they know and eager to share that…

Improved Caching

After our recent introduction of caching, I had an interesting conversation with a friend about the way I’d written the code. He was persuasive that the approach I’d taken had some significant issues and that it was worth taking the time to address them. The AzureSpeechGenerator class is doing too much. In violation of the single responsibility principle, the class has multiple conflicting…

Sharpen The Saw - May 2020

In today’s post: How to choose between a static factory method and a constructor; What not to do with async; Meeting with Skype for free; How to stop wasting your time; What you don’t know about names; New static analysis features in GCC prove their worth; Making your C# more functional; Coding bootcamps for veterans; and, How to crash an airplane. Sharpen the Saw used to be an email newsletter of…

Caching Speech

If you’ve been playing around with maintenance screen and the speech integration that we completed last week you may have noticed that there can be a noticeable lag between the time you press a play button and when you hear the speech. The lag is caused by the necessary round trip to Azure Cognitive Services (henceforth ACS) to do the conversion of text to speech. In my testing (using service…

Maintenance & Speech

With our speech infrastructure in place, our next step is to hook it up with our existing maintenance screen. This will allow our users to test out pronunciation as they make changes. We’ll add a play button next to each of the individual fields in our form: To make room for the buttons on the righthand side of the data entry fields, we add an additional column to our grid just to their right. We…

Speech Middleware

Now that we’ve modified our Redux store to support middleware , we have the foundation needed to integrate speech synthesis into the main flow of our application. Leveraging the ISpeechService abstraction we previously defined, the implementation falls out relatively easily, though (as we’ll see) there are a few wrinkles that will need to be followed up. public SpeechMiddleware ( ISpeechService…

Redux Middleware Implementation

Based on the interfaces we defined last time , let’s integrate middleware functionality into our existing Redux store. This will lay the foundation we need for asynchronous speech generation. There’s a whole heap of code changes in this implementation, so instead of a blow by blow description of every piece, I’ll give you an overview of the highlights by following the flow of data - as usual, all…

The Liskov substitution principle goes both ways

The Liskov Substitution Principle (or LSP) is one of the big five SOLID principles and one that is often poorly understood. Yet, ignorance of the LSP can lead to subtle, expensive, and sometimes embarrassing bugs. The LSP can be stated in many ways, from the original formulation (which has to be regarded by non-mathematicians as dense to the point of being cryptic): Let phi(x) be a property…

Redux Middleware

At this point in the development of the WordTutor, we need to properly incorporate speech generation into the application. We could hack and glue it into place on top of the existing architecture, or we can integrate it into the existing structure in a clean way. There are pros and cons either way - but my experience is that nasty code inevitably becomes a curse on future developers. Let’s do it…

Sharpen The Saw - March 2020

In today’s post: Why Code Katas are important and how do do them well; the new Microsoft Edge is available now and coming to a PC near you; Yori is CMD reimagined; improving email one message at a time; why some people are chronically tardy; Intel patches CSME only for researches to find it’s still broken; the consequences of undocumented features; improving your CLI Prompt; and a talk on Unit…

Always review code you copy

Recently a friend of mine noticed some code in a book that was, shall we say, considerably sub-optimal. It’s worth looking at the code to see how both the performance and readability of the code can be easily improved. Here’s the original code: [ Benchmark ] public IDictionary < string , int > Original () { var counter = new Dictionary < string , int >(); foreach ( var word in WordListLoader .…

Speech API

For the WordTutor application to work, we need to be able to read words (and letters) out loud to our student. To power the speech synthesis, we’re going to integrate Azure Cognitive Services into the application. Azure Speech API Setting up access to the Speech API within Azure Cognitive Services is relatively straightforward. Rather than repeating the details here, I’ll just point you to the…

Dumb Transfer Objects

An anti-pattern variant of Data Transfer Objects (DTOs) where the objects are forcefully deprived of all possible functionality, even for matters that are directly relevant such as construction, serialization, and (first stage) validation. Some believe that data transfer objects must only contain data and that there must be no behaviour declared on the type at all. Their understanding of the…

Sharpen The Saw - February 2020

In today’s post: how to write better git commit messages; a cool debugger trick for Visual Studio; a new approach for producer/consumer programming in .NET Core 3.0; how to focus in on a part of a data structure; an alternative to a regular to-do list; how to apologize; protecting users against poor password choices; the NSA does the right thing; the day when someone discovered they had too many…

Logging Implementation

To implement the logging interfaces described earlier, there are some issues we need to consider. There are two different usage patterns we need to support, plus we need to support concurrent use, and avoid code duplication. Usage Scenarios The first scenario is when a method controls the context of its logging; the logger reference it needs is immediate to hand and easily used. Different parts of…

Impossible Numbers

There’s a very clever piece of design advice that I was taught at university that seems to be less well known than I expected. A computer science lecturer of mine once said: There are ony three possible numbers in computer science. Zero, One, and Infinity. Unfortunately, I can’t remember which of my lecturers it was. If you were in any of my classes - and you recognize the quote, please let me…