<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.3">Jekyll</generator><link href="http://saebamini.com/feed.xml" rel="self" type="application/atom+xml" /><link href="http://saebamini.com/" rel="alternate" type="text/html" /><updated>2023-04-16T05:04:20+00:00</updated><id>http://saebamini.com/feed.xml</id><title type="html">Saeb Amini</title><subtitle>A technologist's thoughts on software, projects and the people around them.</subtitle><author><name>Saeb Amini</name></author><entry><title type="html">ChatGPT &amp;amp; Generative AI: A Descent into Dystopia or the Dawn of a Golden Age for Creativity?</title><link href="http://saebamini.com/chatgpt-and-generative-ai-a-descent-into-dystopia-or-the-dawn-of-a-golden-age-for-creativity/" rel="alternate" type="text/html" title="ChatGPT &amp;amp; Generative AI: A Descent into Dystopia or the Dawn of a Golden Age for Creativity?" /><published>2023-04-02T00:00:00+00:00</published><updated>2023-04-02T00:00:00+00:00</updated><id>http://saebamini.com/chatgpt-and-generative-ai-a-descent-into-dystopia-or-the-dawn-of-a-golden-age-for-creativity</id><content type="html" xml:base="http://saebamini.com/chatgpt-and-generative-ai-a-descent-into-dystopia-or-the-dawn-of-a-golden-age-for-creativity/">&lt;p&gt;I bet you can’t go a day without hearing someone rave about AI nowadays. Even if you’re not in the tech field, it’s hard to escape the buzz. ChatGPT and similar generative AI tools are popping up everywhere, have already started to impact people’s daily lives, and it seems like everyone is trying to find ways &lt;a href=&quot;https://twitter.com/clickup/status/1636149802730651650&quot;&gt;to use&lt;/a&gt; (&lt;a href=&quot;https://twitter.com/fabianstelzer/status/1638506765837914114&quot;&gt;or abuse&lt;/a&gt;) them.&lt;/p&gt;

&lt;p&gt;The possibilities have caused significant excitement and unease in people. The big question is: will this technology replace everyone’s jobs and send humanity spiralling into an apocalyptic abyss, or are we on the brink of a golden age?&lt;/p&gt;

&lt;p&gt;ChatGPT’s ability to converse like humans, has made a lot of people apprehensive and has made it easy to treat it as potentially sentient. However, consider that the concept of telling machines what to do, and that becoming easier over time with layers of abstraction, is not anything new. Remember the days when working in our industry meant slogging through obscure low-level language syntax and mucking around with memory allocations? Instead, we now have high-level languages like C# that read very close to English, and make programming more accessible. With things like ChatGPT, you’d still be “programming” machines to do what you want, just in a much more accessible way. So it’s all just another step towards easier communication with our &lt;del&gt;future robot overlords&lt;/del&gt; machines.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2023-04-chatgpt/hal-9000.jpg&quot; alt=&quot;HAL 9000, 2001: A Space Odyssey&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Change can be scary. We humans are intrinsically cautious of and resistant to change (or more specifically, the unknown). But let’s not forget, we’re also the most adaptable species on this little blue rock. We’ve gone through (and created) some massive disruptions and changes in our time.&lt;/p&gt;

&lt;p&gt;Consider this: throughout history, we’ve made tools to help us do things faster or to replace manual labour altogether. Sure, some jobs changed or vanished, but new ones emerged, leaving us more time for creative problem-solving and doing less low-value busy work. There are too many examples from history, but I’ll go through a few.&lt;!--more--&gt;&lt;/p&gt;

&lt;p&gt;The Industrial Revolution. Remember that? I don’t either. But picture a time when machines started replacing a huge amount of manual labour. Some jobs, like blacksmiths and weavers, were replaced by machines. Instead, factory jobs were born. The world didn’t end (although, it probably became much less sustainable, but we digress). Humans adapted, became more productive, and moved on.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“It is not the strongest of the species that survives, nor the most intelligent; it is the one most responsive to change.” - Charles Darwin&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The telephone. You know, that thing that Gen Z probably have only seen footage of in the movies and consider a pre-historic artifact. It changed the game for communication. While telegraph operators became a thing of the past, call center, infrastructure, technician, and telemarketing (unfortunately) jobs were created.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2023-04-chatgpt/call-center.jpg&quot; alt=&quot;Call center agents - a new profession&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The 80s, the era of big hair, great music, and the computer boom. Fast forward a bit, and smartphones became the extra limb nobody thought they needed, but don’t seem to be able to live without for 5 minutes anymore, making everyone a cyborg. The world saw a decline in the need for typists, bookkeepers, bank tellers, and other manual professions that could be greatly automated. However, jobs were created in software, graphic design, cybersecurity, digital marketing, and social media, just to name a few, giving birth to an industry with trillions of value.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“Invention is the mother of necessity.” – Marshall McLuhan&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are many more examples here like the introduction of electricity, the printing press, and automobiles. While there have been some negative aspects to our technological advancements, they have for the most part forced us to evolve, discover new possibilities, and focus on higher-value work. More time to work on solving actual problems instead of fighting with your tools to do what you want? Sold!&lt;/p&gt;

&lt;p&gt;I think the biggest downside to watch out for with AI is confirmation bias. As AI systems like ChatGPT are trained on vast amounts of data, they tend to reflect the patterns and biases present in that data. This can inadvertently lead to the creation of an echo chamber, where AI simply reinforces average or even false information instead of generating truly novel or accurate insights. This is even more insidious as AI systems can present information with confidence and assertiveness, making it sound plausible and legitimate. This could lead to the proliferation of misinformation, as people might be more inclined to trust the AI-generated content without questioning its validity.&lt;/p&gt;

&lt;p&gt;However, the potential for good is incredible. Imagine using AI to improve education and healthcare in remote areas with limited resources. It could be used to create personalized learning materials, adapting the curriculum to each student’s needs. In healthcare, AI can help diagnose illnesses by analysing symptoms, medical history, and other data, making a huge difference in people’s lives, especially those less privileged.&lt;/p&gt;

&lt;p&gt;I’ve personally been using AI to handle some of the more tedious tasks in my day-to-day life. It’s like having a smart junior personal assistant that’s really good at language and writing and is easily trainable. It may or may not have even helped me write this blog post!&lt;/p&gt;

&lt;p&gt;Ultimately, like any technology or invention, like the most basic of them all, fire, AI can be used for good or for evil. It’s up to us humans to decide its fate. One thing is for certain though: we’re witnessing another major technological breakthrough in our lifetimes, and it’s an exciting privilege.&lt;/p&gt;</content><author><name>Saeb Amini</name></author><summary type="html">I bet you can’t go a day without hearing someone rave about AI nowadays. Even if you’re not in the tech field, it’s hard to escape the buzz. ChatGPT and similar generative AI tools are popping up everywhere, have already started to impact people’s daily lives, and it seems like everyone is trying to find ways to use (or abuse) them.</summary></entry><entry><title type="html">My Key Takeaways From Impact Mapping</title><link href="http://saebamini.com/my-key-takeaways-from-impact-mapping/" rel="alternate" type="text/html" title="My Key Takeaways From Impact Mapping" /><published>2020-08-30T00:00:00+00:00</published><updated>2020-08-30T00:00:00+00:00</updated><id>http://saebamini.com/my-key-takeaways-from-impact-mapping</id><content type="html" xml:base="http://saebamini.com/my-key-takeaways-from-impact-mapping/">&lt;div class=&quot;post-intro-image-container&quot;&gt;
  &lt;p&gt;&lt;img src=&quot;/images/posts/impact-mapping/book.jpg&quot; alt=&quot;The Impact Mapping Book&quot; /&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;I received &lt;a href=&quot;https://www.goodreads.com/book/show/16084015-impact-mapping&quot;&gt;the Impact Mapping book&lt;/a&gt; as a gift from my company, &lt;a href=&quot;https://purple.telstra.com.au/&quot;&gt;Telstra Purple&lt;/a&gt;. It’s been in my long reading backlog for a while, but I finally got around to reading it on the weekend and found it a great and easy read while being full of gems. A lot of the concepts resonated with me, especially because I already knew about the concept, but I still picked up a few ideas. Here are the golden nuggets I wrote down as I was reading the book:&lt;!--more--&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;For all software projects (and most other endeavours), focus on a shared understanding of four key questions with stakeholders:
    &lt;ul&gt;
      &lt;li&gt;&lt;em&gt;Why&lt;/em&gt; [are we doing this?]. This is your &lt;em&gt;goal&lt;/em&gt;.&lt;/li&gt;
      &lt;li&gt;&lt;em&gt;Who&lt;/em&gt; [can influence the outcome?]. These are your &lt;em&gt;actors&lt;/em&gt;.&lt;/li&gt;
      &lt;li&gt;&lt;em&gt;How&lt;/em&gt; [can they influence the outcome?]. These are your &lt;em&gt;impacts&lt;/em&gt;.&lt;/li&gt;
      &lt;li&gt;&lt;em&gt;What&lt;/em&gt; [can we do to support or reduce the outcomes?]. These are your &lt;em&gt;deliverables&lt;/em&gt;.&lt;/li&gt;
    &lt;/ul&gt;

    &lt;p&gt;In that order. Always start with the why, but all of them are key. Without any one of them, you’ll end up building the wrong thing.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/impact-mapping/impact-map-example.png&quot; alt=&quot;The four impact mapping questions&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;If you’re lost on arriving at a good &lt;em&gt;why&lt;/em&gt;, keep asking it until you get to the money (&lt;em&gt;i.e.&lt;/em&gt; someone’s boat 😉).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Finding good questions is more important and difficult than finding good answers.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The critical component is neither the cause, nor the effect, but rather the validity of the assumption that links them.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;You should do your best so people on the ground and doing the work understand the &lt;em&gt;why&lt;/em&gt;. This results in superior solutions. In reality, these people are rarely privy to the information and it mostly exists in the back of senior stakeholders’ minds. Just knowing the &lt;em&gt;how&lt;/em&gt; and &lt;em&gt;what&lt;/em&gt; is not enough for teams to make the best decisions.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Environments that focus only on the &lt;em&gt;whats&lt;/em&gt; are usually the worst, bums-on-seats places to work at.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Impact mapping makes it easy to identify solutions looking for a problem. &lt;em&gt;i.e.&lt;/em&gt;, “We need to do microservices/blockchain/k8s/etc.”&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;em&gt;Who&lt;/em&gt;, &lt;em&gt;how&lt;/em&gt; and &lt;em&gt;what&lt;/em&gt; map nicely to the common user story template clauses of “As a [who], I want [what], so that [how]”. Use this frame of thinking to stop writing user stories like “As a system, I want a customer report” or “As a trader, I want a trading system, so that I can trade”!&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Goals and impacts should be &lt;a href=&quot;https://en.wikipedia.org/wiki/SMART_criteria&quot;&gt;SMART&lt;/a&gt;. Beware of “vanity” metrics which are the result of a psychological tendency to measure what’s easily measured and makes people feel good, rather than what can inform good decisions.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Don’t mistake metrics for goals.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If you achieve your goal with a different scope than planned, have you succeeded? if the answer is no, then you don’t have the right metrics.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The &lt;em&gt;what&lt;/em&gt; forms your detailed backlog. The aim in delivery should always be to focus on items connected to the most impactful &lt;em&gt;hows&lt;/em&gt; and &lt;em&gt;whos&lt;/em&gt; and finding the shortest path to the &lt;em&gt;why&lt;/em&gt;, not to implement all backlog items. Achieving goals is what matters, not delivering the highest number of features.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Similarly, going to market and shipping software should not be the goal. The goal should be to make a measurable impact after that happens.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The initial vision should not be set in stone. We live in a rapidly changing world, especially when it comes to software. The vision should be a living artefact, like most other inputs that feed into software development. Don’t do &lt;a href=&quot;https://sdtimes.com/agile/analyst-watch-water-scrum-fall-is-the-reality-of-agile/&quot;&gt;Water-Scrum-fall&lt;/a&gt;!&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;What the user/customer wants to get done is much more important than their ideas on how to do it. They are not the technology/solution experts.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Many teams fail to engage business people because they ask them to focus on prioritising the &lt;em&gt;whats&lt;/em&gt; (individual backlog items), while business people are much better engaged and make better decisions when discussing priorities on &lt;em&gt;whos&lt;/em&gt; and &lt;em&gt;hows&lt;/em&gt;. Prioritising actors and impacts is much more important than prioritising user stories.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If you follow agile and iterative processes without connecting them to measurables and the overall goal, it’s like saying:&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;“We don’t know exactly where we’ll go, but small steps ensure we don’t fall down.”&lt;/p&gt;
    &lt;/blockquote&gt;

    &lt;p&gt;So you might end up in a totally irrelevant place, successfully!&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are many online mind mapping tools you can use to create impact maps. &lt;a href=&quot;https://www.mindmup.com/&quot;&gt;MindMup&lt;/a&gt; is a good one.&lt;/p&gt;

