.NET R&D Digest (December, 2023)

2023 was a long year with a lot of surprising (for instance, AI boom), well expected (like new release of .NET 8) and a bit sad (cancellation of Project Tye in favour of Aspire) events. Some of these events put a “dot” and some raise a new beginning. Among these events were regular releases of .NET R&D Digest issues for every month except the December, which I am intending to fix now.

This issue includes bits of stories, software development practices, C#, diagnostics, performance, low level optimisations, AI and of course — .NET.

Have a nice read!

Developers Story

  1. A failed experiment with interceptors in C# 12 and .NET 8 (by Andrew Lock)
    C# is great and user friendly programming language. It provides a lot of shortcuts to make the code compact and encourage usage of the right programming patterns. However, it also hides some of the internal details, which might lead to an unexpected result. In this post Andrew Lock shares a story of a failed attempt to use a brand new feature of .NET 8 (interceptors) to improve performance of the enum types. The post is a good example of why you need to understand how everything works under the hood.
  2. Building a bare-metal bootable game for Raspberry Pi in C# (by Michal Strehovský)
    Recent versions of .NET made a huge step towards support of high performance and low-level scenarios, especially, introduction of NativeAOT. But how “low” is low? In this post Michal Strehovský describes how you can create a bootable game in C# by carefully reading the standards, some math, translating a few snippets from C++ and hacking into .NET SDK build process (looks pretty complex). The post is an interesting demonstration of how creative one can be and how far .NET made since.NET Framework times.
  3. 10 Years of Building Akka.NET (by Aaron Stannard)
    Building successful, long standing product is a tremendous effort — every year some new software comes up, some technology makes a break through and some libraries you were relying on becomes obsolete and in between of this chaos a product which has to evolve and solve problems. In this post Aaron Stannard shares his 10 years of experience of developing Akka.NET as a mix of stories and guidance. All extracted from a long product journey.

Software Development

  1. Canon TDD (by Kent Beck)
    As all of software development approaches, TDD has many interpretations and even more implementations (which seems quite natural, because every team and every project are unique). However, it is always great to read what is the canonical way of doing things. In this post Kent Beck gives a dense and pragmatic description of what canonical TDD should look. Besides the explanation, the post includes a list of common mistakes and a nice flow chart to visualises the whole development process.

.NET

  1. C# Advent: The Joy of Immutable Update Patterns (by Steve Cleary)
    C# has reference and value types. Both of these are mutable by default. This is a reasonable default because in most of the cases it is what we need — to change the state of an object. However, there is another way, a way to write programs which do not mutate state of existing objects but instead create new objects based just on the input. Recent versions of C# made a lot to support this kind of programming style. In this post Steve Cleary demonstrates how you can use latest language feature to write “pure” and immutable code in C#.
  2. Integrating OpenAI Image Generation into a .NET Application (by Rick Strahl)
    Modern AI models are great productivity tools, they can create code snippets or generate high quality images. However, they are still separate tools, which you need to somehow integrate into your workflows. The good news, most of them have an API, so the integration can be quite seamless. In this post Rick Strahl describes how you can integrate image generation AI into your application. The post is very detailed and covers everything from the setup to pieces of code for the UI components.
  3. Avoiding flaky tests with TimeProvider and ITimer (by Andrew Lock)
    .NET 8 has been released more than a month ago but there are still so many features to explore. In this post, as a continuation of a great series, Andrew Lock describes a new feature of .NET 8 designed to give .NET developers a control over the flow of time (at least for testing purposes) through TimeProvider abstraction. As usual, the post is very practical, with concrete examples and detailed explanations.
  4. String Interning – To Use or Not to Use? A Performance Question (by Sergiy Teplyakov)
    In .NET when you want to display something on the screen you need a string. If you want to parse user input — it also done using the strings, and to be honest, a lot of non-user things (for instance, serialisation to JSON) also requires strings. Strings are everywhere and in many cases they are not unique, which makes them good candidates for caching. In this post Sergiy Teplyakov describes an interesting case when using native string.Intern functionality turns to be a bottleneck which (despite the common wisdom) can be improved by writing your own implementation.
  5. Behind [LogProperties] and the new telemetry logging source generator
    Enriching logs with [TagProvider] and ILogEnricher (by Andrew Lock)
    Everything is .NET can be transformed into a string, including objects of course. However, the quality of such transformations is questionable because sometimes what we want is to get object properties (especially during logging) but instead we receive a type string. And sometimes, we need a list of properties but without any kind of PII (personal identifiable information). Well, at least for logs these are not problems anymore. In these posts Andrew Lock demonstrates how to use new source generators introduced in .NET 8 to automatically generate code to efficient logging of object properties, including a smart filtration of PII fields.

Diagnostics

  1. Be Aligned! Or how to investigate a stack corruption (by Christophe Nasarre)
    It is a common situation when the well tested code starts to fail without any obvious reason and you need to dive into it line by line verifying one hypothesis after another, even if they are a bit crazy. The ability to perform this kind of research is what is called “debugging skills” and these skills are best learned by experience. In this post Christophe Nasarre describes an interesting case of stack corruption which occurred in a previously working C++ code. The post is a good demonstration of approaches you can take when investigating this (and other) types of problems. Don’t be afraid all the C++ code is pretty straightforward and requires no special knowledge.
  2. Diff Debugging (by Martin Fowler)
    It is a quite well known saying that “debugging is an art” and it has a lot of truth in it because a major thing of traditional art is an ability to take something usual and regular and show it from a new and sometimes unexpected side. In this small post Martin Fowler describes a “Diff Debugging” technique, which includes usage of a well known search approach to find the commit which causes a regression or an issue.

Performance 

  1. Four Kinds of Optimisation (by Laurence Tratt)
    Application performance is a characteristic which greatly depends on how program is used, where it is used and how often it is used and many more factors, which help to understand and define the “optimised” state of the program. In this post Laurence Tratt describes the four kinds of optimisations you can apply to program improve performance. Besides the description of the approaches, the post is full of insights of how to approach application optimisations, how to think about performance and common traps for developers.
  2. CPU Affinity: Because Even A Single Chip Is Nonuniform (by Mark E. Dawson, Jr.)
    Modern CPU hardware is a combination of heuristics, specialised units for operations and calculations and of course, kilometres of communication lines. Still, when we think about CPU performance we tend to see the CPU as a single unit with some rules related to caching, number of cores, available instructions and so on. Which apply to it as a whole. What we don’t expect, is that assignment of threads on different cores of the same CPU might result in performance change. In this post Mark E. Dawson, Jr. describes what CPU affinity is, why it can introduce a difference between cores on the same chip and demonstrates how correct affinity assignment can result in a measurable speed up.

Tips & Tricks

  1. Weak events in C# (by Gérald Barré)
    Event handlers is one of a few things which might cause a memory leak in managed code. In this small tip Gérald Barré demonstrates how you can create a simple wrapper class which would make event subscribers to use «weak references» and prevent memory leakage.

Leave a comment