Monthly Archives: December 2021

Happy New Year?

The current state of affairs

In 2020 I learned the meaning of the English expression Busman’s Holiday, and it generally applies to software developers that write code on their free time, but especially so during a pandemic with abundant remote working. Putting that aside, I will make some predictions of what will be happening over the coming year.

Predictions

The Pestilence

Given how popular the Omicron strain has proven, my guess is that everybody will have had Covid, and the patience for government measures will have grown thin, especially given the attitudes with which they flout the rules within the government itself. If Labour takes power, of course this can all change and we can be heading for more lockdowns.

The Industry

Despite lockdowns and the inevitable destruction of the service industry (yes, for good reasons in managing the spread of the virus, but let us be honest with the consequences) the IT industry has fared reasonably well. As long as I have lived in this country there has been a general election every two-and-bit years, and we could be looking at one of those again, and in a run-up to that, Rishi Sunak will want to keep money pumped into the system, meaning IT people will most likely still do quite well for a bit longer.

The Great Resignation

From the discussions around recruitment before the above variant gained popularity, there seemed to be two main streams, people that want to work remote full time, and people who want to work in a hybrid capacity, where you do meetings and collaboration in the office, and focussed work remote – if not at home at least in a co-working space closer to your home. The crutch used by weak leaders to manage people – counting bums in seats – will probably need to be replaced by some kind of outcome-based measurement. Luckily that ought to align quite well with company targets. No company has a slide in an AGM saying “well revenue is down, profits are down but luckily we have 99.5% occupancy of our desks“, the goal is to make money, and with the right type of goals within an organisation you can have department and team goals that in some way works towards the overall business goals, but of course measuring the right thing is key, so – yes – it is harder than just counting empty desks.

My thinking is that if the pandemic calms down, we will se a subset of organisations that are unashamedly on-prem only, and those that look for work that is on-prem only will go there, but I suspect that it will be harder to hire for those positions.

The Continuous Delivery

People insist with this Agile malarkey, and even though “Scrum, but…” remains the dominant methodology, companies are starting to read Accelerate and realise that they need to move faster, so gradually obstacles are being dismantled. Management structures are tweaked, project management and budgeting is being replaced with product and portfolio management. Coordination exists in companies already. Organisations that are famously agile say they struggle to coordinate cross-cutting changes across an organisation, but in old enterprises, that coordination work is the thing they do well, because in their current day-to-day even the most trivial piece of work cuts across several teams and needs careful planning and second-guessing to be delivered safely. The big differentiator is to change the internal structure so that for 80% of changes, a single team can plan, test, construct and monitor features completely independently, while leaving some version of the existing structure to deal with the subset of changes where you still need to coordinate. If you achieve that, you are in a vastly better place than before.

The Hardware Shortage

Have you tried buying a graphics card? A car? Well, you may have noticed that there is a supply chain crisis in the world. US container ports are struggling now and what originally started with the double whammy of Chinese New Year and OG Covid shutting down electronics suppliers, got worse as there was a supply shock when the pessimistic demand prognoses turned out to have not accounted for stimulus checks inducing demand globally, and more recently there i are geopolitical issues when one of the main semiconductor suppliers globally, Taiwan Semiconductor Manufacturing Company (TSMC) is situated in region on the brink of war while at the same time Intel are struggling to produce any advanced processor nodes in their own fabs, even though they now are producing a competitive line of processors again.

My prediction is grim here, but let’s pretend like things will go well. I don’t think you should buy anytihng in 2022 if you can avoid it, which has been my advice from March 2020 onwards, that hasn’t changed.,

The Crypto Scams

Just like with drug trafficking and modern slavery, you can make a lot of money with cryptocurrencies and NFTs, and you can already see that the biggest profits are made when people are robbed of their coins.

As you dream up your practical use cases that will finally be the problem that crypto solves, just remember this: Like with all applications of cryptographic signing, the time it takes to encrypt or decrypt something is part of why it works, why it is secure. You will never have a world where these transactions are fast and secure. All exchanges for cryptocurrencies that trade fast circumvent a number of supposed features of a distributed ledger. There is no “it will be faster, eventually” unless you are prepared to sacrifice some of the key selling points.

Luckily China has decided that crypto currencies are inherently decadent and are clamping down on miners, and if western utilities start going after those that steal electricity with more zeal, we could start to see positive change.

Don’t forget that NFTs, Bitcoin and Eth singlehandedly is destroying the Paris Accord on climate change, You can heat a typical American home for six weeks on the energy required for one (1) bitcoin transaction. As computers become faster, this will gradually be worse as well.

Conclusion

As with any arbitrary point in time, the time immediately after will not be drastically different than the time immediately preceding it, so there will be much of the same next year, but I have still tried to make some statements that are specific enough that we can go back in a year to see what I got right and what I got wrong. Happy New Year!

Async Enumerable in C# / .NET 6

Background

In recent times Microsoft have begun to performance test their web platforms. Whilst previous generations of their .NET framework and ASP.NET web platform had prioritised ease of development over performance quite dramatically, the latest generation ASP.NET Core performs quite well, on Linux no less.