&lt;p&gt;Have you used impact mapping before? Do you think I’ve missed something important? Has reading this post piqued your interest to learn more about it? I’m interested to know your thoughts in the comments section below 👇.&lt;/p&gt;</content><author><name>Saeb Amini</name></author><summary type="html"></summary></entry><entry><title type="html">Remove Your Conference Call Background Noise for Free!</title><link href="http://saebamini.com/remove-your-conference-call-background-noise-for-free/" rel="alternate" type="text/html" title="Remove Your Conference Call Background Noise for Free!" /><published>2020-08-15T00:00:00+00:00</published><updated>2020-08-15T00:00:00+00:00</updated><id>http://saebamini.com/remove-your-conference-call-background-noise-for-free</id><content type="html" xml:base="http://saebamini.com/remove-your-conference-call-background-noise-for-free/">&lt;p&gt;As working from home has become the new normal for a lot of professionals during the pandemic, communication over conference calls has posed more of a challenge. I’m not talking about the &lt;a href=&quot;https://youtu.be/rOWGe7uOuPU&quot;&gt;funny WFH incidents&lt;/a&gt; as people and their families are adapting to the new situation. I’m talking about not being able to leverage non-verbal communication as before, which is commonly believed to be responsible for the majority of our communication’s impact.&lt;/p&gt;

&lt;p&gt;With fewer communication opportunities and negligible body language visibility, we’re now relying on the clarity of our words and voice more than ever. Having a decent sound setup is no longer just a nice-to-have for those occasional WFH days – it’s become essential.&lt;/p&gt;

&lt;p&gt;Having &lt;a href=&quot;https://www.bluemic.com/en-us/products/yeti-nano/&quot;&gt;a decent microphone&lt;/a&gt; is a good start, but improving your setup doesn’t necessarily have to cost much. In fact, I recently improved my setup a great deal without spending any money by just removing background noise using free software. Let me take you through how I did it:&lt;!--more--&gt;&lt;/p&gt;

&lt;h2 id=&quot;walkthrough&quot;&gt;Walkthrough&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;What makes most of this possible is the amazing (and open-source) &lt;a href=&quot;https://obsproject.com/&quot;&gt;OBS Studio&lt;/a&gt; which is popular with streamers. Go ahead and install it. While you can do many fancy things with it, we’re going to use its &lt;a href=&quot;https://obsproject.com/wiki/Filters-Guide#audio-device-filters&quot;&gt;audio filters&lt;/a&gt; for our purpose.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Another core part of the setup is &lt;a href=&quot;https://www.vb-audio.com/Cable/&quot;&gt;Virtual Audio Cable&lt;/a&gt;, which is also free. While there are &lt;a href=&quot;https://obsproject.com/forum/resources/obs-virtualcam.949/&quot;&gt;OBS plugins available to provide its video as a virtual webcam&lt;/a&gt;, there are no equivalent plugins for sound yet. We’re going to use this software to capture the filtered/noiseless OBS audio output and provide it as a virtual microphone that we can use in conferencing software like Teams and Zoom. Go ahead and install this one as well.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;In OBS Studio’s Audio Mixer, click the settings cog icon next to Mic/Aux and choose &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Advanced Audio Properties&lt;/code&gt;:&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/images/posts/remove-bg-noise/1.png&quot; alt=&quot;OBS Mic/Aux Advanced Audio Settings&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;Then set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Audio Monitoring&lt;/code&gt; for your Mic/Aux to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Monitor and Output&lt;/code&gt;:&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/images/posts/remove-bg-noise/2.png&quot; alt=&quot;Audio Monitoring&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Go to the Audio settings tab from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;File → Settings → Audio&lt;/code&gt; and under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Advanced&lt;/code&gt;, set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Monitoring Device&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CABLE Input (VB-Audio Virtual Cable)&lt;/code&gt;:&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/images/posts/remove-bg-noise/3.png&quot; alt=&quot;Monitoring Device&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;This sends the filtered OBS audio output to the virtual input, which in turn directs it to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CABLE Output (VB-Audio Virtual Cable)&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;To make tweaking OBS filters easier, go to sound settings for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CABLE Output&lt;/code&gt; recording device in your Control Panel and turn on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Listen to this device&lt;/code&gt;:&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/images/posts/remove-bg-noise/4.png&quot; alt=&quot;Listen to this device&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;This lets you hear the filtered OBS audio output immediately so you can tweak the filters until you’re happy with the result.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;You are now ready to tweak the OBS audio filters to remove your background noise. Same as step 3 above, in OBS Studio’s Audio Mixer, click the settings cog icon next to Mic/Aux but this time choose &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Filters&lt;/code&gt;:&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/images/posts/remove-bg-noise/5.png&quot; alt=&quot;OBS Audio Filters&quot; /&gt;&lt;/p&gt;

    &lt;p&gt;There 3 main audio filters here that’ll help you remove noise and unnecessary sounds:&lt;/p&gt;

    &lt;ol&gt;
      &lt;li&gt;&lt;a href=&quot;https://obsproject.com/wiki/Filters-Guide#expander&quot;&gt;&lt;strong&gt;Expander&lt;/strong&gt;&lt;/a&gt; is pretty powerful and lets you reduce background noise such as computer fans, mouse/keyboard clicks, breathing, unwanted mouth noises and faint chatter/music. In short, it makes quiet sounds quieter. You typically should place this near the end of your filter chain, but you can sometimes get pretty good results with correctly configuring this filter alone based on your environment.&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://obsproject.com/wiki/Filters-Guide#noise-suppression&quot;&gt;&lt;strong&gt;Noise Suppression&lt;/strong&gt;&lt;/a&gt; can be used to remove mild background noise or white noise that may be in any of your audio sources (e.g. AC/Computer fan). Start at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-10 dB&lt;/code&gt; and move the slider to the left until you don’t hear them anymore. I’ve found this filter can make voice sound a bit high-pitch and artificial, and correctly adjusting an Expander filter produces a better result.&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://obsproject.com/wiki/Filters-Guide#noise-gate&quot;&gt;&lt;strong&gt;Noise Gate&lt;/strong&gt;&lt;/a&gt; lets you cut your microphone off when you’re not talking. This is helpful when you’re in active conversation, otherwise, it’s much better to just mute yourself when you’re not talking for extended periods. Select a close threshold above the noise volume and an open threshold slightly below your normal talking volume for good results.&lt;/li&gt;
    &lt;/ol&gt;

    &lt;p&gt;Once you’re happy with the results, turn off &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Listen to this device&lt;/code&gt; from your sound settings.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Now in your conferencing software like Teams, Zoom, etc. or any other software that uses a microphone, just set your microphone to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CABLE Output (VB-Audio Virtual Cable)&lt;/code&gt; and everyone will hear the audio that’s gone through your OBS filters.&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/images/posts/remove-bg-noise/6.png&quot; alt=&quot;Choose virtual microphone&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s it. There’s no excuse for you to continue sharing the sound of your computer fan, AC and your neighbour’s great taste in music with everyone on the call!&lt;/p&gt;</content><author><name>Saeb Amini</name></author><summary type="html">As working from home has become the new normal for a lot of professionals during the pandemic, communication over conference calls has posed more of a challenge. I’m not talking about the funny WFH incidents as people and their families are adapting to the new situation. I’m talking about not being able to leverage non-verbal communication as before, which is commonly believed to be responsible for the majority of our communication’s impact.</summary></entry><entry><title type="html">Code Reviews: An Accurate Window into a Team’s Health</title><link href="http://saebamini.com/code-reviews-an-accurate-window-into-a-teams-health/" rel="alternate" type="text/html" title="Code Reviews: An Accurate Window into a Team’s Health" /><published>2019-12-08T00:00:00+00:00</published><updated>2019-12-08T00:00:00+00:00</updated><id>http://saebamini.com/code-reviews-an-accurate-window-into-a-teams-health</id><content type="html" xml:base="http://saebamini.com/code-reviews-an-accurate-window-into-a-teams-health/">&lt;p&gt;Pull requests and code reviews are one of the most powerful software quality tools we have available in our tool-belt.&lt;/p&gt;

&lt;p&gt;Even when flying (han) solo on a project, I tend to create feature branches and PRs and review my own code after a short break; I usually find a few things I can improve when doing that, with the added benefit of being able to switch easily to other work if needed.&lt;/p&gt;

&lt;p&gt;In teams, the benefits are many and more significant: extra pair of eyes are always better in spotting improvement opportunities and catching mistakes, they consistently raise the quality of the project in all areas to the best of the team’s knowledge rather than individuals, they reduce the project risk by sharing knowledge and breaking down information silos while upskilling everyone. To a much &lt;em&gt;much&lt;/em&gt; lesser degree of importance, they are about guarding the project against YOLO pushes of crap code – that’s more relevant for public, open-source projects; if that’s your main reason for using pull requests and code reviews, that’s a sign of bigger root problems in the team.&lt;/p&gt;

&lt;p&gt;However, this post isn’t about those more commonly known benefits; it’s about how code reviews are one of the best places to observe and gauge a team’s health. I recently thought about this as I was reading the excellent book called &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Five_Dysfunctions_of_a_Team&quot;&gt;“The Five Dysfunctions of a Team”&lt;/a&gt;, recommended to me by my dear colleague &lt;a href=&quot;https://www.mehdi-khalili.com/&quot;&gt;Mehdi Khalili&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the book, Patrick Lencioni talks about the following five core team dysfunctions which build on top of each other. I’ll go through them and note how they can be observed in PRs and code reviews&lt;!--more--&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/code-reviews/dysfunctions-pyramid.png&quot; alt=&quot;The Five Dysfunctions of a Team&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;absence-of-trust&quot;&gt;Absence of trust&lt;/h2&gt;

&lt;p&gt;The most fundamental dysfunction in a team is a lack of trust, which is essentially the team members not willing to be vulnerable and open to each other. This results in a huge waste of time and energy as team members invest them in defensive behaviours, and are reluctant to ask for help from each other.&lt;/p&gt;

&lt;p&gt;Putting your code up in front of colleagues to review and give feedback on is essentially an act of vulnerability and people opposing the idea of code reviews is a strong sign of this dysfunction.&lt;/p&gt;

&lt;p&gt;Tackling this issue has to start with the leaders. Team and tech leads need to keep their minds open and look for opportunities to learn from and ask for help from junior people. You also have to cultivate a safe culture where mistakes aren’t frowned upon, but are seen as an opportunity to learn and improve. Otherwise, they keep happening and growing silently until they lead to big failures.&lt;/p&gt;

&lt;h2 id=&quot;fear-of-conflict&quot;&gt;Fear of conflict&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;When there is trust, conflict becomes nothing but the pursuit of truth, an attempt to find the best possible answer. – Patrick Lencioni&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Healthy, constructive conflict and discussion within a team is good thing (tension isn’t; don’t confuse the two). Diversity of thoughts leads to improvements and better outcomes.&lt;/p&gt;

&lt;p&gt;If there is trust, but code reviews are going through with little or no comments or discussions, that’s a strong sign that the team has a fear of conflict and wants to maintain an artificial harmony. At this point, pull requests and code reviews become merely red tape.&lt;/p&gt;

