Convenience Methods, Golden Hammer and Boat Anchor

According to Wikipedia, Golden Hammer anti-pattern is a cognitive bias that involves an over-reliance on a familiar tool. Boat Anchor anti-pattern occurs due to developer’s belief or assumption that a piece of code is kept in the code base, assuming necessary in future (next week or next month), even though it is not mentioned in the requirement.

On the other hand, Convenience Methods are from any language or framework that provide similar functionality with minimal tasks. Convenience Methods mostly come with increased verbiage.

As beginners mostly we start with “Convenience Methods” in any given language or framework – if exist. The caveat is that overfamiliarity of the convenience methods sometimes ends-up in Golden Hammer anti-pattern. One classic example is the usage of convenience methods such as GetAsync(), PostAsync() and PatchAsync() in ASP.NET HttpClient.

Convenience Methods and Golden Hammer – Case Study

Due to the over-familiarity with such convenience methods, such as PostAsync(), developers assume that, this is the only way to make a POST call in the HTTPClient. This might be OK for 90% of the scenarios however, there may be some exceptional cases where the the sole usage of PostAsync() might not be enough. One such case I came across this is when we use Named HTTPClient and when we try to add custom headers and TPL.

Recently I was working “Update Range” REST API in Microsoft Graph, which requires a “Workbook-Session-Id” header. The idea was to update a number of cells with given value via this API and get the calculated value from “GET Range” API. Since the UpdateRange API certainly involves a delay and since there are a number of cells to be updated – the decision was made to use Task.WhenAll() and passing the tasks to update the ranges. With this we can update all the ranges with certain degree of parallelism and perhaps reduce the response time of the custom API we’re building.

However since this API requires the above mentioned header to keep the changes to the sheet persisted using a code as below to keep using a Task which has PostAsync() insider Task.WhenAll() would be problematic since the _httpClient is a singleton object (if injected through AddScoped() or AddSingleton()).

public class UpdateRange: IUpdateRange {
  private readonly HttpClient _httpClient;

  public UpdateRange(HttpClient httpClient) {
    _httpClient = httpClient;
  }

  public async Task ExcecuteAsync(string accessToken, string siteId, string workbookPath, string workbookName, string sessionId) {
    _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
    if (!_httpClient.DefaultRequestHeaders.Contains("workbook-session-id"))
      _httpClient.DefaultRequestHeaders.Add("workbook-session-id", sessionId);
    // Construction of updateRangeContent object and url
    var response = await _httpClient.PatchAsync(url, updateRangeContent);
  }
}

Even though AddTransient() would solve this exact problem, we don’t need to focus on that since the topic is about convenience methods.

In ASP.NET PatchAsync() is a convenience method for SendAsync() method. PatchAsync() accepts HttpContent object and SendAsync() accept HttpRequestMessage object. With HttpRequestMessage, the custom header can be added to the request without adding it to the singleton _httpClient object itself and causing problems.

This is one classic case where using a convenience method, PatchAsync() causes problem, even though it might increase the readability.

Boat Anchor Anti-Patten in this Context

While refactoring, sometimes after realising a fact that is mentioned above, one might assume to keep the “pre-convenience” method such as “SendAsync()” instead of rewriting them with convenience methods.

However it is not necessary, refactoring must increase the readability and maintainability of the code. So convenience methods must be always considered whenever possible since they mostly provide “Parameter Object“.

Epilogue

The struggle is real as a beginners – particularly as a beginner of a framework. Frameworks also provide ways to overcome such problems as .NET Core provides “AddTransient()” in this very classic case. Reading the documentation and if possible the reference source code is always beneficial. It is important to fix the root cause of the problem instead of fixing the symptoms. In my personal opinion, using “AddTransient()” is such way to fix the symptom.

Knowing pre-convenience methods such as “SendAsync()” will surely help you to write best code by proving a deep understanding on why does a convenience method exist. However one should be aware of both Boat Anchor anti-pattern and also must avoid Golden Hammer ant-patten. Avoiding anti-patterns is very important.

Happy Coding!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s