After inventing the async/await model of abstracting away callback hell when writing asynchronous code, the New Microsoft, the Ones That Care About Performance realised that people will just allocate all the RAM in the universe if you let them, and that whilst engaging in the now very common practice of using ASP.NET Core to create web APIs that produce data as json payloads, users would mercilessly just serialise massive payloads of List<T> into one massive string that they would shove out onto the network, or have server endpoints that would accept arbitrarily large strings off of the Internet attempting to coerce into a List<T>, meaning ASP.NET Core services could be knocked offline by supplying a ludicrously large payload, and performance could be a bit erratic at times, depending in the size of data the user was requesting.

So what do they do? Well, a couple of things, but one of them is to introduce the concept of IAsyncEnumerable<T>, an asynchronous enumerable, that supports cancellation, clean exception handling and stable performance for handling variably sized payloads without suffering unpredictable performance impact.

The goal today is to successfully serve a payload in ASP.NET Core 6.0, and to deserialise it in a client application, also in .NET 6, serialising onto streams, deserialising off of streams, processing data without allocating massive payloads, also – beginning to receive data right away rather than to wait before the full payload has been buffered in its entirety in various services along the way before eventually reaching the end user.

Physics and leaky abstractions

Just to preface this – just like the async /await doesn’t fundamentally change physics, i e there is no getting away from the fact that you first kick off an operation and basically schedule code to be run when that operation has finished, leaving you to do other things. I.e. since your code will actually return to the caller directly after you’re scheduled the first async operation, the code has to return something in addition to the normal return value, it has to return a handle through which you can access the state of the function, and – once the operation has completed – the return value. This way the surrounding code has a chance to deal with the asynchrony but most of the time just pretend that the code is synchronous.

You see, if the human squishy brain cannot fathom mulithreading, don’t let me get started on asynchrony.

So with a normal asynchonous function that returns a scalar, the caller receives a System.Threading.Task that encalsulates the asynchonous state and eventually the return value. The async keyword lets you pretend it isn’t there and write synchronous code , as long as you put an await in before the asynchronous call is made.

Contagion

You’ll notice though, like with monads, that when you’ve started wrapping your return values in Task<T>, it’ll go all the way across to the other side of the application, i e if your database code is asynchronous, the repository or other database access layer topology you have will be asynchronous too, and then you turn around and then you find that it has spread all the way to your ASP.NET controller. On the plus side, the ASP.NET controller automagically injects a CancellationToken that you can send all the way down to the database and get automagic cancellation support for long running queries if people refresh their page, but that’s an aside.

The point here is the contagion. You can attempt to force things to be different with GetAwaiter().GetResult() to block a thread while it’s evaluating, but that is very dangerous performance-wise, better to just let it spread, except for in places where Microsoft have been lazy, such as in Validation and Configuration, cause clearly when it would mean work for them it’s “not necessary” but when it’s eons of work for us they are fine with it. Our time is free for them.

Anyway, I mean it makes sense that the abstraction must leak in some cases, and IAsyncEnumerable is no different. Any one return value would fly in the face of the whole streaming thing. So awaiting a task doesn’t really make sense. Instead it’s iterators all the way down. Everywhere. Each level yield returns to the next, all the way down the chain.

Dapper allegedly comes with support for IAsyncEnumerable, but at the time of writing there is zero documentation supporting that allegation.

You can simulate that by writing this bit of code:

    public static async IAsyncEnumerable<T> QueryIncrementally<T>(this SqlConnection conn, CommandDefinition commandDefinition, CommandBehavior behaviour = CommandBehavior.CloseConnection)
    {
        await using var reader = await conn.ExecuteReaderAsync(commandDefinition, behaviour);
        var rowParser = reader.GetRowParser<T>();

        while (await reader.ReadAsync())
        {
            yield return rowParser(reader);
        }
    }

From that you can then pass the payload up iterator style, yield returning all the way up, until you get to the controller where you can declare the controller to return IAsyncEnumerable and the framework will handle it correctly.

Obviously as you cross the network boundary you have a choice in how to proceed, do you want to receive the data incrementally as well, or do you want to wait for all of it to arrive?

Since you made such a fuss in the first API, we will assume you want the consuming side to be as much work.

    private static async Task<Stream> GetStream(HttpClient client, string endpoint)
    {
        var response = await client.GetAsync(endpoint, HttpCompletionOption.ResponseHeadersRead);
        var responseStream = await response.Content.ReadAsStreamAsync();
        return responseStream;
    }

    public static async IAsyncEnumerable<T> HandleGetIncremental<T>(this HttpClient client, string endpoint)
    {
        var stream = await GetStream(client, endpoint);
        var items = JsonSerializer.DeserializeAsyncEnumerable<T>(stream, CreateSerializerOptions());
        await foreach (var item in items)
            yield return item;
    }

And then, of course, you yield return all the way up to the next network boundary.

Is this ready for prime time? Well, in the sense that Jay Leno was ready for prime time when he ceded the Tonight Show to Conan O’Brien, but everybody would probably like some more pace and less awkwardness.
Apparently letting lambdas yield return is on its way, and hopefully that can make it easier to pipe an IAsyncEnumerable through one API to the next, easily adding some filter or transformation mid flight rather than the incessant await foreaching that is now necessary.