&lt;p&gt;To tackle this, encourage everyone to give feedback or even ask questions. Encourage opinions, but have an open mind and hold them loosely. However, be careful to not fall into the trap of &lt;a href=&quot;https://en.wikipedia.org/wiki/Law_of_triviality&quot;&gt;bike-shedding on trivial issues&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Having code review etiquette also definitely helps. Be nice and show how something could be improved rather than just criticising. Call out the positive things you like. Don’t ever make feedback personal; it should always be about the code and don’t forget that people are not their code!&lt;/p&gt;

&lt;h2 id=&quot;lack-of-commitment&quot;&gt;Lack of commitment&lt;/h2&gt;

&lt;p&gt;This happens when people haven’t had a chance to provide their input or be heard. When people don’t weigh in on something, they don’t buy in to it. This is not about seeking consensus (although it’s good if you have that); it’s more about making sure people are heard.&lt;/p&gt;

&lt;p&gt;If there is no fear of conflict, but people are reluctant to perform code reviews or give their vote to them, that is a sign of either this dysfunction or the next one.&lt;/p&gt;

&lt;p&gt;To solve this, team members (including seniors) should regularly bounce ideas off each other and ask for other team members’ opinions about how to approach a particular problem, even if they already have in mind what they think is a solid approach.&lt;/p&gt;

&lt;h2 id=&quot;avoidance-of-accountability&quot;&gt;Avoidance of accountability&lt;/h2&gt;

&lt;p&gt;In a well-functioning team, it’s the responsibility of each team member to hold one another accountable, and accept it when others hold them accountable. Otherwise, they’ll end up with low standards.&lt;/p&gt;

&lt;p&gt;This happens when people have a lack of clarity on the work being done. They don’t understand it properly or they don’t know why it’s being done.&lt;/p&gt;

&lt;p&gt;The signs of this dysfunction in code reviews is very similar to the previous one: people are either reluctant to perform code reviews, or they make trivial comments but then leave them in a pending state without approving or voting otherwise.&lt;/p&gt;

&lt;p&gt;To solve this, have clear communication around expectations and ensure the team understands why something is being done. Abiding by the user story template of “As a [persona], I want [feature], so that [outcome]” and having clear and detailed acceptance criteria helps here; if you have trouble with these, that’s usually because of poor connection and communication with the business or end-users.&lt;/p&gt;

&lt;h2 id=&quot;inattention-to-results&quot;&gt;Inattention to results&lt;/h2&gt;

&lt;p&gt;This is often because individual contributions and goals are prioritized over the team’s goal and collective business outcomes, which is usually a result of big egos, politics and individual KPIs.&lt;/p&gt;

&lt;p&gt;If the previous dysfunctions don’t exist, but you find that people have to be constantly pushed and nudged to review pending pull requests, and it usually takes a long time before they happen, that’s a strong sign of this dysfunction, as people are prioritizing their WIP individual contributions over shipping work that’s nearly done.&lt;/p&gt;

&lt;p&gt;To tackle this, you need to move towards a team-oriented culture and thinking. The whole of a well-functioning team is greater than the sum of its parts.&lt;/p&gt;

&lt;p&gt;Goals, recognitions and rewards should primarily be for teams rather than individuals. However, it’s &lt;em&gt;crucial&lt;/em&gt; that teams are small enough that each individual feels the effects of their contributions towards the collective outcome, otherwise, the motivating effects are lost.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Note that code reviews don’t fix these dysfunctions by themselves; but they are a great place where the dysfunctions are exhibited, letting you observe and identify them – a critical first step in fixing them. This, in addition to the benefits mentioned in the beginning, makes code reviews the single highest impact practice you can have to help you improve your product &lt;em&gt;and&lt;/em&gt; your team, both from a technical and people perspective.&lt;/p&gt;</content><author><name>Saeb Amini</name></author><summary type="html">Pull requests and code reviews are one of the most powerful software quality tools we have available in our tool-belt.</summary></entry><entry><title type="html">Integration Testing in Azure Functions with Dependency Injection</title><link href="http://saebamini.com/integration-testing-in-azure-functions-with-dependency-injection/" rel="alternate" type="text/html" title="Integration Testing in Azure Functions with Dependency Injection" /><published>2019-11-03T00:00:00+00:00</published><updated>2019-11-03T00:00:00+00:00</updated><id>http://saebamini.com/integration-testing-in-azure-functions-with-dependency-injection</id><content type="html" xml:base="http://saebamini.com/integration-testing-in-azure-functions-with-dependency-injection/">&lt;p&gt;I’m a big proponent of integration and functional tests (or &lt;a href=&quot;https://lostechies.com/jimmybogard/2010/08/25/an-effective-testing-strategy/&quot;&gt;“subcutaneous tests”&lt;/a&gt; if there’s a UI). Done efficiently and sparingly, they give you the biggest bang for your buck when it comes to confidence in the overall well-being of the majority of your system.&lt;/p&gt;

&lt;p&gt;Dependency injection is ubiquitous these days, and &lt;a href=&quot;https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests&quot;&gt;ASP.NET Core MVC’s seamless support for integration testing&lt;/a&gt; via the &lt;a href=&quot;https://www.nuget.org/packages/Microsoft.AspNetCore.Mvc.Testing&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Microsoft.AspNetCore.Mvc.Testing&lt;/code&gt; NuGet package&lt;/a&gt; has made this kind of testing simple when using dependency injection. However, I found that when dealing with &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/azure-functions/functions-overview&quot;&gt;Azure Function Apps&lt;/a&gt;, a similar setup is not as effortless as installing a package and using a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WebApplicationFactory&lt;/code&gt;, especially since Azure Function projects aren’t set up for dependency injection out of the box. Fortunately, after a bit of digging under the hood of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Microsoft.AspNetCore.Mvc.Testing&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Microsoft.AspNetCore.TestHost&lt;/code&gt;, I’ve been able to create a similar testing experience which I’ll go through below&lt;!--more--&gt;.&lt;/p&gt;

&lt;div class=&quot;tip&quot;&gt;
  &lt;p&gt;The setup isn’t &lt;em&gt;identical&lt;/em&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Microsoft.AspNetCore.Mvc.Testing&lt;/code&gt; bootstraps an in-memory test server that you can communicate with using an HTTP client, however, that’s part of ASP.NET Core while Azure Functions are built on top of the WebJobs SDK. While we can’t have that identical setup with functions, we can still meet our goal of setting up high-level integration tests while leveraging existing dependency injection setup and settings from our “real” functions without any duplication. We do this by operating at the level after HTTP by just bootstrapping a test &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IHost&lt;/code&gt;.&lt;/p&gt;
&lt;/div&gt;

&lt;h2 id=&quot;sample-function-app-with-dependency-injection&quot;&gt;Sample Function App With Dependency Injection&lt;/h2&gt;

&lt;p&gt;Let’s assume the below Azure Function app, with one HTTP endpoint that responds with the answer to life, the universe and everything:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SuperFunction&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IHitchhikerGuideToTheGalaxy&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_hitchhikerGuideToTheGalaxy&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;HitchhikerGuideToTheGalaxy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FunctionName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnswerToLifeTheUniverseAndEverything&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))]&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IActionResult&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;AnswerToLifeTheUniverseAndEverything&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;HttpTrigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AuthorizationLevel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Anonymous&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HttpRequest&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OkObjectResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_hitchhikerGuideToTheGalaxy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetTheAnswerToLifeTheUniverseAndEverything&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;IHitchhikerGuideToTheGalaxy&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetTheAnswerToLifeTheUniverseAndEverything&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HitchhikerGuideToTheGalaxy&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IHitchhikerGuideToTheGalaxy&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ISuperComputer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_superComputer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;SuperComputer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetTheAnswerToLifeTheUniverseAndEverything&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_superComputer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CalculateTheAnswerToLifeTheUniverseAndEverything&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ISuperComputer&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CalculateTheAnswerToLifeTheUniverseAndEverything&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SuperComputer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ISuperComputer&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CalculateTheAnswerToLifeTheUniverseAndEverything&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;But we all know that &lt;a href=&quot;https://ardalis.com/new-is-glue&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;new&lt;/code&gt; is glue&lt;/a&gt; for dependencies, so let’s inject them. Support for dependency injection in Azure Functions has been added since Azure Functions 2.x. To register &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IHitchhikerGuideToTheGalaxy&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ISuperComputer&lt;/code&gt; as services and inject them, we’ll create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Startup&lt;/code&gt; class, similar to what we have with ASP.NET Core applications:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Microsoft.Azure.Functions.Extensions.DependencyInjection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Microsoft.Extensions.DependencyInjection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;SuperFunctionApp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assembly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;FunctionsStartup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Startup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))]&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;SuperFunctionApp&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Startup&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FunctionsStartup&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Configure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IFunctionsHostBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddTransient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IHitchhikerGuideToTheGalaxy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HitchhikerGuideToTheGalaxy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddTransient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ISuperComputer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SuperComputer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It has to inherit from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FunctionsStartup&lt;/code&gt; and you also need to add a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FunctionsStartupAttribute&lt;/code&gt; assembly attribute that points to the Startup class. Both of these types exist in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Microsoft.Azure.Functions.Extensions&lt;/code&gt; NuGet package which you need to install.&lt;/p&gt;

&lt;p&gt;Now we can have some dependency injection goodness with the Function Host automatically injecting the dependencies for us:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SuperFunction&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IHitchhikerGuideToTheGalaxy&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_hitchhikerGuideToTheGalaxy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;SuperFunction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IHitchhikerGuideToTheGalaxy&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hitchhikerGuideToTheGalaxy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;_hitchhikerGuideToTheGalaxy&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hitchhikerGuideToTheGalaxy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;FunctionName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnswerToLifeTheUniverseAndEverything&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))]&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IActionResult&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;AnswerToLifeTheUniverseAndEverything&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;HttpTrigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AuthorizationLevel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Anonymous&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HttpRequest&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OkObjectResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_hitchhikerGuideToTheGalaxy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetTheAnswerToLifeTheUniverseAndEverything&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;IHitchhikerGuideToTheGalaxy&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetTheAnswerToLifeTheUniverseAndEverything&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HitchhikerGuideToTheGalaxy&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IHitchhikerGuideToTheGalaxy&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ISuperComputer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_superComputer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;HitchhikerGuideToTheGalaxy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ISuperComputer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;superComputer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;_superComputer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;superComputer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetTheAnswerToLifeTheUniverseAndEverything&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_superComputer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CalculateTheAnswerToLifeTheUniverseAndEverything&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ISuperComputer&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CalculateTheAnswerToLifeTheUniverseAndEverything&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SuperComputer&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ISuperComputer&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CalculateTheAnswerToLifeTheUniverseAndEverything&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;But how do we now properly test that our function correctly returns what we know is the obvious answer to life, the universe and everything? testing the various bits separately would cross into the realm of unit-testing, while duplicating our dependency injection setup is far from ideal; we want to keep and use all our existing DI configuration from our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Startup&lt;/code&gt; in our tests.&lt;/p&gt;

&lt;h2 id=&quot;setting-up-an-azure-function-test-host&quot;&gt;Setting Up An Azure Function Test Host&lt;/h2&gt;

