Lets talk about events. We want to write some code that reacts when something happens. This pattern exists in many domains from UI programming to IoT to serverless. What do the programming patterns for this look like today in #dotnet and #csharp?
We create a button (imagine this was referenced by a form or some UI component), then hook up an event handler and write to the console when a button click event happens. This is the one of the most popular and idiomatic event handling paradigms in .NET today.
It's existed for years and years in many different programming languages and domains. There may or may not be data associated with these events.
What APIs can you use to represent an event? Lets take a look. First the O.G. EventHandler. Built in to .NET since 1.0, probably inspired by VB 6 (I'm sure somebody will fact check me on this). Many of the existing APIs in use these.
The big downside with exposing events like this are NO async :(. There's no async event handler type so its impossible for callers to know when the callback is actually done. Many UI stacks in .NET use async void event handlers and custom synchronization contexts to manage this.
Then came IObservable<T> which was born in .NET by @headinthebox but it's more popular in Java than it is in .NET. Reactive programming is an alternative programming model for events where you treat events from the same source as a single stream.
Button click looks like this with Rx. Clicks is a stream of click events. Where this really shines is when you use the Rx operators/combinators, they make complex tasks easy to implement (ever had to implement debouncing manually??)
This is a paradigm shift. reactiveui.net is an entire library built around these patterns and it shows what the mental shift looks like going from event handling on UI elements to streams of values.
There are a ton of other ways to represent evented APIs, for example the new minimal APIs in .NET 6. This pattern is passing a delegate to a method overload (MapGet in this case).
One benefit over the EventHandler property approach is that it can support overloads and callback shapes. Want to support both sync and async delegates? You can add overloads to do so (more parameters? multiple generic arguments etc). Methods are more powerful for API evolution.
Other APIs in the BCL also just take a straight up calback (like timers). This API also overlaps callbacks and doesn't do back pressure, that's for you to manage.
The above models are all callback based. You pass some information about which event you want to subscribe to, and you pass a function that will be called back in the future. You do not control how data is pulled out of this event stream (there's no concept of a stream exposed)
IAsyncEnumerable<T> (originally came from Rx) but was recently added to the .NET 6 and to the C# 10. It's the only option that gives the user access to an event stream in a way where they control how often events are pulled from the queue.
It also side steps the sync/async problem since the user is the one that is in control of consumption (well I guess it means you're always async because events are async :)).
Going back to our button click example, this is what it looks like with async enumerable. I'm not sure if we'll see this pattern emerge to replace events and I'm not sure that it's easier but it does solve certain class of problem with events.
The one awkward thing so I've found with this so far is that concurrent events need to be fired up on different tasks. Which one of the below do prefer?
I expect the left because it’s how we’ve been trained to handle events from the get go
I want you to go look at all of your callback based code and see if pull based vs pushed based is a better approach.
• • •
Missing some Tweet in this thread? You can try to
force a refresh
Our hackathon project this year was working on making it easier to incrementally migrate large ASP.NET projects to https://t.co/4PmXMQN7SX Core. Here's the MVC music store app: #dotnet#aspnetcore
Most pages are running on .NET Framework but the shopping cart is managed by ASP.NET Core. This application is 10 years old and using both technologies at the same time, sharing source where possible.
This is made possible because both applications are running in the same IIS pipeline using different modules. It's sharing session and auth with the existing application without many changes to it. The ASP.NET Core application is part of the larger application.
ConcurrentDictionary - Good read speed even in the face of concurrency, but it’s a heavyweight object to create and slower to update.
Dictionary with lock - Poor read speed lightweight to create and “medium” update speed.
Dictionary as immutable object - best read speed and lightweight to create but heavy update. Copy and modify on mutation e.g. new Dictionary(old).Add(key, value)
Reflecting on my immigration journey this morning and for anyone else in the same situation it was:
F1/OPT 1 year (student visa) -> H1-B 5 years (work via) -> Green Card 7 years (permanent resident) -> Citizen yesterday. No more immigration anxiety 😅
Since being on a student visa I've always been worried about not being able to enter the US for some random reason or the other (plus being a black immigrant). Travelling with an excess amount of paperwork to prove you belong here.
When I joined Microsoft in 2008, there were huge layoffs and I was sure I was going to be in that set of people. Why not lay off the new employees (and immigrants at that)? It didn't happen and I was thankful. Microsoft sponsored my H1-B and Green card.
The biggest problem with async await is the “colored functions” problem brilliantly explained by this article journal.stuffwithstuff.com/2015/02/01/wha…. It’s a never ending problem because everything can’t be async and it’s viral. It’s not a new problem though, it’s always been this way.
JavaScript has an easier time because blocking always meant you’d destroy the browsers UI thread. That model naturally made it nicely non blocking on the server side.
Then golang chose a different direction and did go routines. Not conceptually different but the big thing it solves is the “virality”problem. Java’s Loom is also headed this direction. It’s easy to say that .NET should follow but it’s never easy…
High level IC (individual contributors) should have a support group. Managing the transition from being “just another engineer” to being a “force multiplier by working through others” is tough. Talking to others that have managed that transition is calming.
Your role suddenly goes from cranking out lots of code to mentoring/growing others, and shaping the team culture. Often times companies train managers but don’t formally prepare ICs for those roles. Learn on the job, become a great people person!
One of the hardest things is measuring your impact. You don’t have anyone reporting to you, and you are no longer being judge solely on your technical abilities. What did you do at the end of the year? It can feel very abstract at times.