&lt;p&gt;The secret to using our existing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Startup&lt;/code&gt; configuration and DI for integration testing lies in bootstrapping a &lt;a href=&quot;https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host&quot;&gt;.NET Core Generic Host&lt;/a&gt; via the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ConfigureWebJobs&lt;/code&gt; extension method:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startup&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Startup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;host&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;HostBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ConfigureWebJobs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Configure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;div class=&quot;tip&quot;&gt;
  &lt;p&gt;The use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ConfigureWebJobs&lt;/code&gt; might seem a bit strange, but since Azure Functions are built on top of the Web Jobs SDK, there is significant shared and compatible API surface. Here we are using the overload that takes an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Action&amp;lt;IWebJobsBuilder&amp;gt; configure&lt;/code&gt; argument. Our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Startup&lt;/code&gt; class inherits from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FunctionsStartup&lt;/code&gt; which inherits from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IWebJobsStartup&lt;/code&gt;, &lt;a href=&quot;https://github.com/Azure/azure-functions-dotnet-extensions/blob/master/src/Extensions/DependencyInjection/FunctionsStartup.cs&quot;&gt;providing a compatible Configure method that calls our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Configure(IFunctionsHostBuilder builder)&lt;/code&gt; method&lt;/a&gt;!&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Putting the above together, we can write an integration test, that initializes our HTTP Function reusing all the dependency injection and settings from our “real” code inside a test Host, and tests whether it correctly returns the true answer to life, the universe and everything:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SuperFunctionTests&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SuperFunction&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_sut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;SuperFunctionTests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startup&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Startup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
		&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;host&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;HostBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ConfigureWebJobs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Configure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

		&lt;span class=&quot;n&quot;&gt;_sut&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;SuperFunction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetRequiredService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IHitchhikerGuideToTheGalaxy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;());&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;c1&quot;&gt;// arrange&lt;/span&gt;
		&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;DefaultHttpRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;DefaultHttpContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;

		&lt;span class=&quot;c1&quot;&gt;// act&lt;/span&gt;
		&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OkObjectResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_sut&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AnswerToLifeTheUniverseAndEverything&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

		&lt;span class=&quot;c1&quot;&gt;// assert&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Equal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If you’d like to quickly try it for yourself, I have shared my preferred way to set up Azure Function projects as a &lt;a href=&quot;https://github.com/SaebAmini/Saeb.FunctionApp&quot;&gt;.NET Core Template on GitHub&lt;/a&gt;. The template includes a test set up with the above approach, plus using the familiar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;appsettings.json&lt;/code&gt; file for settings instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;local.settings.json&lt;/code&gt; and Environment Variables, to help with ease and simplicity of deployment, as well as a build defined via Azure YAML Pipelines.&lt;/p&gt;</content><author><name>Saeb Amini</name></author><summary type="html">I’m a big proponent of integration and functional tests (or “subcutaneous tests” if there’s a UI). Done efficiently and sparingly, they give you the biggest bang for your buck when it comes to confidence in the overall well-being of the majority of your system.</summary></entry><entry><title type="html">How to Version Your .NET NuGet Packages, Libraries and Assemblies + Azure YAML Pipelines Example using .NET Core CLI</title><link href="http://saebamini.com/how-to-version-your-net-nuget-packages-libraries-and-assemblies-azure-yaml-pipelines-example-using-net-core-cli/" rel="alternate" type="text/html" title="How to Version Your .NET NuGet Packages, Libraries and Assemblies + Azure YAML Pipelines Example using .NET Core CLI" /><published>2019-09-20T00:00:00+00:00</published><updated>2019-09-20T00:00:00+00:00</updated><id>http://saebamini.com/how-to-version-your-net-nuget-packages-libraries-and-assemblies-azure-yaml-pipelines-example-using-net-core-cli</id><content type="html" xml:base="http://saebamini.com/how-to-version-your-net-nuget-packages-libraries-and-assemblies-azure-yaml-pipelines-example-using-net-core-cli/">&lt;p&gt;I often see arbitrary patterns used for versioning packages and assemblies, especially for internal projects, with the only common goal being that the versions are increased with each release. There is rarely a distinction between NuGet package &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Version&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AssemblyVersion&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FileVersion&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InformationalVersion&lt;/code&gt; and they’re commonly all set to the same value, if set at all. That’s not to blame anyone, having all these different ways to set a version is darn confusing.&lt;/p&gt;

&lt;p&gt;However, if you plan to release a public NuGet package, or an internal package that could be heavily used, you’ll be making your life, and your users’ lives a lot easier, and avoid creating a “dependency hell”, if you distinguish between the above versions and follow a meaningful versioning strategy like &lt;a href=&quot;https://semver.org/&quot;&gt;Semantic Versioning&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you haven’t heard about Semantic Versioning, here’s the TL;DR&lt;!--more--&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;It solves the problems of &lt;em&gt;version lock&lt;/em&gt;, the inability to upgrade a package with minor changes and bug fixes without having to release new versions of every dependent package, and &lt;em&gt;version promiscuity&lt;/em&gt;, the inability to safely upgrade a package with breaking changes without automatically breaking dependent packages.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The versioning scheme is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{major}.{minor}.{patch}-{tag}+{buildmetadata}&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{major}&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{minor}&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{patch}&lt;/code&gt; are numeric, while &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{tag}&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{buildmetadata}&lt;/code&gt; can be alphanumeric.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Bug fixes increment the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{patch}&lt;/code&gt; number.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Backward compatible additions/changes increment the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{minor}&lt;/code&gt; number.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Only breaking changes increment the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{major}&lt;/code&gt; number. You can refer to &lt;a href=&quot;https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/breaking-change-rules.md&quot;&gt;CoreFX’s rules for classifying breaking changes&lt;/a&gt; as a guideline.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-{tag}&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+{buildmetadata}&lt;/code&gt; parts are optional. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-{tag}&lt;/code&gt; is used to denote pre-release unstable versions and so is used less frequently, although I recommend always including the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+{buildmetadata}&lt;/code&gt; to provide valuable information – more on this below.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So how do you follow and apply that in the .NET ecosystem?&lt;/p&gt;

&lt;p&gt;I’ve recently released a NuGet package, called &lt;a href=&quot;https://github.com/SaebAmini/EF.Auditor&quot;&gt;EF.Auditor&lt;/a&gt; – a simple and lightweight auditing library for Entity Framework Core that supports Domain Driven Design. As part of releasing this package, I refreshed my knowledge around versioning, the multitude of version attributes and researched versioning strategies used by Microsoft and popular packages to arrive at the sweet spot of versioning packages and assemblies. I’ll go through the highlights below. If you’d like to skip the details and just see the versioning strategy, jump to the &lt;a href=&quot;#putting-it-all-together&quot;&gt;“Putting it all together”&lt;/a&gt; part.&lt;/p&gt;

&lt;h2 id=&quot;what-the-heck-are-nuget-package-version-assemblyversion-fileversion-informationalversion&quot;&gt;What the heck are NuGet package &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Version&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AssemblyVersion&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FileVersion&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InformationalVersion&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;If you’re confused by all the different versions, you’re not alone. However, while they might all look the same, they have quite different characteristics and effects.&lt;/p&gt;

&lt;h3 id=&quot;nuget-package-version&quot;&gt;NuGet package version&lt;/h3&gt;

&lt;p&gt;This is the version in your package’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nuspec&lt;/code&gt; file in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;version&amp;gt;&lt;/code&gt; element.&lt;/p&gt;

&lt;p&gt;The NuGet package version is displayed on &lt;a href=&quot;https://www.nuget.org/packages/ef.auditor&quot;&gt;NuGet.org&lt;/a&gt;, the Visual Studio NuGet package manager and is the version number users will commonly see, and they’ll refer to it when they talk about the version of a library they’re using. The NuGet package version is used by NuGet and has &lt;em&gt;no effect&lt;/em&gt; on runtime behavior.&lt;/p&gt;

&lt;p&gt;Since this version is the most visible version to developers, it’s a good idea to update it using Semantic Versioning. SemVer indicates the significance of changes between release and helps developers make an informed decision when choosing what version to use. For example, going from 1.0 to 2.0 indicates that there are potentially breaking changes.&lt;/p&gt;

&lt;p&gt;However, since Visual Studio &amp;lt; 2017 and NuGet client &amp;lt; 4.3.0 do not support SemVer 2.0.0, I suggest sticking with SemVer 1.0.0 here for maximum compatibility.&lt;/p&gt;

&lt;h3 id=&quot;assemblyversion&quot;&gt;AssemblyVersion&lt;/h3&gt;

&lt;p&gt;Commonly defined in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;csproj&lt;/code&gt; file, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AssemblyInfo.cs&lt;/code&gt; in old project formats, the assembly version is what the CLR uses at runtime to select which version of an assembly to load.&lt;/p&gt;

&lt;p&gt;The .NET Framework CLR demands an exact match to load a strong named assembly. For example, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Libary1, Version=1.0.0.0&lt;/code&gt; was compiled with a reference to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Newtonsoft.Json, Version=11.0.0.0&lt;/code&gt;. The .NET Framework will only load that exact version &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;11.0.0.0&lt;/code&gt;. To load a different version at runtime, a binding redirect must be added to the .NET application’s config file.&lt;/p&gt;

&lt;p&gt;Strong naming combined with assembly version enables strict assembly version loading. While strong naming a library has a number of benefits, it often results in runtime exceptions that an assembly can’t be found and requires binding redirects to be fixed. .NET Core assembly loading has been relaxed, and the .NET Core CLR will automatically load assemblies at runtime with a higher version, but the .NET Framework CLR needs the entire AssemblyVersion has to be an exact match in order for an assembly to be loaded.&lt;/p&gt;

&lt;p&gt;For maximum binary compatibility with the .NET Framework CLR and strong-naming scenarios, only sync the major version of this attribute to match the major part of your semantic version and leave the other parts as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt;. This is the strategy followed by .NET Framework BCL, CoreFX and many other popular packages like Entity Framework Core and Newtonsoft.Json.&lt;/p&gt;

&lt;p&gt;Providing a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*&lt;/code&gt; in place of the numbers is likely one of the worst things to do as it makes compiler set numbers based on &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/api/system.reflection.assemblyversionattribute&quot;&gt;some crazy rules&lt;/a&gt; and you’d need a calculator to get any valuable information out of those numbers. It also would cause an error in .NET Core projects as they are &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/deterministic-compiler-option&quot;&gt;deterministic&lt;/a&gt; by default.&lt;/p&gt;

&lt;p&gt;Note that although Assembly Version follows a similar &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{Major}.{Minor}.{BuildNumber}.{Revision}&lt;/code&gt; schema, it has significant limitations so you won’t be able to apply SemVer here anyway:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It only supports numbers for all parts.&lt;/li&gt;
  &lt;li&gt;Each number &lt;a href=&quot;https://blogs.msdn.microsoft.com/msbuild/2007/01/03/why-are-build-numbers-limited-to-65535/&quot;&gt;can only go up to 65534&lt;/a&gt;, so you wouldn’t be able to, for example, have a useful full date such as 190920 included in your revision. Using an auto-incremented build number from your CI here &lt;a href=&quot;https://stackoverflow.com/q/1188284/68080&quot;&gt;would also get you only so far&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;fileversion&quot;&gt;FileVersion&lt;/h3&gt;

&lt;p&gt;Commonly defined in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;csproj&lt;/code&gt; file, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AssemblyInfo.cs&lt;/code&gt; in old project formats, the assembly file version is used to display a file version in Windows and has &lt;em&gt;no effect&lt;/em&gt; on runtime behavior. Setting this version is optional. It’s visible in the File Properties dialog in Windows Explorer:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/versioning/file-version.png&quot; alt=&quot;File Version&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It’s also the version displayed in the Windows Explorer tooltip when you hover over an assembly:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/versioning/file-version-tooltip.png&quot; alt=&quot;File Version&quot; /&gt;&lt;/p&gt;

&lt;p&gt;File Version follows the same versioning schema as Assembly Version and has the same limitations, so you can’t use this one for proper SemVer versioning either. But for consistency and preventing user confusion, I recommend keeping the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{Major}.{Minor}.{BuildNumber}&lt;/code&gt; parts of this attribute in sync with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{major}.{minor}.{patch}&lt;/code&gt; from your semantic version. Changing this attribute frequently won’t create the same issues as changing Assembly Version explained above, as this attribute is never used by .NET.&lt;/p&gt;

&lt;h3 id=&quot;informationalversion&quot;&gt;InformationalVersion&lt;/h3&gt;

&lt;p&gt;Commonly defined in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;csproj&lt;/code&gt; file, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AssemblyInfo.cs&lt;/code&gt; in old project formats, the assembly informational version is similar to File Version in that setting it is optional, it has &lt;em&gt;no effect&lt;/em&gt; on runtime behavior and it shows up in File Properties dialog in Windows Explorer as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Product version&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/versioning/informational-version.png&quot; alt=&quot;Product Version&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The major difference is this version can be &lt;em&gt;any&lt;/em&gt; string and doesn’t have the same limitations as Assembly Version and File Version, which makes it perfect for being set to your full SemVer 2.0.0 version.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InformationalVersion&lt;/code&gt; assembly attribute could be read at runtime and used to identify the exact version of your package or application, for example in logging:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;semanticVersion&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;assembly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GetCustomAttribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AssemblyInformationalVersionAttribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;().&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InformationalVersion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;putting-it-all-together&quot;&gt;Putting it all together&lt;/h2&gt;

&lt;p&gt;Combining the above information and after trying many different approaches through the years, I’ve found the below strategy to be at the sweet spot of versioning NuGet packages and .NET assemblies:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Set your NuGet package version to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{major}.{minor}.{patch}-{tag}&lt;/code&gt; part of your Semantic Version&lt;/li&gt;
  &lt;li&gt;Follow &lt;a href=&quot;https://semver.org/#semantic-versioning-specification-semver&quot;&gt;the SemVer specs&lt;/a&gt; for bumping the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{major}&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{minor}&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{patch}&lt;/code&gt; parts&lt;/li&gt;
  &lt;li&gt;Set your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AssemblyVersion&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{major}.0.0.0&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Set your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FileVersion&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{major}.{minor}.{patch}.0&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Set your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;InformationalVersion&lt;/code&gt; to the full Semantic Version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{major}.{minor}.{patch}-{tag}+{buildmetadata}&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;For &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{buildmetadata}&lt;/code&gt;, use the pattern of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{BuildDate:yyyyMMdd}{BuildRevision}.{commitId}&lt;/code&gt;. This provides you with super-useful information at a glance:
        &lt;ul&gt;
          &lt;li&gt;When the build was done&lt;/li&gt;
          &lt;li&gt;The exact commit in your source control history the build was from, which helps you quickly check out that version for troubleshooting&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Only include the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-{tag}&lt;/code&gt; part if you’re releasing an unstable pre-release version, e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-alpha&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How you implement the strategy would depend on your platform, tooling and build process. While you could go with tools like GitVersion, my preferred method these days is a simple source-controlled way of managing the version through &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema&quot;&gt;Azure YAML Pipelines&lt;/a&gt;, close to where the rest of my build definition is.&lt;/p&gt;

&lt;h3 id=&quot;azure-yaml-pipelines-example&quot;&gt;Azure YAML Pipelines example&lt;/h3&gt;

&lt;p&gt;Here’s EF.Auditor’s versioning done through Azure YAML Pipelines:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yaml&quot; data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;$(Date:yyyyMMdd)$(Rev:r)&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;pool&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;vmImage&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Ubuntu&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;16.04'&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;variables&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;buildConfiguration&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Release'&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;versionMajor&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;versionMinor&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;versionPatch&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;powershell&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;$mainVersion = &quot;$(versionMajor).$(versionMinor).$(versionPatch)&quot;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;$commitId = &quot;$(Build.SourceVersion)&quot;.Substring(0,7)&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;Write-Host &quot;##vso[task.setvariable variable=mainVersion]$mainVersion&quot;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;Write-Host &quot;##vso[task.setvariable variable=semanticVersion]$mainVersion+$(Build.BuildNumber).$commitId&quot;&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;Write-Host &quot;##vso[task.setvariable variable=assemblyVersion]$(versionMajor).0.0&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;SetVersionVariables&lt;/span&gt;

&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;powershell&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;dotnet pack --configuration Release /p:AssemblyVersion='$(assemblyVersion)' /p:FileVersion='$(mainVersion)' /p:InformationalVersion='$(semanticVersion)' /p:Version='$(mainVersion)' --output '$(Build.ArtifactStagingDirectory)'&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Pack&lt;/span&gt;

&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;PublishBuildArtifacts@1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I’ve simplified the pipeline to the bits relevant to versioning; you can &lt;a href=&quot;https://github.com/SaebAmini/EF.Auditor/blob/master/azure-pipelines.yml&quot;&gt;see the full pipeline definition on GitHub&lt;/a&gt;.&lt;/p&gt;</content><author><name>Saeb Amini</name></author><summary type="html">I often see arbitrary patterns used for versioning packages and assemblies, especially for internal projects, with the only common goal being that the versions are increased with each release. There is rarely a distinction between NuGet package Version, AssemblyVersion, FileVersion and InformationalVersion and they’re commonly all set to the same value, if set at all. That’s not to blame anyone, having all these different ways to set a version is darn confusing.</summary></entry><entry><title type="html">Common C# async and await misconceptions</title><link href="http://saebamini.com/common-async-and-await-misconceptions/" rel="alternate" type="text/html" title="Common C# async and await misconceptions" /><published>2018-10-30T00:00:00+00:00</published><updated>2018-10-30T00:00:00+00:00</updated><id>http://saebamini.com/common-async-and-await-misconceptions</id><content type="html" xml:base="http://saebamini.com/common-async-and-await-misconceptions/">&lt;p&gt;.NET Programmers have traditionally shied away from writing asynchronous code, and mostly for good reason. Writing asynchronous code used to be &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/asynchronous-programming-model-apm&quot;&gt;arduous work&lt;/a&gt; and the result was &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/event-based-asynchronous-pattern-eap&quot;&gt;difficult to reason about, debug and maintain&lt;/a&gt;. That became exacerbated when you threw concurrency into the mix – parallel or asynchronous – as that’s harder to consciously follow for our brains which are optimised/trained for non-concurrent and sequential logic.&lt;/p&gt;

&lt;p&gt;The compiler magic of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async/await&lt;/code&gt; since C# 5.0 and the &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/task-based-asynchronous-pattern-tap&quot;&gt;Task-based Asynchronous Pattern&lt;/a&gt; has immensely improved that experience, mainly by abstracting asynchronous code to read like synchronous code. In fact it’s been such a big hit that it’s spread and &lt;a href=&quot;https://en.wikipedia.org/wiki/Futures_and_promises#History&quot;&gt;been adopted by many other popular languages such as JavaScript, Dart, Python, Scala and C++&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This has resulted in a trend of more and more asynchronous code popping up in our code-bases. That’s mostly a good thing, because leveraging asynchrony &lt;em&gt;in the right place&lt;/em&gt; can lead to significant performance and scalability improvements. However, with all great magic, comes great misconception. I’ll go over some of the most common ones below which I encounter often&lt;!--more--&gt;.&lt;/p&gt;

&lt;h2 id=&quot;asyncawait-means-multi-threading&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async/await&lt;/code&gt; means multi-threading&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;“The method isn’t &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;, it’s single-threaded.” – too many devs&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I continue to hear and see many varieties of the above statement and it’s the most common misconception in my experience. Overloading of terms like &lt;em&gt;asynchronous&lt;/em&gt;, &lt;em&gt;concurrent&lt;/em&gt; and &lt;em&gt;parallel&lt;/em&gt; and using them interchangeably in the industry can take some of the blame, and maybe some of it falls on Tasks being included in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System.Threading&lt;/code&gt; namespace.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; doesn’t magically make your code asynchronous. It don’t spin up worker threads behind your back either. In fact, it doesn’t really do anything other than enable the use of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt; keyword in a method. It was only introduced &lt;a href=&quot;https://blogs.msdn.microsoft.com/ericlippert/2010/11/11/asynchrony-in-c-5-part-six-whither-async/&quot;&gt;to not break existing codebases that had used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt; as an identifier and to make &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt; usage heuristics simpler&lt;/a&gt;. That’s it!&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;await&lt;/code&gt; is a bit more complicated and is quite similar to how the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yield&lt;/code&gt; keyword works, in that it yields flow of control back to the caller and creates a state-machine by causing the compiler to register the rest of the async method as a continuation. That continuation is run whenever the awaited task completes. The compiler transforms the below:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;statements&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Into essentially:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;awaiter&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetAwaiter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;awaiter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;OnCompleted&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;awaiter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;statements&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;That’s the gist. The compiler emits &lt;a href=&quot;https://weblogs.asp.net/dixin/understanding-c-sharp-async-await-1-compilation&quot;&gt;more complex code&lt;/a&gt;, however, none of that involves spinning worker threads. It also doesn’t magically make your task’s implementation asynchronous either. In fact, if the implementation is synchronous it all runs synchronously, but &lt;a href=&quot;#all-code-should-be-async-by-default-for-better-performance&quot;&gt;&lt;em&gt;slooower&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;you-cant-have-concurrency-with-purely-asynchronous-code&quot;&gt;You can’t have concurrency with purely asynchronous code&lt;/h2&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;en&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Don&amp;#39;t wanna be that guy, but you mean concurrent. Async = non-blocking.&lt;/p&gt;&amp;mdash; Diogo Castro (@dfacastro) &lt;a href=&quot;https://twitter.com/dfacastro/status/808345214725275649?ref_src=twsrc%5Etfw&quot;&gt;December 12, 2016&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;p&gt;So I just said async doesn’t require multiple threads. That means unless you mix in multi-threading you can’t have concurrency right?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Wrong.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Truly asynchronous operations can be &lt;em&gt;concurrently&lt;/em&gt; performed by one thread. Heresy! how can one thread perform multiple operations at the same time?&lt;/p&gt;

&lt;p&gt;That’s possible because IO operations leverage &lt;a href=&quot;https://docs.microsoft.com/en-us/windows/desktop/fileio/i-o-completion-ports&quot;&gt;&lt;em&gt;IOCP&lt;/em&gt;&lt;/a&gt; ports at the device driver level. The point of IO completion ports is you can bind thousands of IO handles to a single one, effectively using a single thread to drive thousands of asynchronous operations concurrently.&lt;/p&gt;

&lt;p&gt;Take this sample code that makes 5 HTTP calls to a slow API one by one:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;DoSequentialAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SlowApiUrl&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://slow-api-that-responds-after-2-seconds&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;++)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;WebClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DownloadStringTaskAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SlowApiUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;For me it takes about a little more than 10 seconds to complete, while using a single thread. No surprise here.&lt;/p&gt;

&lt;p&gt;Now what do you think happens if we change the code to instead of awaiting each call one by one, fire off all of them and await the combination of all those tasks?&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;DoConcurrentAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SlowApiUrl&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://slow-api-that-responds-after-2-seconds&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tasks&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;++)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;WebClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
		&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;no&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;tasks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;DownloadStringTaskAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SlowApiUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WhenAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tasks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The moment of truth! the whole thing takes a little more than 2 seconds this time, and all with just a single thread. &lt;a href=&quot;https://gist.github.com/SaebAmini/05a2370ee8ad7248e2e037ee3b6ffbae&quot;&gt;Here’s a more complete example&lt;/a&gt; that keeps track of used threads and the exact time. Go ahead and run it for yourself, may you become a believer.&lt;/p&gt;

&lt;p&gt;How that’s possible is that as soon as each call is fired and registered on a completion port, while it is “in flight”, we get the thread back and use it to fire the next one. That’s also the same reason why doing something like the above with tasks that use an EF context to query the database asynchronously will cause EF to blow up with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DbConcurrencyException&lt;/code&gt; saying concurrent queries on the same context aren’t supported.&lt;/p&gt;

&lt;h2 id=&quot;all-code-should-be-async-by-default-for-better-performance&quot;&gt;All code should be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; by default for better performance&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/async-misconceptions/async_all_the_things.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We saw that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async/await&lt;/code&gt; generates a state-machine and significant extra code which involves a new type with extra heap allocations, exceptions and try-catches and context marshalling between different execution contexts. As you can imagine, all of that comes with some overhead which inevitably makes asynchronous code run slower than a synchronous counterpart.&lt;/p&gt;

&lt;p&gt;If it’s slower, why do we use asynchronous code?&lt;/p&gt;

&lt;p&gt;In rich client applications which have a UI thread, or single-threaded applications, it’s for &lt;em&gt;responsiveness&lt;/em&gt;. Because you won’t block the main thread and freeze the app while waiting for an asynchronous operation.&lt;/p&gt;

&lt;p&gt;It’s a different story in ASP.NET web applications and APIs. ASP.NET request processing is multi-threaded with a thread per request model. Releasing the thread when awaiting an asynchronous request in an API call doesn’t create a more responsive experience for the user because it still has to complete before the user gets the response. The benefit here is &lt;em&gt;scalability&lt;/em&gt; and &lt;em&gt;throughput&lt;/em&gt; – getting more bang (request handling) for your buck (hardware resources).&lt;/p&gt;

&lt;p&gt;Threads are maintained in a thread pool and map to limited system resources. Depending on many different factors, the underlying scheduler might decide to spin more threads and add to this pool which involves some microseconds of overhead per thread. That may seem insignificant, but for an ASP.NET API serving a lot of users, it can quickly add up to significant numbers. By releasing the thread when it’s idling for an IO-bound work to complete, such as calling another API, it can be used to serve another request. It also protects against usage bursts since the scheduler doesn’t suddenly find itself starved of threads to serve new requests.&lt;/p&gt;

&lt;p&gt;This means your API can make better use of available system resources and deal with a lot more requests before it falls over. However, you only get these benefits when you leverage &lt;em&gt;truly&lt;/em&gt; asynchronous code on &lt;em&gt;inherently&lt;/em&gt; asynchronous IO bound operations that have &lt;em&gt;significant latency&lt;/em&gt; like reading a file from a slow drive or making a network call.&lt;/p&gt;

&lt;p&gt;If async code is used for performing synchronous operations, or even asynchronous operations that are guaranteed to complete in milliseconds, the overhead outweighs the gains and results in worse performance. &lt;a href=&quot;http://www.ducons.com/blog/tests-and-thoughts-on-asynchronous-io-vs-multithreading&quot;&gt;In one benchmark this detriment was measured to be about 300% in total execution time, 600% in memory and 25% in CPU usage&lt;/a&gt;. So give it a second think before making that next method &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt; by default. Horses for courses.&lt;/p&gt;

&lt;h2 id=&quot;you-need-to-use-asyncawait-in-the-whole-call-stack&quot;&gt;You need to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async/await&lt;/code&gt; in the whole call stack&lt;/h2&gt;

&lt;p&gt;Have you seen code like this before?&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// FooController.cs&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FooController&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetFoo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_fooService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetFooAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;


&lt;span class=&quot;c1&quot;&gt;// FooService.cs&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FooService&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetFooAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_fooContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You should have asynchronous code in the whole call stack to not hold up threads, but you don’t have to actually use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async/await&lt;/code&gt; keywords unless you need to.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FooController.GetFoo&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FooService.GetFooAsync&lt;/code&gt; just return another task without doing anything else. These “proxy” methods don’t need to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async/await&lt;/code&gt; at all and can be simplified to:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// FooController.cs&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FooController&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetFoo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_fooService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetFooAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;


&lt;span class=&quot;c1&quot;&gt;// FooService.cs&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FooService&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetFooAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_fooContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetAsync&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;It is still asynchronous code, but it’s more efficient as it avoids &lt;a href=&quot;#all-code-should-be-async-by-default-for-better-performance&quot;&gt;creating an unnecessary state-machine&lt;/a&gt;. It is also less code and reads better, so it’s simply cleaner code.&lt;/p&gt;

&lt;p&gt;Note that there are some gotchas involved with omitting the async/await keywords in more complex methods. For example, returning a Task inside a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;using&lt;/code&gt; block without awaiting it, exits the block and results in immediate disposal which might not be expected. Also, exception behaviour is slightly different when a synchronous part of the method throws an exception, and the calling code happens to await the method after invoking it, e.g. firing a bunch of tasks and then awaiting them all with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Task.WhenAll&lt;/code&gt;. That exception will be thrown synchronously rather than when the task is awaited. To avoid these issues and their cognitive overhead, I recommend only omitting the async/await keywords in simple proxy methods as my examples above.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;Hopefully this helps debunk some of the most common misconceptions about the magic of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async/await&lt;/code&gt; in C# and .NET.&lt;/p&gt;</content><author><name>Saeb Amini</name></author><summary type="html">.NET Programmers have traditionally shied away from writing asynchronous code, and mostly for good reason. Writing asynchronous code used to be arduous work and the result was difficult to reason about, debug and maintain. That became exacerbated when you threw concurrency into the mix – parallel or asynchronous – as that’s harder to consciously follow for our brains which are optimised/trained for non-concurrent and sequential logic.</summary></entry><entry><title type="html">Good Practices for Enterprise Integrations over the Azure Service Bus</title><link href="http://saebamini.com/good-practices-for-enterprise-integrations-over-the-azure-service-bus/" rel="alternate" type="text/html" title="Good Practices for Enterprise Integrations over the Azure Service Bus" /><published>2018-09-14T00:00:00+00:00</published><updated>2018-09-14T00:00:00+00:00</updated><id>http://saebamini.com/good-practices-for-enterprise-integrations-over-the-azure-service-bus</id><content type="html" xml:base="http://saebamini.com/good-practices-for-enterprise-integrations-over-the-azure-service-bus/">&lt;p&gt;Integrating systems over a good messaging infrastructure has many benefits if done right. Some of these are system/network decoupling and platform agnosticism, independent scalability, high reliability, spike protection, a central place to keep an eye on your integrations and more depending on your situation.&lt;/p&gt;

&lt;p&gt;Many of these benefits are vast topics on their own. But the point of this article is to go over some of the pitfalls when implementing large-scale integrations over a messaging infrastructure and guidelines for avoiding them.&lt;/p&gt;

&lt;p&gt;These are based on my learning from a recent project which involved improving a client’s existing integration between 5+ large systems. While the messaging infrastructure in use was the Azure Service Bus, I believe most of these points apply to all other message-based integrations and service buses&lt;!--more--&gt;.&lt;/p&gt;

&lt;h2 id=&quot;1--dont-roll-your-own&quot;&gt;1.  Don’t roll your own&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/integrations/dont_reinvent_the_wheel.jpg&quot; alt=&quot;Don't re-invent the wheel&quot; /&gt;
&lt;em&gt;Don’t re-invent the wheel.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Not rolling your own should really be no-brainer in all projects, yet you still see it unnecessarily done more often than you should.&lt;/p&gt;

&lt;p&gt;Unless your aim is to provide a competing solution that works better than what’s available and you have the resources to maintain it, you will get it wrong, miss edge cases, and it will eventually cost you more as your efforts are diverted from delivering business value to maintaining your custom solution.&lt;/p&gt;

&lt;p&gt;So stand on the shoulder of giants as much as you can by using tried and tested infrastructure that’s already available.&lt;/p&gt;

&lt;h2 id=&quot;2-dont-bypass-your-messaging-infrastructure&quot;&gt;2. Don’t bypass your messaging infrastructure&lt;/h2&gt;

&lt;p&gt;This is closely related to the previous point and includes plugging in your own service bus-esque solutions alongside a proper infrastructure like the Azure Service Bus, for example, storing messages in a database table for later processing.&lt;/p&gt;

&lt;p&gt;One of the major initial issues I identified with the client’s integration, was that to avoid queues getting full, they were retrieving messages from the queues, storing them in an MSSQL database and doing the real processing from there. This had introduced a big flaw in the design, losing out on many benefits that came with ASB:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Proper locking of the message when it’s being processed, to prevent duplicate processing. Implementing your own locking mechanism on a database table is complex, error-prone and can easily cause dead-lock situations.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Scaling and performance. Even if you get the locking right, it won’t be anywhere near as performant as a proper message queue for high-traffic scenarios. You’ll have a high-write, high-read situation (a lot of messages coming in and a lot of polling) which is very hard to optimize a SQL database table for.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Availability and reliability. A good messaging platform like ASB, is highly available and redundantly stores your data.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Filtering, dead lettering, automatic expiry and a myriad of other features that come with ASB.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This would lead you to the pitfall #1 from above: in order to get it right, they had to essentially roll their own messaging infrastructure, so they ended up with two problems instead of solving the first one.&lt;/p&gt;

&lt;p&gt;Treat the root problem, not the symptom.&lt;/p&gt;

&lt;p&gt;&lt;a class=&quot;img-link&quot; href=&quot;https://xkcd.com/1739/&quot;&gt;&lt;img src=&quot;https://imgs.xkcd.com/comics/fixing_problems.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;em&gt;‘What was the original problem you were trying to fix?’ ‘Well, I noticed one of the tools I was using had an inefficiency that was wasting my time.’&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;3-use-shared-topics-and-a-pub-sub-pattern-instead-of-queues&quot;&gt;3. Use shared topics and a &lt;a href=&quot;https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern&quot;&gt;pub-sub pattern&lt;/a&gt; instead of queues&lt;/h2&gt;

&lt;p&gt;Imagine the scenario of updating customer contact details in a CRM system which should be reflected in the sales system. There’s only two systems, so it might be tempting to do something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/integrations/p2p_1.png&quot; alt=&quot;Point-to-Point&quot; /&gt;
&lt;em&gt;An exclusive topic/queue for sending a single system’s customer update messages, effectively creating a point-to-point integration.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This might look fine if you’re only starting with a couple systems, however not going down this route is critical for future maintainability.&lt;/p&gt;

&lt;p&gt;Let’s say after some time, the business needs a third legacy system – one that drives many other parts of the business – integrated as well:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/integrations/p2p_3.png&quot; alt=&quot;Point-to-Point&quot; /&gt;
&lt;em&gt;Keep it simple?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There’s several problems with the above:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Single points of failure. Each of the systems being slow or unavailable breaks the link and the data no longer flows to the next system. This actually caused one of the client’s main systems to have data that was weeks old until the faulty system was properly fixed and processed its backlog of messages.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If, some time later, you add a third integration between the legacy system and CRM like the diagram, all of a sudden you have inadvertently created an integration between all of the systems by forming a circle which may not have been your intention. It also becomes much more difficult to reliably stop infinite loops from happening between all the systems involved where one message keeps going round and round. This can result in invalid data and even more resources being wasted. More on this below about having a mechanism to stop infinite message loops.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to have redundancy, you’ll end up having to integrate each system with all the other ones:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/integrations/p2p_2.png&quot; alt=&quot;Point-to-Point&quot; /&gt;
&lt;em&gt;Fancy some spaghetti?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;With only 3 systems and one simple message, this is already looking like a mess. As you add more systems and integrations, it becomes exponentially costlier and harder to develop and maintain.&lt;/p&gt;

&lt;p&gt;There are many flavours to these point-to-point integrations and each come with a similar set of problems.&lt;/p&gt;

&lt;p&gt;A much better approach that addresses most of the above issues and is easily maintainable, is a shared &lt;em&gt;topic&lt;/em&gt; that all participating systems publish and subscribe to:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/integrations/pubsub.png&quot; alt=&quot;Point-to-Point&quot; /&gt;
&lt;em&gt;The publishers don’t have to know about the other systems. Any interested system can subscribe to the topic, effectively getting its own queue.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;By using this approach, you further decouple the systems, keep it extensible for plugging new systems and keep complexity and maintenance costs linear. If subscribing systems need to know where a message originated from, that can be included in a standard message body format, or better yet, message properties as they can drive &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/service-bus-messaging/topic-filters&quot;&gt;filters and actions&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;4-be-mindful-of-loops--subscribers-shouldnt-republish&quot;&gt;4. Be mindful of loops – subscribers shouldn’t republish&lt;/h2&gt;

&lt;p&gt;It’s very easy to cause infinite loops that can wreak havoc on all the systems involved. From the above example, it can easily happen if each system received a message from the topic, updates a customer and as a result republishes a CustomerUpdated message back to the topic.&lt;/p&gt;

&lt;p&gt;One solution to this problem that works with the above pub-sub model, is that a system’s action based on a message received from the topic, shouldn’t cause the same message to be republished back to the topic.&lt;/p&gt;

&lt;h2 id=&quot;5-include-domain-event-timestamps-in-messages&quot;&gt;5. Include domain event timestamps in messages&lt;/h2&gt;

&lt;p&gt;Each message should have a &lt;em&gt;domain event&lt;/em&gt; timestamp. I’m not referring to the one that is automatically stamped on messages by the service bus, but one included by your system in the message. The timestamp should describe when the event the message describes happened within that system. &lt;em&gt;e.g.&lt;/em&gt;, you care about when a customer updated their details in a system, not when the message was published and not when another system finally gets around to processing it.&lt;/p&gt;

&lt;p&gt;This provides a means for other systems to not act based on outdated data. e.g. it’s possible that by the time a subscribing system receives a CustomerUpdated message, it’s already applied a more recent update. A simple timestamp check can prevent the more recent data from being overwritten.&lt;/p&gt;

&lt;p&gt;While you’re at it, make that timestamp a UTC one – or better yet, use a type that unambiguously represents an instant, like &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/standard/datetime/choosing-between-datetime#the-datetimeoffset-structure&quot;&gt;DateTimeOffset&lt;/a&gt; – so you don’t run into time zone conversion and datetime arithmetic issues. You only care about the &lt;em&gt;instant&lt;/em&gt; when something happened, not the local time, and a UTC datetime simply represents that.&lt;/p&gt;

&lt;h2 id=&quot;6-messages-should-be-the-single-source-of-truth&quot;&gt;6. Messages should be the single source of truth&lt;/h2&gt;

&lt;p&gt;&lt;a class=&quot;img-link&quot; href=&quot;https://xkcd.com/246/&quot;&gt;&lt;img src=&quot;https://imgs.xkcd.com/comics/labyrinth_puzzle.png&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;
&lt;em&gt;‘And the whole setup is just a trap to capture escaping logicians.  None of the doors actually lead out.’&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;All necessary information from the publishing system should be self-contained in each published message. That means all the information the subscribing systems need to be able to &lt;em&gt;act&lt;/em&gt; on the message.&lt;/p&gt;

&lt;p&gt;A simple scenario of how breaking this pattern could cause problems:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;The CRM system publishes a CustomerUpdated message that only states a specific customer’s details has been updated, without including the details.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The Sales system makes a call to the CRM API to retrieve the details.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Problems:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;There needs to be a direct means of communication between the two systems, whereas before they only needed to communicate with the messaging infrastructure. This takes away system and network decoupling, one of the major benefits of using a service bus.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;By the time the message is processed by Sales, the CRM API might not even be available.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;It puts additional load on the CRM system since its API would need to be called for each message.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;By the time the message is processed by Sales, the customer details may have been changed again. If the Sales system’s action was dependent on the historical data at the time of the original event, such as auditing, it is going to retrieve inconsistent data.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So keep and treat messages as the single source of truth. On the other hand, don’t include unnecessary information and keep them lightweight to make the most of your topic space.&lt;/p&gt;

&lt;h2 id=&quot;7-have-naming-conventions-for-topics-and-subscriptions&quot;&gt;7. Have naming conventions for topics and subscriptions&lt;/h2&gt;

&lt;p&gt;Each topic and subscription following a naming convention brings many monitoring and troubleshooting upsides:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;As the integrations within the service bus namespace grow it remains easy to find the target topic and subscription.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;You can see what’s going on in your service bus namespace more easily when using an external tool like the &lt;a href=&quot;https://github.com/paolosalvatori/ServiceBusExplorer&quot;&gt;Service Bus Explorer&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;It could potentially drive an automatic monitoring tool that can visualize all the integrations and the flow of data between various systems.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An example of such a convention could be:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Topic Name&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CustomerContactDetailsUpdated&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Topic Subscription Names&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CRM&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Sales&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Legacy&lt;/code&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Like most conventions, the value mainly comes from there being one, rather than the convention per se.&lt;/p&gt;

&lt;h2 id=&quot;8-have-proper-logging-and-monitoring-to-quickly-identify-and-deal-with-issues&quot;&gt;8. Have proper logging and monitoring to quickly identify and deal with issues&lt;/h2&gt;

&lt;p&gt;Integrations, once in place, shouldn’t just become part of a black box that’s your service bus.&lt;/p&gt;

&lt;p&gt;It is crucial to have proper logging and instrumentation and monitoring on top of those in place, to be notified of irregularities as soon as possible. You should have automatic alarm bells for &lt;em&gt;at least&lt;/em&gt; the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;A subscription’s incoming rate becomes consistently higher than its processing rate. This should be fine for short periods of time e.g. traffic spikes. However if it continues your topic would eventually get full.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;A topic’s used space is consistently increasing.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;A subscription’s dead-letter queue message count is consistently increasing.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The above are closely related and are usually a sign that a subscribing system is having issues with processing messages. These issues need to be dealt with ASAP. Depending on how the publishing systems can cope with the topic they’re publishing to being full, it could also lead to problems in those systems. For the client, this accumulated a backlog of failed tasks in a publishing system that was limited and hosted externally. It was hopelessly retrying over and over, unnecessarily using significant resources which affected other parts of the system such as delays in sending important marketing material.&lt;/p&gt;

&lt;p&gt;As a last resort, to stop the topic from getting full, you could set up forwarding to redirect messages for the problematic system to a different backup topic subscription or queue until the problem is resolved. Just &lt;a href=&quot;#2-dont-bypass-your-messaging-infrastructure&quot;&gt;don’t move them to a database&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/monitoring-and-diagnostics/monitoring-overview-azure-monitor&quot;&gt;Azure Monitor&lt;/a&gt; can help here. Having structured logging of important information to a centralized logging server such as &lt;a href=&quot;https://getseq.net/&quot;&gt;Seq&lt;/a&gt; could also be beneficial, however, be careful not to create a lot of noise by logging the world.&lt;/p&gt;

&lt;h2 id=&quot;9-dont-forget-the-dead-letter-queue&quot;&gt;9. Don’t forget the dead-letter queue&lt;/h2&gt;

&lt;p&gt;All queues and topic subscriptions automatically come with a supplementary sub-queue, called the dead-letter queue (DLQ). Messages can end up here for a number of reasons:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;By the engine itself as a result of your messaging entity configurations, e.g. automatically dead-lettering expired messages or filtering evaluation errors.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;By the engine itself as messages exceeds maximum delivery count – which is 10 by default. For example, your subscriber receives the message, but fails to process it due to an exception.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;By the subscriber’s explicit request in message processing code.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-dead-letter-queues#moving-messages-to-the-dlq&quot;&gt;See here&lt;/a&gt; for a complete list and their details.&lt;/p&gt;

&lt;p&gt;These dead-letter queues contribute to the overall used space of the topic, so you should keep an eye on them, using &lt;a href=&quot;#8-have-proper-logging-and-monitoring-to-quickly-identify-and-deal-with-issues&quot;&gt;your monitoring tools&lt;/a&gt;, and empty them regularly via either resubmitting them if they were due to transient errors, or discard them if they were poison messages.&lt;/p&gt;

&lt;h2 id=&quot;10-performance-is-not-just-a-nice-to-have&quot;&gt;10. Performance is not just a nice-to-have&lt;/h2&gt;

&lt;p&gt;Having performant message processors ensures your integrations run smoothly and can withstand traffic spikes without your topics getting full. Here are some tips that can increase performance dramatically:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Use AMQP and avoid HTTP polling. This should be the default if you’re using the &lt;a href=&quot;https://github.com/Azure/azure-sdk-for-net/tree/master/sdk/servicebus/Microsoft.Azure.ServiceBus&quot;&gt;new .NET Standard Service Bus Client library&lt;/a&gt;, you can &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-amqp-overview&quot;&gt;read about the benefits here&lt;/a&gt;. Don’t use &lt;a href=&quot;https://www.nuget.org/packages/WindowsAzure.ServiceBus&quot;&gt;the old library&lt;/a&gt; – most of the documentation around still point to that.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Use the &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.servicebus.subscriptionclient.registermessagehandler?view=azure-dotnet&quot;&gt;asynchronous callback-based message pump API&lt;/a&gt;. Sending/receiving messages to/from the message broker is an inherently IO based asynchronous operation – you shouldn’t hold up threads for them.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Process messages concurrently. Many programmers shy away from writing concurrent code, as it is more complex and error prone. That’s usually a good approach, however &lt;a href=&quot;http://www.gotw.ca/publications/concurrency-ddj.htm&quot;&gt;the free lunch has long been over&lt;/a&gt;, and this is one of the scenarios where having concurrent code really shines. Concurrent code doesn’t mean you have to do unnecessary multithreading. If you use the asynchronous APIs and leverage truly async code where possible, even a single thread can accomplish orders of magnitude more. This needs to be accompanied by proper &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/api/system.threading.semaphoreslim?view=netframework-4.7.2&quot;&gt;asynchronous synchronization&lt;/a&gt; so you don’t, for example, process two messages for the same customer simultaneously.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Keep connections to the service bus alive (&lt;em&gt;i.e.&lt;/em&gt; the clients) and don’t recreate them as that’s expensive. They are designed to be kept alive and reused.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Leverage prefetching with a message lock duration that’s tweaked based on message processing times. When using the default lock expiration of 60 seconds, &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-performance-improvements#prefetching&quot;&gt;Microsoft recommends&lt;/a&gt; 20 times the maximum processing rate of your subscriber. e.g. if the subscriber processes 10 messages per second the prefetch count could be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10 x 20 = 200&lt;/code&gt;. The idea is to prefetch comfortably below the number of messages your subscriber can process, so they aren’t expired by the time it gets around to processing them. You can &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-prefetch&quot;&gt;read more about that here&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Use &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-partitioning&quot;&gt;partitioned topics&lt;/a&gt;. One of their biggest benefits is they can go up to 80GBs in size compared to just 5GBs for unpartitioned ones. That can give you a lot more time to deal with issues explained &lt;a href=&quot;#8-have-proper-logging-and-monitoring-to-quickly-identify-and-deal-with-issues&quot;&gt;above&lt;/a&gt; and you almost never need to worry about them getting full. But they also have better throughput, performance and reliability. There’s really no good reason for not using them.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By combining the above approaches, I improved the processing time on a critical subscription for the client from ~15 seconds to ~3 seconds per message and the message processing rate per hour from ~240 to ~12000.&lt;/p&gt;

&lt;h2 id=&quot;11-have-message-versioning-and-remain-backward-compatible&quot;&gt;11. Have message versioning and remain backward compatible&lt;/h2&gt;

&lt;p&gt;It’s only a matter of when, not if, that your messages need to be changed. To make moving forward easier and seamless, have a message versioning strategy to start with and make those changes in a backward compatible way.&lt;/p&gt;

&lt;p&gt;Prepare yourself for the situation that different subscriptions of a single topic contain different message versions. This allows subscribers to be upgraded at their own pace, while not blocking those that can process the new version.&lt;/p&gt;

&lt;p&gt;Old message versions can ultimately be retired when all subscribers are upgraded.&lt;/p&gt;

&lt;h2 id=&quot;12-have-idempotent-subscribers&quot;&gt;12. Have idempotent subscribers&lt;/h2&gt;

&lt;p&gt;Even with other measures in place such as &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/service-bus-messaging/duplicate-detection&quot;&gt;duplicate detection&lt;/a&gt;. It’s highly likely that your subscriber receives the same message twice. For example, this happens when during the time a subscriber is processing a message, the message’s lock expires and it is released back to the subscription queue. So you have to make sure your subscribers process messages idempotently. This can be achieved via various mechanisms depending on your circumstance, but checking against &lt;a href=&quot;#5-include-event-timestamps-in-messages&quot;&gt;message timestamps&lt;/a&gt; or unique message IDs can be a simple effective measure.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;In conclusion, service buses, like any other tool in our toolbox, can be misused, perhaps more easily than some of the others, which has led to many hating them. But they are powerful and very beneficial in the right situation. Following the above guidelines should help you build a solid foundation for large-scale integrations over service buses and not end up with huge improvement costs – because &lt;a href=&quot;https://stevemcconnell.com/articles/upstream-decisions-downstream-costs/&quot;&gt;changing upstream design costs exponentially more downstream&lt;/a&gt;.&lt;/p&gt;</content><author><name>Saeb Amini</name></author><summary type="html">Integrating systems over a good messaging infrastructure has many benefits if done right. Some of these are system/network decoupling and platform agnosticism, independent scalability, high reliability, spike protection, a central place to keep an eye on your integrations and more depending on your situation.</summary></entry><entry><title type="html">The Dangerous EF Core Feature: Automatic Client Evaluation</title><link href="http://saebamini.com/the-dangerous-ef-core-feature-automatic-client-evaluation/" rel="alternate" type="text/html" title="The Dangerous EF Core Feature: Automatic Client Evaluation" /><published>2018-07-08T00:00:00+00:00</published><updated>2018-07-08T00:00:00+00:00</updated><id>http://saebamini.com/the-dangerous-ef-core-feature-automatic-client-evaluation</id><content type="html" xml:base="http://saebamini.com/the-dangerous-ef-core-feature-automatic-client-evaluation/">&lt;h4 id=&quot;update-starting-from-ef-core-30-preview-4-this-damaging-default-behavior-has-been-greatly-limited-although-not-completely-turned-off&quot;&gt;&lt;em&gt;Update: starting from EF Core 3.0-preview 4, &lt;a href=&quot;https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-3.0/breaking-changes#linq-queries-are-no-longer-evaluated-on-the-client&quot;&gt;this damaging default behavior has been greatly limited, although not completely turned off&lt;/a&gt;.&lt;/em&gt;&lt;/h4&gt;

&lt;p&gt;Recently when going through our shiny new ASP.NET Core application’s logs, I spotted a few entries like this:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The LINQ expression ‘foo’ could not be translated and will be evaluated locally.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Odd.&lt;/p&gt;

&lt;p&gt;I dug around in the code and found the responsible queries. Some of them were quite complex with many joins and groupings, while some of the other ones were quite simple&lt;!--more--&gt;, like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;someStringField.Contains(&quot;bar&quot;, StringComparison.OrdinalIgnoreCase)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You may have spotted the problem right away. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;StringComparison.OrdinalIgnoreCase&lt;/code&gt; is a .NET concept. It doesn’t translate to SQL and EF Core can’t be blamed for that. In fact, if you run the same query in the classic Entity Framework, you’ll get a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NotSupportedException&lt;/code&gt; telling you it can’t convert your perdicate to a SQL expression and that’s a &lt;em&gt;good&lt;/em&gt; thing, because it prompts you to review your query and if you &lt;em&gt;really&lt;/em&gt; want to have a predicate in your query that only applies in the CLR world, &lt;em&gt;you&lt;/em&gt; can decide if it makes sense in your case to do a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ToList()&lt;/code&gt; or similar at some point in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IQueryable&lt;/code&gt; to pull down the results of your query from the database into memory, or you may decide that you don’t need that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;StringComparison.OrdinalIgnoreCase&lt;/code&gt; after all, because your database collation is case-insensitive anyway.&lt;/p&gt;

&lt;p&gt;The point is that, by default &lt;em&gt;you&lt;/em&gt; are in control and can make explicit decisions based on your circumstances.&lt;/p&gt;

&lt;p&gt;That’s unfortunately not the case in Entity Framework Core because of its concept of &lt;a href=&quot;https://docs.microsoft.com/en-us/ef/core/querying/client-eval&quot;&gt;mixed client/server evaluation&lt;/a&gt;. What mixed evaluation effectively does is, if you have anything in an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IQueryable&lt;/code&gt; LINQ query that can’t be translated to SQL, it tries to magically and silently make it work for you, by taking the untranslatable bits out and running them locally… and it’s enabled by &lt;em&gt;default&lt;/em&gt;! what could go wrong?&lt;/p&gt;

&lt;p&gt;That’s an extremely dangerous behavior change compared to the good old Entity Framework. Consider this entity:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Person&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FirstName&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LastName&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Addresses&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Orders&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And this query:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dbContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Persons&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Addresses&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Orders&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LastName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Amini&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StringComparison&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrdinalIgnoreCase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;EF Core can’t translate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;p.LastName.Equals(&quot;Amini&quot;, StringComparison.OrdinalIgnoreCase)&lt;/code&gt; into a query that can be run on the database, so it pulls down the &lt;em&gt;whole&lt;/em&gt; Persons table, as well as the &lt;em&gt;whole&lt;/em&gt; Orders and Addresses tables from the database into the memory and &lt;em&gt;then&lt;/em&gt; runs the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.Where(p =&amp;gt; p.LastName.Equals(&quot;Amini&quot;, StringComparison.OrdinalIgnoreCase))&lt;/code&gt; filter on the results &lt;span style=&quot;font-size: 3em&quot;&gt;🤦🏻‍♂️&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The fact that this behavior is enabled by default is &lt;em&gt;mind blowing&lt;/em&gt;! It’s not hard to imagine the performance repercussions of that on any real-size application with significant usage. It can easily bring down applications to their knees. Frameworks should make it difficult to make mistakes, especially ones with potentially devastating consequences like this.&lt;/p&gt;

&lt;p&gt;You might be thinking that it’s the developer’s fault for including something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;StringComparison.OrdinalIgnoreCase&lt;/code&gt; in the IQueryable prediate, but having untranslatable things like that in your query isn’t the only culprit that results in client evaluation. If you &lt;a href=&quot;https://github.com/aspnet/EntityFrameworkCore/issues/6245&quot;&gt;have&lt;/a&gt; too many &lt;a href=&quot;https://stackoverflow.com/questions/45237492/ef-core-could-not-be-translated-and-will-be-evaluated-locally&quot;&gt;joins&lt;/a&gt; or &lt;a href=&quot;https://github.com/aspnet/EntityFrameworkCore/issues/12255&quot;&gt;groupings&lt;/a&gt;, the query could become too complex for EF Core and make it fall back to local evaluation.&lt;/p&gt;

&lt;p&gt;So if you’re using EF Core, you want to keep an eye on your logs to spot client evaluations. If you don’t want that additional cognitive overhead, you can disable it altogether and make it throw like the good old Entity Framework:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;cm&quot;&gt;/* Startup.cs */&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ConfigureServices&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IServiceCollection&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddDbContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;YourContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;optionsBuilder&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;optionsBuilder&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;UseSqlServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;@&quot;Server=(localdb)\mssqllocaldb;Database=EFQuerying;Trusted_Connection=True;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ConfigureWarnings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;warnings&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;warnings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Throw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RelationalEventId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;QueryClientEvaluationWarning&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;cm&quot;&gt;/* Or in your context's OnConfiguring method */&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OnConfiguring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DbContextOptionsBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;optionsBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;optionsBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ConfigureWarnings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;warnings&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;warnings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Throw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RelationalEventId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;QueryClientEvaluationWarning&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;However, I found that disabling client evaluation made EF core so limited, that it became practically unusable. That’s why I’m staying away from it for now and will re-evaluate it when version 3 is out to see if it’s production-ready yet.&lt;/p&gt;</content><author><name>Saeb Amini</name></author><summary type="html">Update: starting from EF Core 3.0-preview 4, this damaging default behavior has been greatly limited, although not completely turned off.</summary></entry><entry><title type="html">Create Your Own Visual Studio Code Snippets</title><link href="http://saebamini.com/create-your-own-visual-studio-code-snippets/" rel="alternate" type="text/html" title="Create Your Own Visual Studio Code Snippets" /><published>2016-01-18T00:00:00+00:00</published><updated>2016-01-18T00:00:00+00:00</updated><id>http://saebamini.com/create-your-own-visual-studio-code-snippets</id><content type="html" xml:base="http://saebamini.com/create-your-own-visual-studio-code-snippets/">&lt;p&gt;Visual Studio &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/ms165392.aspx&quot;&gt;Code Snippets&lt;/a&gt; are awesome productivity enhancers; I can only imagine how many millions of keystrokes I’ve saved over the years by making a habit out of using them.&lt;/p&gt;

&lt;p&gt;Although a lot of common code you use daily might not be available out of the box, adding them yourself is very simple&lt;!--more--&gt;.&lt;/p&gt;

&lt;p&gt;Here are some samples for creating &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Console.ReadLine&lt;/code&gt; &amp;amp; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Console.ReadKey&lt;/code&gt; snippets:&lt;/p&gt;

&lt;p&gt;Console.ReadLine:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;CodeSnippets&lt;/span&gt;  &lt;span class=&quot;na&quot;&gt;xmlns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;CodeSnippet&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Format=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1.0.0&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;Header&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;Title&amp;gt;&lt;/span&gt;cr&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Title&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;Shortcut&amp;gt;&lt;/span&gt;cr&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Shortcut&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;Description&amp;gt;&lt;/span&gt;Code snippet for Console.ReadLine&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Description&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;Author&amp;gt;&lt;/span&gt;Community&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Author&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;SnippetTypes&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;SnippetType&amp;gt;&lt;/span&gt;Expansion&lt;span class=&quot;nt&quot;&gt;&amp;lt;/SnippetType&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/SnippetTypes&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Header&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;Snippet&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;Declarations&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;Literal&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Editable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;ID&amp;gt;&lt;/span&gt;SystemConsole&lt;span class=&quot;nt&quot;&gt;&amp;lt;/ID&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;Function&amp;gt;&lt;/span&gt;SimpleTypeName(global::System.Console)&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Function&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Literal&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Declarations&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;Code&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Language=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;csharp&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;cp&quot;&gt;&amp;lt;![CDATA[$SystemConsole$.ReadLine();$end$]]&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Code&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Snippet&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/CodeSnippet&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/CodeSnippets&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Console.ReadKey:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;CodeSnippets&lt;/span&gt;  &lt;span class=&quot;na&quot;&gt;xmlns=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;CodeSnippet&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Format=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1.0.0&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;Header&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;Title&amp;gt;&lt;/span&gt;ck&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Title&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;Shortcut&amp;gt;&lt;/span&gt;ck&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Shortcut&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;Description&amp;gt;&lt;/span&gt;Code snippet for Console.ReadKey&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Description&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;Author&amp;gt;&lt;/span&gt;Community&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Author&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;SnippetTypes&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;SnippetType&amp;gt;&lt;/span&gt;Expansion&lt;span class=&quot;nt&quot;&gt;&amp;lt;/SnippetType&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/SnippetTypes&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Header&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;Snippet&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;Declarations&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;Literal&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Editable=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;ID&amp;gt;&lt;/span&gt;SystemConsole&lt;span class=&quot;nt&quot;&gt;&amp;lt;/ID&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;Function&amp;gt;&lt;/span&gt;SimpleTypeName(global::System.Console)&lt;span class=&quot;nt&quot;&gt;&amp;lt;/Function&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Literal&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Declarations&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;Code&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;Language=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;csharp&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;cp&quot;&gt;&amp;lt;![CDATA[$SystemConsole$.ReadKey();$end$]]&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Code&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/Snippet&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/CodeSnippet&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/CodeSnippets&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;You can save the above as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.snippet&lt;/code&gt; files and then import them via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Tools &amp;gt; Code Snippet Manager... &amp;gt; Import...&lt;/code&gt; and use them by typing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cr&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ck&lt;/code&gt; and hitting &lt;kbd&gt;TAB&lt;/kbd&gt; twice.&lt;/p&gt;

&lt;p&gt;So go ahead and create handy ones for things you find yourself typing all the time. You can refer to this &lt;a href=&quot;https://docs.microsoft.com/en-us/visualstudio/ide/walkthrough-creating-a-code-snippet&quot;&gt;MSDN article for more details&lt;/a&gt;.&lt;/p&gt;</content><author><name>Saeb Amini</name></author><summary type="html">Visual Studio Code Snippets are awesome productivity enhancers; I can only imagine how many millions of keystrokes I’ve saved over the years by making a habit out of using them.</summary></entry></feed>