<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rob</title>
    <description>The latest articles on DEV Community by Rob (@robgeorgemm).</description>
    <link>https://dev.to/robgeorgemm</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F817079%2F354a81c8-cb3e-48cd-bb0a-3eb41e2bd403.png</url>
      <title>DEV Community: Rob</title>
      <link>https://dev.to/robgeorgemm</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/robgeorgemm"/>
    <language>en</language>
    <item>
      <title>December ProductTalk on Continuous Interviewing</title>
      <dc:creator>Rob</dc:creator>
      <pubDate>Thu, 12 Dec 2024 15:31:33 +0000</pubDate>
      <link>https://dev.to/robgeorgemm/product-talk-on-continuous-interviewing-33h7</link>
      <guid>https://dev.to/robgeorgemm/product-talk-on-continuous-interviewing-33h7</guid>
      <description>&lt;p&gt;This article provides a brief summary of a webinar on the topic of continuous interviewing hosted by Teresa Torres from &lt;a href="https://www.producttalk.org/" rel="noopener noreferrer"&gt;Product Talk&lt;/a&gt; on on 4th December 2024.&lt;/p&gt;

&lt;p&gt;Continuous interviewing is a part of the &lt;a href="https://www.producttalk.org/2021/08/product-discovery/" rel="noopener noreferrer"&gt;continuous discovery&lt;/a&gt; framework and is a commitment to weekly touch points with customers to conduct research in purist of a product outcome. Talking to customers is naturally a big part of this. Teresa has also published a &lt;a href="https://www.amazon.co.uk/Continuous-Discovery-Habits-Discover-Products/dp/1736633309" rel="noopener noreferrer"&gt;book&lt;/a&gt; on the topic.&lt;/p&gt;

&lt;p&gt;With continuous discovery there is an emphasis on being outcome first, with cross-functional products teams maintaining at least two research activities to discover opportunities. Opportunities are defined as a customer &lt;code&gt;need&lt;/code&gt;, &lt;code&gt;pain-point&lt;/code&gt; or &lt;code&gt;desire&lt;/code&gt; where solutions provide both business and customer value.&lt;/p&gt;

&lt;p&gt;During this process people make the mistake of using customer interviews as a way to validate solutions or confirm factual behaviours. This is not good practice for discovery. Showing customers a solution and asking what they think invites speculation. One also needs to avoid theoretical questions or scenarios as it invites customers to provide an idealised answer.&lt;/p&gt;

&lt;p&gt;Teresa points out that the sale of gym memberships is largely based on people's false idealised notion of themselves.&lt;/p&gt;

&lt;p&gt;Don't conduct interviews to ask questions that data can tell you.&lt;/p&gt;

&lt;p&gt;Equally, asking theoretical questions triggers people to activate their &lt;a href="https://thedecisionlab.com/reference-guide/philosophy/system-1-and-system-2-thinking" rel="noopener noreferrer"&gt;system 1 thinking&lt;/a&gt;, which is reactionary, efficient and fast but also inaccurate, speculative, bias and prone to error. Instead we want to activate system 2 thinking, which forces our customers to concisely think through their response. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz8tz1ocfvuphvn1obeay.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz8tz1ocfvuphvn1obeay.png" alt="Image description" width="800" height="598"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So how do we trigger system 2 thinking? Well avoid ...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Direct questions leading to short answers.&lt;/li&gt;
&lt;li&gt;Leading questions creating false choices.&lt;/li&gt;
&lt;li&gt;Questions about the future giving unreliable responses.&lt;/li&gt;
&lt;li&gt;Questions that trigger speculation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We want to use our interviews to understand the customers goals with as much context as possible to highlight opportunities for us to pursue.&lt;/p&gt;

&lt;p&gt;Teresa advised the best way to trigger system 2 thinking is to ask questions grounded in specific instances of past behaviours, to force them to use their memory. For example, rather than asking ...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What is your experience watching Netflix?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ask ...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tell me about your last experience watching Netflix?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;instead of asking ...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What are your favourite types of Movies?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ask ...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;What were the last 3 movies you watched?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then build a rich story by expanding questions from there. The interviewee is now replying on memory rather than speculating on a theoretical, which is forcing longer more thoughtful replies.&lt;/p&gt;

&lt;p&gt;Follow up with ...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tell me about the time before that?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do you recall why you watched it?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do you remember facing any challenges or inconvenience?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;How did you decide to pick that movie?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Do you remember how you heard of it?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These questions lead to collecting a story rather than facts. The work of the interviewer is to help the interviewee excavate a story, gently and interactively, we want to get them back to the thinking and emotion of their past decision making.&lt;/p&gt;

&lt;p&gt;Active listening can also present a challenge, as interviewees often flip-flop between specifics and generalisations.&lt;/p&gt;

&lt;p&gt;Follow up links referenced&lt;br&gt;
• &lt;a href="https://www.producttalk.org/2023/12/opportunity-solution-trees/" rel="noopener noreferrer"&gt;Opportunity solution trees&lt;/a&gt;&lt;br&gt;
• &lt;a href="https://www.producttalk.org/2023/10/assumption-testing/" rel="noopener noreferrer"&gt;Assumption testing&lt;/a&gt;&lt;br&gt;
• &lt;a href="https://www.producttalk.org/2024/02/interview-snapshot/" rel="noopener noreferrer"&gt;Interview snapshots&lt;/a&gt;&lt;br&gt;
• &lt;a href="https://www.momtestbook.com/" rel="noopener noreferrer"&gt;The Mom test&lt;/a&gt;&lt;/p&gt;

</description>
      <category>product</category>
      <category>discovery</category>
      <category>interview</category>
    </item>
    <item>
      <title>F# Http Request</title>
      <dc:creator>Rob</dc:creator>
      <pubDate>Wed, 17 Aug 2022 12:14:00 +0000</pubDate>
      <link>https://dev.to/robgeorgemm/f-http-request-with-try-catch-logs-2l3b</link>
      <guid>https://dev.to/robgeorgemm/f-http-request-with-try-catch-logs-2l3b</guid>
      <description>&lt;p&gt;The purpose of this article is to give you an example of making a HTTP request in F# wrapped in a &lt;code&gt;try-catch&lt;/code&gt; with a &lt;code&gt;cancellation token&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The example was built in a &lt;code&gt;console application&lt;/code&gt; using &lt;code&gt;.NET 6&lt;/code&gt; and requires the below packages&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Newtonsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Json&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;13.0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It also makes use of the free to use API placeholder service &lt;a href="https://jsonplaceholder.typicode.com/" rel="noopener noreferrer"&gt;JSONPlaceholder&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Paste the below code into your &lt;code&gt;Program.fs&lt;/code&gt; and execute.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;open&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;
&lt;span class="n"&gt;open&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Net&lt;/span&gt;
&lt;span class="n"&gt;open&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Net&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Http&lt;/span&gt;
&lt;span class="n"&gt;open&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Threading&lt;/span&gt;
&lt;span class="n"&gt;open&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tasks&lt;/span&gt;
&lt;span class="n"&gt;open&lt;/span&gt; &lt;span class="n"&gt;Newtonsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Json&lt;/span&gt;

&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
      &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
      &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
      &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;DeserializePost&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;JsonConvert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeserializeObject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;GetItem&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;HttpRequestMessage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;option&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;    

    &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;        
        &lt;span class="k"&gt;try&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HttpStatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OK&lt;/span&gt; &lt;span class="n"&gt;then&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAsStringAsync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DeserializePost&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;None&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt;
        &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;:?&lt;/span&gt; &lt;span class="n"&gt;TaskCanceledException&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s"&gt;$"Task Canceled Exception: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
                                            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;None&lt;/span&gt;
        &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;:?&lt;/span&gt; &lt;span class="n"&gt;TimeoutException&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s"&gt;$"Timeout Exception: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
                                       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;None&lt;/span&gt;
        &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s"&gt;$"General Exception: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;None&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;    
    &lt;span class="c1"&gt;//GET&lt;/span&gt;
    &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;tokenSource&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;CancellationTokenSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tokenSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;      
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getMessage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HttpRequestMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpMethod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"https://jsonplaceholder.typicode.com/posts/1"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GetItem&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="n"&gt;getMessage&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;
        &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;Some&lt;/span&gt;({ &lt;span class="n"&gt;userId&lt;/span&gt; = &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; = &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="n"&gt;title&lt;/span&gt; =
   &lt;span class="s2"&gt;"sunt aut facere repellat provident occaecati excepturi optio reprehenderit"&lt;/span&gt;
  &lt;span class="n"&gt;body&lt;/span&gt; =
   &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="n"&gt;quia&lt;/span&gt; &lt;span class="n"&gt;et&lt;/span&gt; &lt;span class="n"&gt;suscipit&lt;/span&gt;
&lt;span class="n"&gt;suscipit&lt;/span&gt; &lt;span class="n"&gt;recusandae&lt;/span&gt; &lt;span class="n"&gt;consequuntur&lt;/span&gt; &lt;span class="n"&gt;expedita&lt;/span&gt; &lt;span class="n"&gt;et&lt;/span&gt; &lt;span class="n"&gt;cum&lt;/span&gt;
&lt;span class="n"&gt;reprehenderit&lt;/span&gt; &lt;span class="n"&gt;molestiae&lt;/span&gt; &lt;span class="n"&gt;ut&lt;/span&gt; &lt;span class="n"&gt;ut&lt;/span&gt; &lt;span class="n"&gt;quas&lt;/span&gt; &lt;span class="n"&gt;totam&lt;/span&gt;
&lt;span class="n"&gt;nostrum&lt;/span&gt; &lt;span class="n"&gt;rerum&lt;/span&gt; &lt;span class="n"&gt;est&lt;/span&gt; &lt;span class="n"&gt;autem&lt;/span&gt; &lt;span class="n"&gt;sunt&lt;/span&gt; &lt;span class="n"&gt;rem&lt;/span&gt; &lt;span class="n"&gt;eveniet&lt;/span&gt; &lt;span class="n"&gt;architecto&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Further Readings&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Making F# HTTP calls using either System.Net.Http, Http.Fs or Flurl -&amp;gt; &lt;a href="https://www.encora.com/insights/making-http-requests-in-f" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;br&gt;
Configuring Serilog into F# -&amp;gt; &lt;a href="https://dev.to/robmulpeter/implement-serilog-into-f-297g"&gt;Here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>fsharp</category>
      <category>programming</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>F# : using List.exists on record types may cause breaking changes</title>
      <dc:creator>Rob</dc:creator>
      <pubDate>Thu, 28 Jul 2022 10:49:00 +0000</pubDate>
      <link>https://dev.to/robgeorgemm/f-a-implicit-pitfall-when-using-listexists-on-record-types-2b0o</link>
      <guid>https://dev.to/robgeorgemm/f-a-implicit-pitfall-when-using-listexists-on-record-types-2b0o</guid>
      <description>&lt;p&gt;Below are two examples of how you can determine if an expression returns true for a given list.&lt;/p&gt;

&lt;p&gt;Example 1 uses List.exists as per the &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/lists" rel="noopener noreferrer"&gt;Microsoft documentation&lt;/a&gt; and passes the expression and list as the second parameter&lt;/p&gt;

&lt;p&gt;Example 2 uses a pipe to pass List.exist an explicit type of list as per the &lt;a href="https://fsharp.github.io/fsharp-core-docs/reference/fsharp-collections-listmodule.html#exists" rel="noopener noreferrer"&gt;fsharp.org documentation&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Fox&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;itemExists&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Robert"&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt;

    &lt;span class="c1"&gt;//This won't compile: Type mismatch&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;example1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exists&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"X"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt;

    &lt;span class="c1"&gt;//This will compile&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;example2&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exists&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"X"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The Problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The problem here is that for &lt;code&gt;example1&lt;/code&gt; the order of the record types matter and in its above state will not compile with a &lt;code&gt;type mismatch&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The lambda is implicitly determining the type of &lt;code&gt;i&lt;/code&gt; based on &lt;code&gt;name&lt;/code&gt;. But name is shared by both type &lt;code&gt;Person&lt;/code&gt; and type &lt;code&gt;Fox&lt;/code&gt;. It therefore takes the first matching type in the file or namespace from the BOTTOM. In this case i is of type &lt;code&gt;Fox&lt;/code&gt; and is incompatible with the passed &lt;code&gt;person&lt;/code&gt; list.&lt;/p&gt;

&lt;p&gt;Where this becomes dangerous is when your types are spread out through the application or even in a separate library. If a new record type is added with the same property name and type it will result in your consuming application breaking if it were to take the update.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>fsharp</category>
      <category>dotnet</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Manipulating Collections in F# - Basic Examples</title>
      <dc:creator>Rob</dc:creator>
      <pubDate>Fri, 22 Jul 2022 09:18:00 +0000</pubDate>
      <link>https://dev.to/robgeorgemm/f-collection-function-beginner-examples-50d9</link>
      <guid>https://dev.to/robgeorgemm/f-collection-function-beginner-examples-50d9</guid>
      <description>&lt;p&gt;This article is to provide you with some basic examples of collection manipulation in &lt;code&gt;F#&lt;/code&gt; run from a &lt;code&gt;console application&lt;/code&gt; in &lt;code&gt;.NET 6&lt;/code&gt;. The examples are drawn heavily from a series of exercises in &lt;code&gt;Stylish F# 6: Crafting Elegant Functional Code for .NET 6, 2nd Edition, 2021&lt;/code&gt; by &lt;code&gt;Kit Eason&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In order to run the examples you will need to add some initial utility functions and types to the top of your &lt;code&gt;program.fs&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Car&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Model&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
      &lt;span class="n"&gt;Price&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;PriceBand&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Cheap&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Medium&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Expensive&lt;/span&gt;

&lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="n"&gt;FakeData&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Seed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;/// Make an array of 'count' number of random houses.&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;getRandomArrayOfCars&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="n"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;init&lt;/span&gt; &lt;span class="nf"&gt;count&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"Model %i&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
              &lt;span class="n"&gt;Price&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;150_000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;/// Try to get the distance to the nearest garage.&lt;/span&gt;
    &lt;span class="c1"&gt;/// While the 'Car' parameter is not used we add it to change the signature&lt;/span&gt;
    &lt;span class="c1"&gt;/// Allowing us to pipe into it later with a Car object&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;tryGetDistanceToGarage&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;car&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Car&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;dist&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;dist&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt; &lt;span class="n"&gt;then&lt;/span&gt;
            &lt;span class="n"&gt;Some&lt;/span&gt; &lt;span class="n"&gt;dist&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
            &lt;span class="n"&gt;None&lt;/span&gt;

    &lt;span class="c1"&gt;// Return a price band based on price.&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;getPriceCategory&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;        
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;40_000m&lt;/span&gt; &lt;span class="n"&gt;then&lt;/span&gt;
            &lt;span class="n"&gt;Cheap&lt;/span&gt;
        &lt;span class="n"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;100_000m&lt;/span&gt; &lt;span class="n"&gt;then&lt;/span&gt;
            &lt;span class="n"&gt;Medium&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
            &lt;span class="n"&gt;Expensive&lt;/span&gt;            

&lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="n"&gt;Array&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;tryAverageBy&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="n"&gt;then&lt;/span&gt;
            &lt;span class="n"&gt;None&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;average&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;averageBy&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;decimal&lt;/span&gt;
            &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;average&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Some&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you can add the below examples and execute them with &lt;code&gt;dotnet run&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Transforming Data Items&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getCarListing&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s"&gt;"\n------ TRANSFORMING DATA ------"&lt;/span&gt; 
    &lt;span class="n"&gt;FakeData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getRandomArrayOfCars&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
    &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s"&gt;$"Model: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; - Price: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Price&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Calculating an Average&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getAverageCarPrice&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s"&gt;"\n-------- AVERAGE PRICE --------"&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FakeData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getRandomArrayOfCars&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
                &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;averageBy&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s"&gt;$"Average price: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;// Selecting Based on Condition, Order and iteration&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getExpensiveCars&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s"&gt;"\n------- EXPENSIVE CARS --------"&lt;/span&gt;
    &lt;span class="n"&gt;FakeData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getRandomArrayOfCars&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
    &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Price&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;100_000m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sortByDescending&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;iter&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s"&gt;$"Model: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; - Price: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Price&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Finding a Single Element&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getCarWithDistanceToGarage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s"&gt;"\n- CAR WITH DISTANCE TO GARAGE -"&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FakeData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getRandomArrayOfCars&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
                 &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tryPick&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
                    &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;FakeData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tryGetDistanceToGarage&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
                    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Some&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;None&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;getCarsByPriceCategory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s"&gt;"\n--- CAR WITH PRICE CATEGORY ---"&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FakeData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getRandomArrayOfCars&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;
                 &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;groupBy&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Price&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;FakeData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getPriceCategory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                 &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="k"&gt;group&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
                    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cars&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;group&lt;/span&gt;
                    &lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cars&lt;/span&gt; &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sortBy&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Price&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;tryGetAverageCarPriceOver100K&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s"&gt;"\n--- AVERAGE PRICE OVER 100K ---"&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FakeData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getRandomArrayOfCars&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
                 &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Price&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;100_000m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                 &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tryAverageBy&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Price&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;         
    &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;------ &lt;span class="n"&gt;TRANSFORMING&lt;/span&gt; &lt;span class="n"&gt;DATA&lt;/span&gt; ------
&lt;span class="n"&gt;Model&lt;/span&gt;: &lt;span class="n"&gt;Model&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; - &lt;span class="n"&gt;Price&lt;/span&gt;: &lt;span class="m"&gt;44813&lt;/span&gt;
&lt;span class="n"&gt;Model&lt;/span&gt;: &lt;span class="n"&gt;Model&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; - &lt;span class="n"&gt;Price&lt;/span&gt;: &lt;span class="m"&gt;25504&lt;/span&gt;
&lt;span class="n"&gt;Model&lt;/span&gt;: &lt;span class="n"&gt;Model&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; - &lt;span class="n"&gt;Price&lt;/span&gt;: &lt;span class="m"&gt;75381&lt;/span&gt;

-------- &lt;span class="n"&gt;AVERAGE&lt;/span&gt; &lt;span class="n"&gt;PRICE&lt;/span&gt; --------
&lt;span class="n"&gt;Average&lt;/span&gt; &lt;span class="n"&gt;price&lt;/span&gt;: &lt;span class="m"&gt;73004&lt;/span&gt;.&lt;span class="m"&gt;4&lt;/span&gt;

------- &lt;span class="n"&gt;EXPENSIVE&lt;/span&gt; &lt;span class="n"&gt;CARS&lt;/span&gt; --------
&lt;span class="n"&gt;Model&lt;/span&gt;: &lt;span class="n"&gt;Model&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; - &lt;span class="n"&gt;Price&lt;/span&gt;: &lt;span class="m"&gt;148567&lt;/span&gt;
&lt;span class="n"&gt;Model&lt;/span&gt;: &lt;span class="n"&gt;Model&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt; - &lt;span class="n"&gt;Price&lt;/span&gt;: &lt;span class="m"&gt;142968&lt;/span&gt;
&lt;span class="n"&gt;Model&lt;/span&gt;: &lt;span class="n"&gt;Model&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt; - &lt;span class="n"&gt;Price&lt;/span&gt;: &lt;span class="m"&gt;108595&lt;/span&gt;
&lt;span class="n"&gt;Model&lt;/span&gt;: &lt;span class="n"&gt;Model&lt;/span&gt; &lt;span class="m"&gt;7&lt;/span&gt; - &lt;span class="n"&gt;Price&lt;/span&gt;: &lt;span class="m"&gt;108251&lt;/span&gt;
&lt;span class="n"&gt;Model&lt;/span&gt;: &lt;span class="n"&gt;Model&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; - &lt;span class="n"&gt;Price&lt;/span&gt;: &lt;span class="m"&gt;105497&lt;/span&gt;
&lt;span class="n"&gt;Model&lt;/span&gt;: &lt;span class="n"&gt;Model&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; - &lt;span class="n"&gt;Price&lt;/span&gt;: &lt;span class="m"&gt;101684&lt;/span&gt;

- &lt;span class="n"&gt;CAR&lt;/span&gt; &lt;span class="n"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;DISTANCE&lt;/span&gt; &lt;span class="n"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;GARAGE&lt;/span&gt; -
&lt;span class="n"&gt;Some&lt;/span&gt;(({ &lt;span class="n"&gt;Model&lt;/span&gt; = &lt;span class="s2"&gt;"Model 1"&lt;/span&gt;
  &lt;span class="n"&gt;Price&lt;/span&gt; = &lt;span class="m"&gt;63475&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt; }, &lt;span class="m"&gt;15&lt;/span&gt;))

--- &lt;span class="n"&gt;CAR&lt;/span&gt; &lt;span class="n"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;PRICE&lt;/span&gt; &lt;span class="n"&gt;CATEGORY&lt;/span&gt; ---
(&lt;span class="n"&gt;Cheap&lt;/span&gt;, &lt;span class="n"&gt;Program&lt;/span&gt;+&lt;span class="n"&gt;Car&lt;/span&gt;[])

--- &lt;span class="n"&gt;AVERAGE&lt;/span&gt; &lt;span class="n"&gt;PRICE&lt;/span&gt; &lt;span class="n"&gt;OVER&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt; ---
&lt;span class="n"&gt;Some&lt;/span&gt;(&lt;span class="m"&gt;120609&lt;/span&gt;.&lt;span class="m"&gt;44&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>fsharp</category>
      <category>beginners</category>
      <category>dotnet</category>
      <category>programming</category>
    </item>
    <item>
      <title>F# Convert a List of Type A to Type B with options</title>
      <dc:creator>Rob</dc:creator>
      <pubDate>Thu, 21 Jul 2022 16:42:43 +0000</pubDate>
      <link>https://dev.to/robgeorgemm/f-convert-a-list-of-type-a-to-type-b-with-options-82e</link>
      <guid>https://dev.to/robgeorgemm/f-convert-a-list-of-type-a-to-type-b-with-options-82e</guid>
      <description>&lt;p&gt;The purpose of this article is a small demonstration of how one can convert a list of one type to another type in F#. While 'Convert' is used in the header, this is really using the 'map' function and returning an entirely new list.&lt;/p&gt;

&lt;p&gt;The below code was written in a &lt;code&gt;console application&lt;/code&gt; in &lt;code&gt;.NET 6&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;    
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Employee&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;ConvertPersonToEmployee&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Employee&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"@fsharp.com"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;ConvertPersonListToEmployeeList&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;people&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Employee&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;None&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;None&lt;/span&gt;
    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;
           &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="n"&gt;ConvertPersonToEmployee&lt;/span&gt;
           &lt;span class="p"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Some&lt;/span&gt;

&lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;EntryPoint&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;]&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;    

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;januaryJoiners&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Some&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Rob"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Bob"&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;februaryJoiners&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;januaryEmployees&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ConvertPersonListToEmployeeList&lt;/span&gt; &lt;span class="n"&gt;januaryJoiners&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;februaryEmployees&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ConvertPersonListToEmployeeList&lt;/span&gt; &lt;span class="n"&gt;februaryJoiners&lt;/span&gt;

    &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s"&gt;$"January Employees: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;januaryEmployees&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;printfn&lt;/span&gt; &lt;span class="s"&gt;$"February Employees: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;februaryEmployees&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
    &lt;span class="m"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;January&lt;/span&gt; &lt;span class="n"&gt;Employees&lt;/span&gt;: &lt;span class="n"&gt;Some&lt;/span&gt;([{ &lt;span class="n"&gt;email&lt;/span&gt; = &lt;span class="s2"&gt;"Rob@fsharp.com"&lt;/span&gt; }; { &lt;span class="n"&gt;email&lt;/span&gt; = &lt;span class="s2"&gt;"Bob@fsharp.com"&lt;/span&gt; }])
&lt;span class="n"&gt;February&lt;/span&gt; &lt;span class="n"&gt;Employees&lt;/span&gt;: 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>programming</category>
      <category>dotnet</category>
      <category>fsharp</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Configure and implement Serilog into F#</title>
      <dc:creator>Rob</dc:creator>
      <pubDate>Fri, 08 Jul 2022 07:44:00 +0000</pubDate>
      <link>https://dev.to/robgeorgemm/implement-serilog-into-f-297g</link>
      <guid>https://dev.to/robgeorgemm/implement-serilog-into-f-297g</guid>
      <description>&lt;p&gt;The purpose of this article is to demonstrate the code required to implement the Serilog Log into an F# console application.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setup&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The below example was built into a &lt;code&gt;Console Application&lt;/code&gt; using &lt;code&gt;F#&lt;/code&gt; on the &lt;code&gt;.NET 6 Framework&lt;/code&gt;. The following packages were installed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;Serilog&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;2.11&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="nx"&gt;Serilog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sinks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Console&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;4.0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="nx"&gt;Serilog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Formatting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Compact&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="nx"&gt;Serilog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Enrichers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Environment&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;2.2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="nx"&gt;Serilog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Enrichers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Process&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="nx"&gt;Serilog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Enrichers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Span&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;2.3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="nx"&gt;Serilog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Enrichers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Thread&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;3.1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Copy the below code into your &lt;code&gt;Progam.fs&lt;/code&gt; file and run the application. This will print 5 logs to your terminal. The &lt;code&gt;LoggerConfiguration&lt;/code&gt; makes use of several enrichers to add additional data to the output as well as using &lt;code&gt;RenderedCompactJsonFormatter&lt;/code&gt; which instructs the console writer to output the message in json format.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;open&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;
&lt;span class="n"&gt;open&lt;/span&gt; &lt;span class="n"&gt;Serilog&lt;/span&gt;
&lt;span class="n"&gt;open&lt;/span&gt; &lt;span class="n"&gt;Serilog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Formatting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Compact&lt;/span&gt;

&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;On&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;Created&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;
    &lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;MessageSome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt;
    &lt;span class="n"&gt;MessageNone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;EntryPoint&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;]&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;

  &lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;-&lt;/span&gt;
    &lt;span class="nf"&gt;LoggerConfiguration&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MinimumLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Enrich&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromLogContext&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Enrich&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithEnvironmentName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Enrich&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithMachineName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Enrich&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithThreadId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Enrich&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithProcessId&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteTo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;RenderedCompactJsonFormatter&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateLogger&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;dummyData&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;On&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
        &lt;span class="n"&gt;Created&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt;
        &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Content"&lt;/span&gt;
        &lt;span class="n"&gt;MessageSome&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Some&lt;/span&gt; &lt;span class="s"&gt;"Content"&lt;/span&gt;
        &lt;span class="n"&gt;MessageNone&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;None&lt;/span&gt;    
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt;          
          &lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{dummyData}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dummyData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Information&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{dummyData}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dummyData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;      
          &lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{dummyData}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dummyData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{dummyData}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dummyData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{dummyData}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dummyData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

          &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
      &lt;span class="k"&gt;with&lt;/span&gt;
         &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
             &lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Error: %s&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
             &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="k"&gt;finally&lt;/span&gt;
      &lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CloseAndFlush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;{&lt;span class="s2"&gt;"@t"&lt;/span&gt;:&lt;span class="s2"&gt;"2022-07-08T07:49:44.0016610Z"&lt;/span&gt;,&lt;span class="s2"&gt;"@m"&lt;/span&gt;:&lt;span class="s2"&gt;"\"&lt;/span&gt;{ &lt;span class="n"&gt;Id&lt;/span&gt; = &lt;span class="m"&gt;1&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;On&lt;/span&gt; = &lt;span class="n"&gt;true&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;Created&lt;/span&gt; = &lt;span class="m"&gt;07&lt;/span&gt;/&lt;span class="m"&gt;08&lt;/span&gt;/&lt;span class="m"&gt;2022&lt;/span&gt; &lt;span class="m"&gt;07&lt;/span&gt;:&lt;span class="m"&gt;49&lt;/span&gt;:&lt;span class="m"&gt;44&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;Message&lt;/span&gt; = \\\&lt;span class="s2"&gt;"Content\\\"&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;MessageSome&lt;/span&gt; = &lt;span class="n"&gt;Some&lt;/span&gt; \\\&lt;span class="s2"&gt;"Content\\\"&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;MessageNone&lt;/span&gt; = &lt;span class="n"&gt;None&lt;/span&gt; }\&lt;span class="s2"&gt;""&lt;/span&gt;,&lt;span class="s2"&gt;"@i"&lt;/span&gt;:&lt;span class="s2"&gt;"60a52653"&lt;/span&gt;,&lt;span class="s2"&gt;"@l"&lt;/span&gt;:&lt;span class="s2"&gt;"Debug"&lt;/span&gt;,&lt;span class="s2"&gt;"dummyData"&lt;/span&gt;:&lt;span class="s2"&gt;"{ Id = 1\n  On = true\n  Created = 07/08/2022 07:49:44\n  Message = \"&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;\&lt;span class="s2"&gt;"\n  MessageSome = Some \"&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;\&lt;span class="s2"&gt;"\n  MessageNone = None }"&lt;/span&gt;,&lt;span class="s2"&gt;"EnvironmentName"&lt;/span&gt;:&lt;span class="s2"&gt;"Production"&lt;/span&gt;,&lt;span class="s2"&gt;"MachineName"&lt;/span&gt;:&lt;span class="s2"&gt;"X-MAC"&lt;/span&gt;,&lt;span class="s2"&gt;"ThreadId"&lt;/span&gt;:&lt;span class="m"&gt;1&lt;/span&gt;,&lt;span class="s2"&gt;"ProcessId"&lt;/span&gt;:&lt;span class="m"&gt;69944&lt;/span&gt;}
{&lt;span class="s2"&gt;"@t"&lt;/span&gt;:&lt;span class="s2"&gt;"2022-07-08T07:49:44.1605920Z"&lt;/span&gt;,&lt;span class="s2"&gt;"@m"&lt;/span&gt;:&lt;span class="s2"&gt;"\"&lt;/span&gt;{ &lt;span class="n"&gt;Id&lt;/span&gt; = &lt;span class="m"&gt;1&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;On&lt;/span&gt; = &lt;span class="n"&gt;true&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;Created&lt;/span&gt; = &lt;span class="m"&gt;07&lt;/span&gt;/&lt;span class="m"&gt;08&lt;/span&gt;/&lt;span class="m"&gt;2022&lt;/span&gt; &lt;span class="m"&gt;07&lt;/span&gt;:&lt;span class="m"&gt;49&lt;/span&gt;:&lt;span class="m"&gt;44&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;Message&lt;/span&gt; = \\\&lt;span class="s2"&gt;"Content\\\"&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;MessageSome&lt;/span&gt; = &lt;span class="n"&gt;Some&lt;/span&gt; \\\&lt;span class="s2"&gt;"Content\\\"&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;MessageNone&lt;/span&gt; = &lt;span class="n"&gt;None&lt;/span&gt; }\&lt;span class="s2"&gt;""&lt;/span&gt;,&lt;span class="s2"&gt;"@i"&lt;/span&gt;:&lt;span class="s2"&gt;"60a52653"&lt;/span&gt;,&lt;span class="s2"&gt;"dummyData"&lt;/span&gt;:&lt;span class="s2"&gt;"{ Id = 1\n  On = true\n  Created = 07/08/2022 07:49:44\n  Message = \"&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;\&lt;span class="s2"&gt;"\n  MessageSome = Some \"&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;\&lt;span class="s2"&gt;"\n  MessageNone = None }"&lt;/span&gt;,&lt;span class="s2"&gt;"EnvironmentName"&lt;/span&gt;:&lt;span class="s2"&gt;"Production"&lt;/span&gt;,&lt;span class="s2"&gt;"MachineName"&lt;/span&gt;:&lt;span class="s2"&gt;"X-MAC"&lt;/span&gt;,&lt;span class="s2"&gt;"ThreadId"&lt;/span&gt;:&lt;span class="m"&gt;1&lt;/span&gt;,&lt;span class="s2"&gt;"ProcessId"&lt;/span&gt;:&lt;span class="m"&gt;69944&lt;/span&gt;}
{&lt;span class="s2"&gt;"@t"&lt;/span&gt;:&lt;span class="s2"&gt;"2022-07-08T07:49:44.1611770Z"&lt;/span&gt;,&lt;span class="s2"&gt;"@m"&lt;/span&gt;:&lt;span class="s2"&gt;"\"&lt;/span&gt;{ &lt;span class="n"&gt;Id&lt;/span&gt; = &lt;span class="m"&gt;1&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;On&lt;/span&gt; = &lt;span class="n"&gt;true&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;Created&lt;/span&gt; = &lt;span class="m"&gt;07&lt;/span&gt;/&lt;span class="m"&gt;08&lt;/span&gt;/&lt;span class="m"&gt;2022&lt;/span&gt; &lt;span class="m"&gt;07&lt;/span&gt;:&lt;span class="m"&gt;49&lt;/span&gt;:&lt;span class="m"&gt;44&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;Message&lt;/span&gt; = \\\&lt;span class="s2"&gt;"Content\\\"&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;MessageSome&lt;/span&gt; = &lt;span class="n"&gt;Some&lt;/span&gt; \\\&lt;span class="s2"&gt;"Content\\\"&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;MessageNone&lt;/span&gt; = &lt;span class="n"&gt;None&lt;/span&gt; }\&lt;span class="s2"&gt;""&lt;/span&gt;,&lt;span class="s2"&gt;"@i"&lt;/span&gt;:&lt;span class="s2"&gt;"60a52653"&lt;/span&gt;,&lt;span class="s2"&gt;"@l"&lt;/span&gt;:&lt;span class="s2"&gt;"Warning"&lt;/span&gt;,&lt;span class="s2"&gt;"dummyData"&lt;/span&gt;:&lt;span class="s2"&gt;"{ Id = 1\n  On = true\n  Created = 07/08/2022 07:49:44\n  Message = \"&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;\&lt;span class="s2"&gt;"\n  MessageSome = Some \"&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;\&lt;span class="s2"&gt;"\n  MessageNone = None }"&lt;/span&gt;,&lt;span class="s2"&gt;"EnvironmentName"&lt;/span&gt;:&lt;span class="s2"&gt;"Production"&lt;/span&gt;,&lt;span class="s2"&gt;"MachineName"&lt;/span&gt;:&lt;span class="s2"&gt;"X-MAC"&lt;/span&gt;,&lt;span class="s2"&gt;"ThreadId"&lt;/span&gt;:&lt;span class="m"&gt;1&lt;/span&gt;,&lt;span class="s2"&gt;"ProcessId"&lt;/span&gt;:&lt;span class="m"&gt;69944&lt;/span&gt;}
{&lt;span class="s2"&gt;"@t"&lt;/span&gt;:&lt;span class="s2"&gt;"2022-07-08T07:49:44.1615460Z"&lt;/span&gt;,&lt;span class="s2"&gt;"@m"&lt;/span&gt;:&lt;span class="s2"&gt;"\"&lt;/span&gt;{ &lt;span class="n"&gt;Id&lt;/span&gt; = &lt;span class="m"&gt;1&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;On&lt;/span&gt; = &lt;span class="n"&gt;true&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;Created&lt;/span&gt; = &lt;span class="m"&gt;07&lt;/span&gt;/&lt;span class="m"&gt;08&lt;/span&gt;/&lt;span class="m"&gt;2022&lt;/span&gt; &lt;span class="m"&gt;07&lt;/span&gt;:&lt;span class="m"&gt;49&lt;/span&gt;:&lt;span class="m"&gt;44&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;Message&lt;/span&gt; = \\\&lt;span class="s2"&gt;"Content\\\"&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;MessageSome&lt;/span&gt; = &lt;span class="n"&gt;Some&lt;/span&gt; \\\&lt;span class="s2"&gt;"Content\\\"&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;MessageNone&lt;/span&gt; = &lt;span class="n"&gt;None&lt;/span&gt; }\&lt;span class="s2"&gt;""&lt;/span&gt;,&lt;span class="s2"&gt;"@i"&lt;/span&gt;:&lt;span class="s2"&gt;"60a52653"&lt;/span&gt;,&lt;span class="s2"&gt;"@l"&lt;/span&gt;:&lt;span class="s2"&gt;"Error"&lt;/span&gt;,&lt;span class="s2"&gt;"dummyData"&lt;/span&gt;:&lt;span class="s2"&gt;"{ Id = 1\n  On = true\n  Created = 07/08/2022 07:49:44\n  Message = \"&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;\&lt;span class="s2"&gt;"\n  MessageSome = Some \"&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;\&lt;span class="s2"&gt;"\n  MessageNone = None }"&lt;/span&gt;,&lt;span class="s2"&gt;"EnvironmentName"&lt;/span&gt;:&lt;span class="s2"&gt;"Production"&lt;/span&gt;,&lt;span class="s2"&gt;"MachineName"&lt;/span&gt;:&lt;span class="s2"&gt;"X-MAC"&lt;/span&gt;,&lt;span class="s2"&gt;"ThreadId"&lt;/span&gt;:&lt;span class="m"&gt;1&lt;/span&gt;,&lt;span class="s2"&gt;"ProcessId"&lt;/span&gt;:&lt;span class="m"&gt;69944&lt;/span&gt;}
{&lt;span class="s2"&gt;"@t"&lt;/span&gt;:&lt;span class="s2"&gt;"2022-07-08T07:49:44.1750560Z"&lt;/span&gt;,&lt;span class="s2"&gt;"@m"&lt;/span&gt;:&lt;span class="s2"&gt;"\"&lt;/span&gt;{ &lt;span class="n"&gt;Id&lt;/span&gt; = &lt;span class="m"&gt;1&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;On&lt;/span&gt; = &lt;span class="n"&gt;true&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;Created&lt;/span&gt; = &lt;span class="m"&gt;07&lt;/span&gt;/&lt;span class="m"&gt;08&lt;/span&gt;/&lt;span class="m"&gt;2022&lt;/span&gt; &lt;span class="m"&gt;07&lt;/span&gt;:&lt;span class="m"&gt;49&lt;/span&gt;:&lt;span class="m"&gt;44&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;Message&lt;/span&gt; = \\\&lt;span class="s2"&gt;"Content\\\"&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;MessageSome&lt;/span&gt; = &lt;span class="n"&gt;Some&lt;/span&gt; \\\&lt;span class="s2"&gt;"Content\\\"&lt;/span&gt;\&lt;span class="n"&gt;n&lt;/span&gt;  &lt;span class="n"&gt;MessageNone&lt;/span&gt; = &lt;span class="n"&gt;None&lt;/span&gt; }\&lt;span class="s2"&gt;""&lt;/span&gt;,&lt;span class="s2"&gt;"@i"&lt;/span&gt;:&lt;span class="s2"&gt;"60a52653"&lt;/span&gt;,&lt;span class="s2"&gt;"@l"&lt;/span&gt;:&lt;span class="s2"&gt;"Fatal"&lt;/span&gt;,&lt;span class="s2"&gt;"dummyData"&lt;/span&gt;:&lt;span class="s2"&gt;"{ Id = 1\n  On = true\n  Created = 07/08/2022 07:49:44\n  Message = \"&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;\&lt;span class="s2"&gt;"\n  MessageSome = Some \"&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;\&lt;span class="s2"&gt;"\n  MessageNone = None }"&lt;/span&gt;,&lt;span class="s2"&gt;"EnvironmentName"&lt;/span&gt;:&lt;span class="s2"&gt;"Production"&lt;/span&gt;,&lt;span class="s2"&gt;"MachineName"&lt;/span&gt;:&lt;span class="s2"&gt;"X-MAC"&lt;/span&gt;,&lt;span class="s2"&gt;"ThreadId"&lt;/span&gt;:&lt;span class="m"&gt;1&lt;/span&gt;,&lt;span class="s2"&gt;"ProcessId"&lt;/span&gt;:&lt;span class="m"&gt;69944&lt;/span&gt;}
{&lt;span class="s2"&gt;"@t"&lt;/span&gt;:&lt;span class="s2"&gt;"2022-07-08T07:49:44.1825110Z"&lt;/span&gt;,&lt;span class="s2"&gt;"@m"&lt;/span&gt;:&lt;span class="s2"&gt;"Error: Attempted to divide by zero."&lt;/span&gt;,&lt;span class="s2"&gt;"@i"&lt;/span&gt;:&lt;span class="s2"&gt;"79a82f6d"&lt;/span&gt;,&lt;span class="s2"&gt;"@l"&lt;/span&gt;:&lt;span class="s2"&gt;"Error"&lt;/span&gt;,&lt;span class="s2"&gt;"EnvironmentName"&lt;/span&gt;:&lt;span class="s2"&gt;"Production"&lt;/span&gt;,&lt;span class="s2"&gt;"MachineName"&lt;/span&gt;:&lt;span class="s2"&gt;"X-MAC"&lt;/span&gt;,&lt;span class="s2"&gt;"ThreadId"&lt;/span&gt;:&lt;span class="m"&gt;1&lt;/span&gt;,&lt;span class="s2"&gt;"ProcessId"&lt;/span&gt;:&lt;span class="m"&gt;69944&lt;/span&gt;}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>programming</category>
      <category>fsharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Software documentation is still relevant in certain environments</title>
      <dc:creator>Rob</dc:creator>
      <pubDate>Sun, 24 Apr 2022 11:55:04 +0000</pubDate>
      <link>https://dev.to/robgeorgemm/inspired-to-write-useful-software-documentation-2cm1</link>
      <guid>https://dev.to/robgeorgemm/inspired-to-write-useful-software-documentation-2cm1</guid>
      <description>&lt;p&gt;I am somewhat late to the party but I have recently finished reading 'Inspired: How to Create Tech Products Customers Love' published in 2018 by Marty Cagan from the Silicon Valley Product Group. It's a fantastic read.&lt;/p&gt;

&lt;p&gt;The book was very enlightening and I would highly recommend it to any fellow software engineer in understanding their role in an aspiring product led environment. The language is casual and the content is delivered in short concise chapters, with welcome interjections of high profile product use cases. On this point however, it may have been worth balancing out these successful use cases with some product efforts which for one reason or another went sideways, provided there was a teaching moment in there. We often learn more from the failures than the successes.&lt;/p&gt;

&lt;p&gt;But with all that being said, I did have one bone to pick, the utility of documentation.&lt;/p&gt;

&lt;p&gt;Like many software engineers, the author suggests that code should ideally speak for itself which implies that documenting is not a worthwhile endeavour, and then the topic moves on. This is something I hear very often in industry from software engineers, mainly because the code is being developed faster than someone's ability to update the relevant document but also because software engineers simply do not like doing it.&lt;/p&gt;

&lt;p&gt;This gives a false impression that it's an outdated tool that should be left in the toolbox. But in my experience it depends very much on the environment you are working in, how you create it and what you expect from it.&lt;br&gt;
If you are working in an environment of strong communication, a stable product and a relatively clean codebase developing at a fast pace, then documentation is probably not worth the added expense. This is the ideal. However, if you work in a organisation with weak communication and suffering from extreme technical debt and a sluggish development speed, then documentation is an invaluable and probably essential tool to use. This is especially true if the organisation has plans to turn itself around where documentation can achieve the following:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Saving Investigation Time:&lt;/strong&gt; The author correctly points out that in an environment of extreme technical debt, engineers are often inundated with requests to investigate how a piece of functionality works. A consequence of this continuous tidal wave of requests is that the engineer often does not have time to sensibly refactor or improve that code. So a document here can act as a shield to free up some of that time. Equally, other engineers on the team can find simple answers without time being spent in setting up local environments or requesting environment access.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Remove single points of failure:&lt;/strong&gt; Like writing documentation, few engineers enjoy rolling up their sleeves to deep dive into understanding legacy code, and in an environment of extreme technical debt, this task can be quite horrendous. A resulting document here means that if that engineer later walks out the door, which is not uncommon in these environments, the product team does not need to start from zero.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Bridging tool:&lt;/strong&gt; Documentation can be a useful tool to bridge that gap from technical debt to a cleaner and stable product. For example, your team could be tasked with refactoring a product feature that is driven by 20 unique scripts that largely do the same thing but contain small bespoke functionality for one or more customers. The first step is knowing what makes those 20 variations unique and a single detailed document can map out and communicate that faster and more accurately than any number of engineers.&lt;/p&gt;

&lt;p&gt;Whichever way you lean in respect of your opinion of documentation, writing good documentation is a valuable skill. Do not assume that someone who can write clear software can do the same in plain English for a wider audience to consume. This is an important consideration when judging the utility of your documentation efforts.&lt;br&gt;
I'll end it there 👍&lt;/p&gt;

&lt;p&gt;Other reading materials mentioned in the book include:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;- User Story Mapping (2015 ) Patton, J. et al&lt;/em&gt;&lt;br&gt;
&lt;em&gt;- The Power of Customer Misbehavior (2014) Fisher, M. et al&lt;/em&gt;&lt;br&gt;
&lt;em&gt;- Sprint (2016) Knapp, J. et al&lt;/em&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>programming</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Top Tips for interviewing software developers</title>
      <dc:creator>Rob</dc:creator>
      <pubDate>Fri, 25 Mar 2022 13:29:24 +0000</pubDate>
      <link>https://dev.to/robgeorgemm/interviewing-an-interviewer-advice-on-team-fit-for-developers-hiring-other-developers-da8</link>
      <guid>https://dev.to/robgeorgemm/interviewing-an-interviewer-advice-on-team-fit-for-developers-hiring-other-developers-da8</guid>
      <description>&lt;p&gt;The purpose of this article is to share with you some advice obtained from a professional interviewer with several decades of experience in the field. The reason for obtaining such advice was for our software engineering team to better equip themselves with judging the interpersonal skills, team fit, and general attitude of prospective candidates during an interview process.&lt;/p&gt;

&lt;p&gt;This content is to be understood as general advice from a single individual and discussed in the context of private sector software engineering. Any applications should align with your own industry requirements, values and hiring policies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Structure &amp;amp; Introductions 🖖
&lt;/h3&gt;

&lt;p&gt;The interview process should follow some kind of repeatable and structured design. It will allow for more consistent comparisons of candidates. The candidate will also understand that you are a professional and serious outfit. While there is a huge margin of flexibility to the below points, don't be overly laid back when interviewing.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;b&gt;Length&lt;/b&gt;: An advised interview length is 40 minutes with at least 2 interviewers present. Maintaining a strict time-box will help to counteract wafflers and allow the interviewer to reflect on the quality of information given post-interview. Your questions should be robust enough to fit within the timeframe and compel you to get the right information.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;b&gt;Rounds&lt;/b&gt;: Two rounds of interviews should be plenty to find out what you need to know. This can be supplemented by a technical assignment. The second interview should have one interviewer from the first round and new interviewer. This will allow the team to better evaluate the candidate's behaviour over time. The disadvantage of many rounds of interviews, other than the expense, is that the candidate becomes more comfortable in the latter phases and is likely to start giving more predictable or routine answers to questions. You have a greater chance of honest information and character insights in the earlier interviews.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;b&gt;Introductions&lt;/b&gt;: Every interviewer should give an introduction of who they are and why they are there. It is then advised to give the candidate somewhat of an introduction to the structure or the topics expected to be covered in the interview. This will help keep both the candidate and interviewer on track to obtain the necessary information in the allotted time. Consider explaining to the candidate that you may abruptly change topics. This is not to try throw them off but to ensure we as interviewers get the information we need. This is another tool against rambling.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;b&gt;Topics&lt;/b&gt;: It is common in software engineering to split interviews between technical and interpersonal skills. The issue with this is that you may lose an excellent candidate prematurely or keep an undesirable candidate in the process longer than needed depending on the type of interview you lead with. This is why interviews should always be a mix of interpersonal to technical questions.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Planning &amp;amp; Analytical Skills 💡
&lt;/h3&gt;

&lt;p&gt;The ability to plan and contribute analytical skills is of utmost importance to most positions, especially software engineering. Below are a couple of techniques for determining such skills:&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Planning Questions&lt;/b&gt;: Ask the candidate to go through a planning stage of a project, how they stuck to it and pick questions from this journey.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How did they prepare themselves beforehand?&lt;/li&gt;
&lt;li&gt;Did they foresee any problems for themselves?&lt;/li&gt;
&lt;li&gt;How did they overcome the shortage of a resource?&lt;/li&gt;
&lt;li&gt;What contingencies did they consider in the event of blockers?&lt;/li&gt;
&lt;li&gt;How do they communicate their plan to others?&lt;/li&gt;
&lt;li&gt;Did they ever miss a deadline or fail to deliver work?&lt;/li&gt;
&lt;li&gt;How do they plan for pressure?&lt;/li&gt;
&lt;li&gt;What did they learn from any of the above?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a good category of questions for a number of reasons. Firstly you can judge what the candidate learned by the detail of their initial answer and what they took from the experience. It's of critical importance that the candidate demonstrates an ability to enrich themselves. This is true for all areas of interest and can't be emphasised enough.&lt;/p&gt;

&lt;p&gt;By also asking questions around failures you may detect an undesirable level of ego or pride. Similarly, by asking questions around pressure or burnout you can determine some emotional intelligence.  &lt;/p&gt;

&lt;p&gt;&lt;b&gt;Analytical Questions&lt;/b&gt;: Aside from general code related questions feel free to ask the candidate to step through a technical hurdle they faced. Equally, you can share with the candidate a problem you as the interviewer are currently having. This will test both their analytical skills, as well as their interpersonal skills in communicating their thoughts to you.&lt;/p&gt;

&lt;p&gt;With regards to asking a candidate to discuss an example of any kind, it is very common that they will have a well versed and planned example to give you. However, if you want a less rehearsed answer or want to examine the topic further, simply ask for another example to your question.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interpersonal &amp;amp; Team Skills 🤜🏼🤛🏼
&lt;/h3&gt;

&lt;p&gt;The strongest technically minded engineer can still have the power to derail a project due to terrible communication skills, arrogance, stubbornness, poor leadership or team skills. It is essential that the candidate you bring into your team can work and play well with others, and you must find this out. From the experience of the author, it is the most expensive thing to get wrong. &lt;/p&gt;

&lt;p&gt;&lt;b&gt;Team Experience &amp;amp; Leadership&lt;/b&gt;: To break the ice on this topic you can simply ask the candidate what kind of professional teamwork they have done in the past and then base your questions around the response. Remember, if you're not happy with an example, ask for another. You're looking for some of the following indicators:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can they articulate the value they contributed to the team as whole beyond the software?&lt;/li&gt;
&lt;li&gt;Can the candidate express their weaknesses relative to the team and how did they mitigate them?&lt;/li&gt;
&lt;li&gt;How did they resolve either a creative or personal conflict with another team member&lt;/li&gt;
&lt;li&gt;What has working with others taught the candidate about themselves?&lt;/li&gt;
&lt;li&gt;Did the candidate assume a leadership role and how was it applied?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Regarding leadership, you may want to drill into the topic of mentorship. It is common in software engineering that teams are made up of engineers with very different experience. It is expected that senior engineers guide junior engineers along and improve them. You will want to know how the candidate achieves this and how they resolve any issues before needing to bring the problem to a team lead or manager.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Interests&lt;/b&gt;: Asking questions about outside interests and hobbies is often seen as a bit antiquated, but it is still a valuable tool in determining the interpersonal skills of a candidate. For example, do they engage in any group or community activities? this could be anything from football to board gaming.&lt;/p&gt;

&lt;h3&gt;
  
  
  Organisations Values &amp;amp; Commitment 🦸‍♂️
&lt;/h3&gt;

&lt;p&gt;It is important to work into the interview questions which reflect your organisations values and work ethic. If you as an interviewer are having trouble articulating or evaluating such questions, use your own personal values. After all, the organisation hired you, and trusted you with this task based on those same values. &lt;/p&gt;

&lt;p&gt;Feel free to ask questions regarding the candidate's commitment either to the profession or the project they worked on. You don't want to glorify working ridiculous hours, which is something you hear quite a lot. Instead, you should be looking for personal projects, interest in a particular tech, involvement in the tech community or a demonstration of continuous learning.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>tutorial</category>
      <category>career</category>
      <category>programming</category>
    </item>
    <item>
      <title>Creating Different Default Value Sets for an F# Record Type</title>
      <dc:creator>Rob</dc:creator>
      <pubDate>Sun, 27 Feb 2022 10:23:26 +0000</pubDate>
      <link>https://dev.to/robgeorgemm/creating-different-default-value-sets-for-an-f-record-type-525c</link>
      <guid>https://dev.to/robgeorgemm/creating-different-default-value-sets-for-an-f-record-type-525c</guid>
      <description>&lt;p&gt;The purpose of this post is to provide you with a simple working example of creating different default value sets assigned to a particular &lt;code&gt;record type&lt;/code&gt; in &lt;code&gt;F#&lt;/code&gt;. It then demonstrates how to update selected fields when binding that default to a new variable using the &lt;code&gt;with&lt;/code&gt; &lt;a href="https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/copy-and-update-record-expressions" rel="noopener noreferrer"&gt;keyword&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The benefit of this approach is that the &lt;code&gt;record type&lt;/code&gt; remains &lt;code&gt;immutable&lt;/code&gt;. Record types do not support the &lt;code&gt;DefaultValueAttribute&lt;/code&gt; so it would mean not needing to go out of your way to create a &lt;code&gt;class&lt;/code&gt; with &lt;code&gt;mutable&lt;/code&gt; &lt;a href="https://docs.microsoft.com/en-gb/dotnet/fsharp/language-reference/members/explicit-fields-the-val-keyword" rel="noopener noreferrer"&gt;explicit fields&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Below is an example of a Meal &lt;code&gt;record type&lt;/code&gt; with two different value bindings, one named &lt;code&gt;defaultBreakfastMeal&lt;/code&gt; and the other &lt;code&gt;defaultDinnerMeal&lt;/code&gt;. There is nothing syntactically different between a regular binding of a &lt;code&gt;record type&lt;/code&gt; and one we choose to use as a default.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Record Type &amp;amp; Default Sets&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Meal&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
      &lt;span class="n"&gt;Food&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
      &lt;span class="n"&gt;Drink&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;defaultBreakfastMeal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Meal&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;Food&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Pastry"&lt;/span&gt;
      &lt;span class="n"&gt;Drink&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Coffee"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;defaultDinnerMeal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Meal&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;Food&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Shepherd's Pie"&lt;/span&gt;
      &lt;span class="n"&gt;Drink&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Water"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can later set a new binding but update the returning default values with selected overrides. In this case, the &lt;code&gt;Food&lt;/code&gt; value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;HangoverMeal&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;defaultBreakfastMeal&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt;
        &lt;span class="n"&gt;Food&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Irish Breakfast"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;HangoverMeal.Food = "Irish Breakfast"
HangoverMeal.Drink = "Coffee"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>beginners</category>
      <category>fsharp</category>
      <category>dotnet</category>
      <category>programming</category>
    </item>
    <item>
      <title>Creating a TRX File from an API for Azure DevOps CI/CD Pipeline Integration</title>
      <dc:creator>Rob</dc:creator>
      <pubDate>Thu, 24 Feb 2022 16:11:04 +0000</pubDate>
      <link>https://dev.to/robgeorgemm/creating-a-trx-file-from-an-api-for-azure-devops-pipeline-integration-2io5</link>
      <guid>https://dev.to/robgeorgemm/creating-a-trx-file-from-an-api-for-azure-devops-pipeline-integration-2io5</guid>
      <description>&lt;p&gt;The purpose of this article is to provide you with an example of a TRX file structure and how our team took a TRX formatted string response from a web service and injected it into our CI/CD pipeline on Azure DevOps. &lt;/p&gt;

&lt;p&gt;This web service is called &lt;a href="https://github.com/PiotrJustyna/Palladium" rel="noopener noreferrer"&gt;Palladium&lt;/a&gt; and is an open source solution for executing asynchronous, long-running tests in Orleans and produces TRX results via a HTTP web API endpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  A TRX File, Rawr! 🦖
&lt;/h2&gt;

&lt;p&gt;A TRX file (or T-REX file as I like to pronounce it) is a test result file created typically by Visual Studio when outputting the results of unit tests. It has a &lt;code&gt;.trx&lt;/code&gt; file extension and is formatted the same as &lt;code&gt;xml&lt;/code&gt;. It can be viewed and edited in most text editors or IDE's such &lt;code&gt;Visual Studio&lt;/code&gt; or &lt;code&gt;Jetbrains Rider&lt;/code&gt;.  &lt;/p&gt;

&lt;h2&gt;
  
  
  The Belly of the Beast 😱
&lt;/h2&gt;

&lt;p&gt;Below is an example of the TRX output from &lt;a href="https://github.com/PiotrJustyna/Palladium" rel="noopener noreferrer"&gt;Palladium&lt;/a&gt; /AsynchronousTests. We made some slight alterations from the default file structure to better serve our needs. For example we removed the &lt;code&gt;deployment&lt;/code&gt; node from &lt;code&gt;TestSettings&lt;/code&gt; and made it self closing. We also did away with the contents of the &lt;code&gt;Output&lt;/code&gt; node.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;TestRun&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://microsoft.com/schemas/VisualStudio/TeamTest/2010"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"a5e9e312-66fe-4f2d-b0c9-ce0fbc57cd9b"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"10ed7f37-b86d-4b36-a378-3c3fa724757e"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;Times&lt;/span&gt; &lt;span class="na"&gt;creation=&lt;/span&gt;&lt;span class="s"&gt;"2022-02-24T15:14:59.6966860Z"&lt;/span&gt; &lt;span class="na"&gt;queueing=&lt;/span&gt;&lt;span class="s"&gt;"2022-02-24T15:14:59.6981900Z"&lt;/span&gt; &lt;span class="na"&gt;start=&lt;/span&gt;&lt;span class="s"&gt;"2022-02-24T15:14:59.6981900Z"&lt;/span&gt; &lt;span class="na"&gt;finish=&lt;/span&gt;&lt;span class="s"&gt;"2022-02-24T15:15:00.0311280Z"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;TestSettings&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"fe569017-6430-466c-b8b8-2360549b5576"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"39bc153c-86b0-404a-b93f-67113b5cca75"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;Results&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;UnitTestResult&lt;/span&gt; &lt;span class="na"&gt;executionId=&lt;/span&gt;&lt;span class="s"&gt;"09b849b9-2e9d-42ec-808e-a530ac272082"&lt;/span&gt; &lt;span class="na"&gt;testId=&lt;/span&gt;&lt;span class="s"&gt;"2a3b891d-a24b-4e16-b730-a73607835817"&lt;/span&gt; &lt;span class="na"&gt;testName=&lt;/span&gt;&lt;span class="s"&gt;"Test1"&lt;/span&gt; &lt;span class="na"&gt;computerName=&lt;/span&gt;&lt;span class="s"&gt;"352509f7-e206-465e-966c-b7574939feb5"&lt;/span&gt; &lt;span class="na"&gt;duration=&lt;/span&gt;&lt;span class="s"&gt;"0:00:00.129834"&lt;/span&gt; &lt;span class="na"&gt;startTime=&lt;/span&gt;&lt;span class="s"&gt;"2022-02-24T15:14:59.7007960Z"&lt;/span&gt; &lt;span class="na"&gt;endTime=&lt;/span&gt;&lt;span class="s"&gt;"2022-02-24T15:14:59.8306300Z"&lt;/span&gt; &lt;span class="na"&gt;testType=&lt;/span&gt;&lt;span class="s"&gt;"13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b"&lt;/span&gt; &lt;span class="na"&gt;outcome=&lt;/span&gt;&lt;span class="s"&gt;"Passed"&lt;/span&gt; &lt;span class="na"&gt;testListId=&lt;/span&gt;&lt;span class="s"&gt;"2c0cd20b-ad9a-4ade-b491-479e8d9d4a0d"&lt;/span&gt; &lt;span class="na"&gt;relativeResultsDirectory=&lt;/span&gt;&lt;span class="s"&gt;"09b849b9-2e9d-42ec-808e-a530ac272082"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;UnitTestResult&lt;/span&gt; &lt;span class="na"&gt;executionId=&lt;/span&gt;&lt;span class="s"&gt;"a27998f9-7b79-4b6f-86f9-6b569f46685b"&lt;/span&gt; &lt;span class="na"&gt;testId=&lt;/span&gt;&lt;span class="s"&gt;"1ece5274-6d1e-4dff-b314-dcee7b751358"&lt;/span&gt; &lt;span class="na"&gt;testName=&lt;/span&gt;&lt;span class="s"&gt;"Test2"&lt;/span&gt; &lt;span class="na"&gt;computerName=&lt;/span&gt;&lt;span class="s"&gt;"352509f7-e206-465e-966c-b7574939feb5"&lt;/span&gt; &lt;span class="na"&gt;duration=&lt;/span&gt;&lt;span class="s"&gt;"0:00:00.227086"&lt;/span&gt; &lt;span class="na"&gt;startTime=&lt;/span&gt;&lt;span class="s"&gt;"2022-02-24T15:14:59.7030020Z"&lt;/span&gt; &lt;span class="na"&gt;endTime=&lt;/span&gt;&lt;span class="s"&gt;"2022-02-24T15:14:59.9300880Z"&lt;/span&gt; &lt;span class="na"&gt;testType=&lt;/span&gt;&lt;span class="s"&gt;"13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b"&lt;/span&gt; &lt;span class="na"&gt;outcome=&lt;/span&gt;&lt;span class="s"&gt;"Passed"&lt;/span&gt; &lt;span class="na"&gt;testListId=&lt;/span&gt;&lt;span class="s"&gt;"2c0cd20b-ad9a-4ade-b491-479e8d9d4a0d"&lt;/span&gt; &lt;span class="na"&gt;relativeResultsDirectory=&lt;/span&gt;&lt;span class="s"&gt;"a27998f9-7b79-4b6f-86f9-6b569f46685b"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;UnitTestResult&lt;/span&gt; &lt;span class="na"&gt;executionId=&lt;/span&gt;&lt;span class="s"&gt;"99fb1cb4-8ad8-48d8-97f2-97805f3d0746"&lt;/span&gt; &lt;span class="na"&gt;testId=&lt;/span&gt;&lt;span class="s"&gt;"546e9edb-7b96-4ada-9f45-9f947860839e"&lt;/span&gt; &lt;span class="na"&gt;testName=&lt;/span&gt;&lt;span class="s"&gt;"Test3"&lt;/span&gt; &lt;span class="na"&gt;computerName=&lt;/span&gt;&lt;span class="s"&gt;"352509f7-e206-465e-966c-b7574939feb5"&lt;/span&gt; &lt;span class="na"&gt;duration=&lt;/span&gt;&lt;span class="s"&gt;"0:00:00.327032"&lt;/span&gt; &lt;span class="na"&gt;startTime=&lt;/span&gt;&lt;span class="s"&gt;"2022-02-24T15:14:59.7032380Z"&lt;/span&gt; &lt;span class="na"&gt;endTime=&lt;/span&gt;&lt;span class="s"&gt;"2022-02-24T15:15:00.0302700Z"&lt;/span&gt; &lt;span class="na"&gt;testType=&lt;/span&gt;&lt;span class="s"&gt;"13cdc9d9-ddb5-4fa4-a97d-d965ccfc6d4b"&lt;/span&gt; &lt;span class="na"&gt;outcome=&lt;/span&gt;&lt;span class="s"&gt;"Passed"&lt;/span&gt; &lt;span class="na"&gt;testListId=&lt;/span&gt;&lt;span class="s"&gt;"2c0cd20b-ad9a-4ade-b491-479e8d9d4a0d"&lt;/span&gt; &lt;span class="na"&gt;relativeResultsDirectory=&lt;/span&gt;&lt;span class="s"&gt;"99fb1cb4-8ad8-48d8-97f2-97805f3d0746"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/Results&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;TestDefinitions&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;UnitTest&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"2a3b891d-a24b-4e16-b730-a73607835817"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Test1"&lt;/span&gt; &lt;span class="na"&gt;storage=&lt;/span&gt;&lt;span class="s"&gt;"AsynchronousTests.dll"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;Execution&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"09b849b9-2e9d-42ec-808e-a530ac272082"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;TestMethod&lt;/span&gt; &lt;span class="na"&gt;codeBase=&lt;/span&gt;&lt;span class="s"&gt;"AsynchronousTests.dll"&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"Grains.AsynchronousTests"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Test1"&lt;/span&gt; &lt;span class="na"&gt;adapterTypeName=&lt;/span&gt;&lt;span class="s"&gt;"orleans"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/UnitTest&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;UnitTest&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"1ece5274-6d1e-4dff-b314-dcee7b751358"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Test2"&lt;/span&gt; &lt;span class="na"&gt;storage=&lt;/span&gt;&lt;span class="s"&gt;"AsynchronousTests.dll"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;Execution&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"a27998f9-7b79-4b6f-86f9-6b569f46685b"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;TestMethod&lt;/span&gt; &lt;span class="na"&gt;codeBase=&lt;/span&gt;&lt;span class="s"&gt;"AsynchronousTests.dll"&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"Grains.AsynchronousTests"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Test2"&lt;/span&gt; &lt;span class="na"&gt;adapterTypeName=&lt;/span&gt;&lt;span class="s"&gt;"orleans"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/UnitTest&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;UnitTest&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"546e9edb-7b96-4ada-9f45-9f947860839e"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Test3"&lt;/span&gt; &lt;span class="na"&gt;storage=&lt;/span&gt;&lt;span class="s"&gt;"AsynchronousTests.dll"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;Execution&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"99fb1cb4-8ad8-48d8-97f2-97805f3d0746"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;TestMethod&lt;/span&gt; &lt;span class="na"&gt;codeBase=&lt;/span&gt;&lt;span class="s"&gt;"AsynchronousTests.dll"&lt;/span&gt; &lt;span class="na"&gt;className=&lt;/span&gt;&lt;span class="s"&gt;"Grains.AsynchronousTests"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"Test3"&lt;/span&gt; &lt;span class="na"&gt;adapterTypeName=&lt;/span&gt;&lt;span class="s"&gt;"orleans"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/UnitTest&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/TestDefinitions&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;TestEntries&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;TestEntry&lt;/span&gt; &lt;span class="na"&gt;testId=&lt;/span&gt;&lt;span class="s"&gt;"2a3b891d-a24b-4e16-b730-a73607835817"&lt;/span&gt; &lt;span class="na"&gt;executionId=&lt;/span&gt;&lt;span class="s"&gt;"09b849b9-2e9d-42ec-808e-a530ac272082"&lt;/span&gt; &lt;span class="na"&gt;testListId=&lt;/span&gt;&lt;span class="s"&gt;"2c0cd20b-ad9a-4ade-b491-479e8d9d4a0d"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;TestEntry&lt;/span&gt; &lt;span class="na"&gt;testId=&lt;/span&gt;&lt;span class="s"&gt;"1ece5274-6d1e-4dff-b314-dcee7b751358"&lt;/span&gt; &lt;span class="na"&gt;executionId=&lt;/span&gt;&lt;span class="s"&gt;"a27998f9-7b79-4b6f-86f9-6b569f46685b"&lt;/span&gt; &lt;span class="na"&gt;testListId=&lt;/span&gt;&lt;span class="s"&gt;"2c0cd20b-ad9a-4ade-b491-479e8d9d4a0d"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;TestEntry&lt;/span&gt; &lt;span class="na"&gt;testId=&lt;/span&gt;&lt;span class="s"&gt;"546e9edb-7b96-4ada-9f45-9f947860839e"&lt;/span&gt; &lt;span class="na"&gt;executionId=&lt;/span&gt;&lt;span class="s"&gt;"99fb1cb4-8ad8-48d8-97f2-97805f3d0746"&lt;/span&gt; &lt;span class="na"&gt;testListId=&lt;/span&gt;&lt;span class="s"&gt;"2c0cd20b-ad9a-4ade-b491-479e8d9d4a0d"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/TestEntries&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;TestLists&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;TestList&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"2c0cd20b-ad9a-4ade-b491-479e8d9d4a0d"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"All Loaded Results"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/TestLists&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;ResultSummary&lt;/span&gt; &lt;span class="na"&gt;outcome=&lt;/span&gt;&lt;span class="s"&gt;"Complete"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Counters&lt;/span&gt; &lt;span class="na"&gt;total=&lt;/span&gt;&lt;span class="s"&gt;"3"&lt;/span&gt; &lt;span class="na"&gt;executed=&lt;/span&gt;&lt;span class="s"&gt;"3"&lt;/span&gt; &lt;span class="na"&gt;passed=&lt;/span&gt;&lt;span class="s"&gt;"3"&lt;/span&gt; &lt;span class="na"&gt;failed=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;error=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;timeout=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;aborted=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;inconclusive=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;passedButRunAborted=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;notRunnable=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;notExecuted=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;disconnected=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;warning=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;completed=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;inProgress=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="na"&gt;pending=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Output&lt;/span&gt; &lt;span class="na"&gt;StdOut=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;/ResultSummary&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/TestRun&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  VSTS Integration 🤜🤛
&lt;/h2&gt;

&lt;p&gt;Below is an extract of two steps from our CI/CD pipeline which occur after we deploy our application to our test environment. We configured our Palladium unit tests to run on that same environment.&lt;/p&gt;

&lt;p&gt;We first used the &lt;code&gt;Bash@3&lt;/code&gt; &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/utility/bash?view=azure-devops" rel="noopener noreferrer"&gt;task&lt;/a&gt; to call the internally hosted instance of the &lt;a href="https://github.com/PiotrJustyna/Palladium" rel="noopener noreferrer"&gt;Palladium&lt;/a&gt; solution and save the resulting string as a &lt;code&gt;.trx&lt;/code&gt; file in the &lt;code&gt;DefaultWorkingDirectory&lt;/code&gt; of the VSTS server.&lt;/p&gt;

&lt;p&gt;We then configured a &lt;code&gt;PublishTestResult@2&lt;/code&gt; &lt;a href="https://docs.microsoft.com/en-gb/azure/devops/pipelines/tasks/test/publish-test-results?view=azure-devops&amp;amp;tabs=trx%2Cyaml" rel="noopener noreferrer"&gt;task&lt;/a&gt; to &lt;code&gt;VSTest&lt;/code&gt; and searched explicitly for the &lt;code&gt;palladium-output.trx&lt;/code&gt; file in the working directory. This step publishes the contents of the TRX file to the UI on the Azure pipeline build.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Bash@3&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Calling Palladium API Tests&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;targetType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;inline'&lt;/span&gt;
    &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;curl -s -m 5 $(PALLADIUM_API) -o palladium-output.trx&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PublishTestResults@2&lt;/span&gt;
  &lt;span class="na"&gt;displayName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Printing Test Result File&lt;/span&gt;
  &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;testResultsFormat&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;VSTest'&lt;/span&gt;
    &lt;span class="na"&gt;testResultsFiles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;palladium-output.trx'&lt;/span&gt;
    &lt;span class="na"&gt;searchFolder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;$(System.DefaultWorkingDirectory)'&lt;/span&gt;
    &lt;span class="na"&gt;testRunTitle&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Test&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Palladium&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;TRX'&lt;/span&gt;
    &lt;span class="na"&gt;publishRunAttachments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;failTaskOnFailedTests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;$(PALLADIUM_API)&lt;/code&gt; environment variable holds our URL to the test result endpoint of our Palladium instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The reason for the above implementation is because we as a team wanted to abstract out our unit tests into an independent API solution to call our various environments. If you decide to implement a similar design you can integrate it into your CI/CD with the above solution.&lt;/p&gt;

&lt;p&gt;Co-Author: &lt;a href="https://github.com/PiotrJustyna" rel="noopener noreferrer"&gt;Piotr Justyna&lt;/a&gt;&lt;/p&gt;

</description>
      <category>azure</category>
      <category>devops</category>
      <category>testing</category>
      <category>programming</category>
    </item>
    <item>
      <title>XmL Serialization for F# Record Types</title>
      <dc:creator>Rob</dc:creator>
      <pubDate>Tue, 22 Feb 2022 18:46:56 +0000</pubDate>
      <link>https://dev.to/robgeorgemm/xml-serialization-for-f-record-types-2p9l</link>
      <guid>https://dev.to/robgeorgemm/xml-serialization-for-f-record-types-2p9l</guid>
      <description>&lt;p&gt;While Microsoft do provide &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlserializer?view=net-6.0" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; for &lt;code&gt;XmlSerializer&lt;/code&gt; the examples are currently in &lt;code&gt;C#&lt;/code&gt; only. Equally, many long-standing and valid community solutions can only be found when using &lt;code&gt;keywords&lt;/code&gt; which indicate you already know the answer! Quite annoying.&lt;/p&gt;

&lt;p&gt;The purpose of this article is to provide you with a clear working example of serializing an F# record &lt;code&gt;type&lt;/code&gt; using the &lt;code&gt;XmlSerializer&lt;/code&gt; class and &lt;code&gt;CLIMutable&lt;/code&gt; attribute.&lt;/p&gt;

&lt;h2&gt;
  
  
  XmlSerializer 🥣
&lt;/h2&gt;

&lt;p&gt;The caveat of using the &lt;code&gt;XmlSerializer&lt;/code&gt; with &lt;code&gt;F#&lt;/code&gt; is that the class requires the referenced type to have a &lt;code&gt;parameterless constructor&lt;/code&gt; in order to work. Such constructors are implicitly created in the background for &lt;code&gt;C#&lt;/code&gt; classes without any explicit constructors defined. This is not the case for an &lt;code&gt;F#&lt;/code&gt; record type.&lt;/p&gt;

&lt;p&gt;The below example implements a simple &lt;code&gt;type&lt;/code&gt; with some elements, attributes and an array of sub-types.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Record Type&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CLIMutable&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nf"&gt;XmlRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Student"&lt;/span&gt;&lt;span class="p"&gt;)&amp;gt;]&lt;/span&gt; 
&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Student&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nf"&gt;XmlAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;)&amp;gt;]&lt;/span&gt;
    &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nf"&gt;XmlElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;)&amp;gt;]&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CLIMutable&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nf"&gt;XmlRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Master"&lt;/span&gt;&lt;span class="p"&gt;)&amp;gt;]&lt;/span&gt; 
&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Master&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; 
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nf"&gt;XmlAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;)&amp;gt;]&lt;/span&gt;
    &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="p"&gt;[&amp;lt;&lt;/span&gt;&lt;span class="nf"&gt;XmlElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Name"&lt;/span&gt;&lt;span class="p"&gt;)&amp;gt;]&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Students&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Student&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The below implementation of the serialization logic is standard, with a new &lt;code&gt;StringWriter&lt;/code&gt;, the &lt;code&gt;payload&lt;/code&gt; and some namespace configuration being passed to the &lt;code&gt;Serialize&lt;/code&gt; function of &lt;code&gt;XmlSerilizer&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Serializer&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Master&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1984&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Johnny Lawrence"&lt;/span&gt;
        &lt;span class="n"&gt;Students&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[|&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Miguel Diaz"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hawk"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;|]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;            

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;serializerNamespaces&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;XmlSerializerNamespaces&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;serializerNamespaces&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StringWriter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;serializer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;XmlSerializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Master&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt;
&lt;span class="n"&gt;serializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serializerNamespaces&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;printf&lt;/span&gt; &lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-16"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;Master&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"1984"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Name&amp;gt;&lt;/span&gt;Johnny Lawrence&lt;span class="nt"&gt;&amp;lt;/Name&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;Students&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Student&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Name&amp;gt;&lt;/span&gt;Miguel Diaz&lt;span class="nt"&gt;&amp;lt;/Name&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Student&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Student&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;Name&amp;gt;&lt;/span&gt;Hawk&lt;span class="nt"&gt;&amp;lt;/Name&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Student&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/Students&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Master&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Mutable 🧟‍
&lt;/h2&gt;

&lt;p&gt;The reason the above serialization works is because we added the &lt;code&gt;[&amp;lt;CLIMutable&amp;gt;]&lt;/code&gt; attribute to each of the &lt;code&gt;types&lt;/code&gt; to be serialized. The attribute instructs the compiler to add internal auto-generated &lt;strong&gt;mutable&lt;/strong&gt; fields. From a programming perspective, the &lt;code&gt;type&lt;/code&gt; is still immutable as these internal fields can only be accessed by automated processes or if you decided to expose the &lt;code&gt;type&lt;/code&gt; to &lt;code&gt;C#&lt;/code&gt; code.&lt;/p&gt;

&lt;p&gt;By using this attribute we can make use of normal &lt;code&gt;.NET&lt;/code&gt; serializers and avoid harder to work with solutions like the &lt;code&gt;DataContractSerializer&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Working Example 🧪
&lt;/h2&gt;

&lt;p&gt;The following &lt;a href="https://github.com/PiotrJustyna/Palladium/blob/main/SiloHost/src/Controllers/AsynchronousTestsController.fs" rel="noopener noreferrer"&gt;solution&lt;/a&gt; provides an example of the &lt;code&gt;XmlSerializer&lt;/code&gt; turning a &lt;code&gt;record type&lt;/code&gt; into an &lt;code&gt;xml&lt;/code&gt; formatted string for an API response. This solution is an open-source implementation of asynchronous, long-running tests in Orleans which produce TRX results via a HTTP web API endpoint.&lt;/p&gt;

&lt;p&gt;Co-Author: &lt;a href="https://github.com/PiotrJustyna" rel="noopener noreferrer"&gt;Piotr Justyna&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>fsharp</category>
      <category>programming</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Getting Started with Github Action Workflows</title>
      <dc:creator>Rob</dc:creator>
      <pubDate>Thu, 17 Feb 2022 20:39:39 +0000</pubDate>
      <link>https://dev.to/robgeorgemm/getting-started-with-github-action-workflows-3ehn</link>
      <guid>https://dev.to/robgeorgemm/getting-started-with-github-action-workflows-3ehn</guid>
      <description>&lt;p&gt;This article gives a brief introduction to the concepts and syntax of github actions. While the &lt;a href="https://docs.github.com/en/actions" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt; of github actions is comprehensive, the aim of this article is to help avoid those early learning mistakes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman" rel="noopener noreferrer"&gt;link to original article&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Context 👨🏼‍🏫
&lt;/h2&gt;

&lt;p&gt;Github actions is a platform to automate developer workflows. It was built to reduce the organisational burden attached to large open-source community driven repositories. This burden would manifest in the form of hundreds, if not thousands, of contributors, branches, pull requests, merges as well as testing, labelling, creating release documentation and many other tasks or events.&lt;/p&gt;

&lt;p&gt;The purpose of an action is to listen to these events and trigger a workflow in response. For example, if a contributor raises an issue, you may want to sort it, label it, and assign it automatically. A workflow is a &lt;code&gt;.yml&lt;/code&gt; or &lt;code&gt;.yaml&lt;/code&gt; file with a set of instructions you define.&lt;/p&gt;

&lt;p&gt;While CI/CD is often used to convey its utility, it is just one of many possible workflows you can create to serve your needs. The examples in this article are simple workflows created merely to introduce some of the basic concepts.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Executing Shell Commands&lt;/li&gt;
&lt;li&gt;Accessing Environment Variables&lt;/li&gt;
&lt;li&gt;Calling Composite Actions&lt;/li&gt;
&lt;li&gt;Setting &amp;amp; Passing Variables&lt;/li&gt;
&lt;li&gt;Making Web Service Calls&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  1. &lt;a id="example-1"&gt;&lt;/a&gt;Executing Shell Commands 🐚
&lt;/h2&gt;

&lt;p&gt;The first example below is a very basic workflow executing different commands in their native shells. The point of this example is to illustrate the role of the &lt;code&gt;run-on&lt;/code&gt; and &lt;code&gt;shell&lt;/code&gt; instructions. A workflow refers to all the instructions within the file, which is comprised of one or more &lt;code&gt;jobs&lt;/code&gt;, which in turn is comprised of one or more &lt;code&gt;steps&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Each &lt;code&gt;job&lt;/code&gt; listed within a workflow is executed concurrently on a different github server, but you can choose to host them yourself. The significance of this means you need to specify which operating system you want your &lt;code&gt;job&lt;/code&gt; to run on by using the &lt;code&gt;run-on&lt;/code&gt; keyword. This can include various versions of windows, macOS, ubuntu or even being self-hosted.&lt;/p&gt;

&lt;p&gt;If for example all your steps within a job run powershell commands or scripts, you could specify &lt;code&gt;run-on: windows-latest&lt;/code&gt; and call it job done as powershell would be understood by the runners of that operating system. But let's say you needed to run a one off Zshell script in the same job, here the &lt;code&gt;shell&lt;/code&gt; keyword can allow you to override the shell of the specified OS by specifying the correct shell language.&lt;/p&gt;

&lt;p&gt;Below is an example of 'Hello World' being printed to the console in &lt;code&gt;powershell&lt;/code&gt;, &lt;code&gt;bash&lt;/code&gt;, &lt;code&gt;zshell&lt;/code&gt; and even &lt;code&gt;python&lt;/code&gt; , which are all being run on a &lt;code&gt;windows&lt;/code&gt; github server. Github also accepts &lt;code&gt;powershell&lt;/code&gt;, &lt;code&gt;pwsh&lt;/code&gt; (powershell core) and &lt;code&gt;cmd&lt;/code&gt; when overriding for Windows commands. See the code example for more useful information in the comments and follow all links to source file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/blob/main/.github/workflows/ex1-execute-scripts.yml" rel="noopener noreferrer"&gt;&lt;strong&gt;Workflow&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1 - Run Hello Worlds scripts&lt;/span&gt;              &lt;span class="c1"&gt;# &amp;lt;- Workflow name.&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;                                             &lt;span class="c1"&gt;# &amp;lt;- The trigger definition block.&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;                                         &lt;span class="c1"&gt;# &amp;lt;- An event to trigger the action, of type push.&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;                                 &lt;span class="c1"&gt;# &amp;lt;- Target Branches. Accepts an array.&lt;/span&gt;
      &lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
      &lt;span class="nv"&gt;another-branch&lt;/span&gt;
    &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;                                           &lt;span class="c1"&gt;# &amp;lt;- The execution of work block.&lt;/span&gt;
  &lt;span class="na"&gt;Job-Identifier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;                               &lt;span class="c1"&gt;# &amp;lt;- Job ID. Contains related action steps.&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Executing Hello World Script&lt;/span&gt;          &lt;span class="c1"&gt;# &amp;lt;- Job Name.&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;windows-latest&lt;/span&gt;                     &lt;span class="c1"&gt;# &amp;lt;- Tells the server which OS to run on. Can also be windows, macOS, or even self-hosted.      &lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;                                      &lt;span class="c1"&gt;# &amp;lt;- Step definitions.&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;               &lt;span class="c1"&gt;# &amp;lt;- Use keyword selects an action. Actions/ path in github is where common actions are predefined.&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Printing Powershell&lt;/span&gt;               &lt;span class="c1"&gt;# &amp;lt;- Optional step name, but advised.                       &lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./Powershell/HelloWorld.ps1&lt;/span&gt;        &lt;span class="c1"&gt;# &amp;lt;- Run keyword executes a command. In this case a powershell script.&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Printing Bash&lt;/span&gt;
        &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bash&lt;/span&gt;                             &lt;span class="c1"&gt;# &amp;lt;- Overrides the default shell language of your specified server. &lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./Bash/HelloWorld.sh&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Printing ZShell&lt;/span&gt;
        &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sh&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./Zshell/HelloWorld.zsh&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Printing Python&lt;/span&gt;
        &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;exec(open('./Python/HelloWorld.py').read())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/runs/5173467514?check_suite_focus=true" rel="noopener noreferrer"&gt;&lt;strong&gt;Console Output&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Run ./Powershell/HelloWorld.ps1
Hello World from Powershell!

Run ./Bash/HelloWorld.sh
Hello World from Bash!

Run ./Zshell/HelloWorld.zsh
hello world from Zshell!

Run &lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;open&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'./Python/HelloWorld.py'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;.read&lt;span class="o"&gt;())&lt;/span&gt;
Hello World from Python!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;h2&gt;
  
  
  2. &lt;a id="example-2"&gt;&lt;/a&gt;Accessing Environment Variables 🌱
&lt;/h2&gt;

&lt;p&gt;The following example illustrates how you can read &lt;code&gt;environment variables&lt;/code&gt;. There are two kinds of variables, those provided by github which use protected names and can be found in the &lt;a href="https://docs.github.com/en/actions/learn-github-actions/environment-variables" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;, and custom variables you can set yourself throughout your workflow.&lt;/p&gt;

&lt;p&gt;Another significant feature of the &lt;code&gt;workflow&lt;/code&gt;, &lt;code&gt;job&lt;/code&gt; and &lt;code&gt;step&lt;/code&gt; relationship is how custom variables are scoped. Declared variables within the workflow using the keyword &lt;code&gt;env&lt;/code&gt; follow an access hierarchy and can only be accessed within the element they were defined. Those variables declared at the highest &lt;code&gt;workflow&lt;/code&gt; level can be accessed by all &lt;code&gt;jobs&lt;/code&gt; and &lt;code&gt;steps&lt;/code&gt;. Variables declared within a &lt;code&gt;job&lt;/code&gt; can only be used by steps within that job and if declared inside a &lt;code&gt;step&lt;/code&gt; they can only be used by that step.&lt;/p&gt;
&lt;h3&gt;
  
  
  2.1 Custom &amp;amp; Protected Environment Variables
&lt;/h3&gt;

&lt;p&gt;In the below workflow example you can see that 3 custom variables are declared at different levels: &lt;code&gt;BEST_PINT&lt;/code&gt;, &lt;code&gt;BEST_WHISKEY&lt;/code&gt; and &lt;code&gt;BEST_COCKTAIL&lt;/code&gt;. In the &lt;code&gt;Print Variables to Script&lt;/code&gt; step a &lt;a href="https://github.com/Mulpeter91/Github-Actionman/blob/main/Powershell/GithubEnvVariables.ps1" rel="noopener noreferrer"&gt;script&lt;/a&gt; is executed to print these variables to the console along with a sample of various set github environment variables.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/blob/main/.github/workflows/ex2-access-variables.yml" rel="noopener noreferrer"&gt;&lt;strong&gt;Workflow&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2 - Access Github Environment Variables&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
        &lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;another-branch&lt;/span&gt;
    &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;                                   &lt;span class="c1"&gt;# &amp;lt;- Pull request trigger. Used in Example 2.2.&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
        &lt;span class="nv"&gt;main&lt;/span&gt;                                      &lt;span class="c1"&gt;# &amp;lt;- If any pull request is made to branch 'main'.      &lt;/span&gt;
    &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;BEST_PINT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Guinness&lt;/span&gt;                             &lt;span class="c1"&gt;# &amp;lt;- Custom environment variable declared at workflow level.&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;#Example 2.1&lt;/span&gt;
  &lt;span class="na"&gt;Access-Environment-Variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Print Github Environment Variables&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;windows-latest&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;BEST_WHISKEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Midleton&lt;/span&gt;                      &lt;span class="c1"&gt;# &amp;lt;- Scoped to this job and subsequent steps.         &lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Print Variables to Script&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./Powershell/GithubEnvVariables.ps1&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;BEST_COCKTAIL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Whiskey Sour&lt;/span&gt;              &lt;span class="c1"&gt;# &amp;lt;- Scoped to this step only.&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Inspect Environment Variables&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;env&lt;/span&gt;                                   &lt;span class="c1"&gt;# &amp;lt;- Prints to output the available variables to this step.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/runs/5173467512?check_suite_focus=true" rel="noopener noreferrer"&gt;&lt;strong&gt;Console Output&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;The owner and repository name.
GITHUB_REPOSITORY: &lt;span class="s1"&gt;'Mulpeter91/Github-Actionman'&lt;/span&gt;

The commit SHA that triggered the workflow.
GITHUB_SHA: &lt;span class="s1"&gt;'321d557ec2d724d2c6aaf056b14859ea8468051e'&lt;/span&gt;

The job &lt;span class="nb"&gt;id &lt;/span&gt;you assigned to the current job.
GITHUB_JOB: &lt;span class="s1"&gt;'Job-Identifier-Sample'&lt;/span&gt;

A unique number &lt;span class="k"&gt;for &lt;/span&gt;each workflow run within a repository. This number does not change &lt;span class="k"&gt;if &lt;/span&gt;you re-run the workflow run.
GITHUB_RUN_ID: &lt;span class="s1"&gt;'1836698654'&lt;/span&gt;

An unique number &lt;span class="k"&gt;for &lt;/span&gt;each &lt;span class="nb"&gt;time &lt;/span&gt;the same workflow is run again. Starts at 1 and increments by 1.
GITHUB_RUN_NUMBER: &lt;span class="s1"&gt;'18'&lt;/span&gt;

The name of the runner executing the job.
RUNNER_NAME: &lt;span class="s1"&gt;'GitHub Actions 4'&lt;/span&gt;

I love a pint of Guinness with a glass of Midleton and end the night on a Whiskey Sour.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A useful command to inspect available environment variables within a step is &lt;code&gt;run: env&lt;/code&gt;. Notice that the below output does not contain &lt;code&gt;BEST_COCKTAIL&lt;/code&gt; because it was defined and scoped to the previous step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;...

&lt;span class="nv"&gt;APPDATA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;C:&lt;span class="se"&gt;\U&lt;/span&gt;sers&lt;span class="se"&gt;\r&lt;/span&gt;unneradmin&lt;span class="se"&gt;\A&lt;/span&gt;ppData&lt;span class="se"&gt;\R&lt;/span&gt;oaming
&lt;span class="nv"&gt;AZURE_EXTENSION_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;C:&lt;span class="se"&gt;\P&lt;/span&gt;rogram Files&lt;span class="se"&gt;\C&lt;/span&gt;ommon Files&lt;span class="se"&gt;\A&lt;/span&gt;zureCliExtensionDirectory
&lt;span class="nv"&gt;BEST_PINT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Guinness
&lt;span class="nv"&gt;BEST_WHISKEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Midleton
&lt;span class="nv"&gt;CABAL_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;C:&lt;span class="se"&gt;\c&lt;/span&gt;abal
&lt;span class="nv"&gt;ChocolateyInstall&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;C:&lt;span class="se"&gt;\P&lt;/span&gt;rogramData&lt;span class="se"&gt;\c&lt;/span&gt;hocolatey

...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You must remember to use the correct syntax for referencing variables in your target shell. For example, Windows runners would required the format &lt;code&gt;$env:NAME&lt;/code&gt; while the Linux runners using bash shell would use &lt;code&gt;$NAME&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.2 Specific Event Variables
&lt;/h3&gt;

&lt;p&gt;Most github environment variables will always populate, such as &lt;code&gt;GITHUB_ACTOR&lt;/code&gt; but some will only be populated during a specific event trigger. In the above &lt;code&gt;workflow&lt;/code&gt; example you can see a trigger has been added for &lt;code&gt;pull_request&lt;/code&gt;. This has been added to show you some of the variables that will only populate during that event, such as &lt;code&gt;GITHUB_BASE_REF&lt;/code&gt; and &lt;code&gt;GITHUB_HEAD_REF&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/blob/main/.github/workflows/ex2-access-variables.yml" rel="noopener noreferrer"&gt;&lt;strong&gt;Workflow&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;#Example 2.2&lt;/span&gt;
&lt;span class="na"&gt;Pull-Request-Variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Obtain variables useful to a pull request&lt;/span&gt;
  &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;windows-latest&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;var&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nothing&lt;/span&gt;
  &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Print Variables for Pull Request&lt;/span&gt;     &lt;span class="c1"&gt;# &amp;lt;- Add a pipe key on the run command to make a multiple.&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;Write-Host "Actor: $Env:GITHUB_ACTOR"&lt;/span&gt;
        &lt;span class="s"&gt;Write-Host "Target Branch: $Env:GITHUB_BASE_REF"&lt;/span&gt;
        &lt;span class="s"&gt;Write-Host "Source Branch: $Env:GITHUB_HEAD_REF"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/runs/5198208204?check_suite_focus=true" rel="noopener noreferrer"&gt;&lt;strong&gt;Console Output&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Actor: Mulpeter91
Target Branch: main
Source Branch: pull-request-ex
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2.3 Accessing Event Metadata
&lt;/h3&gt;

&lt;p&gt;Another variable worth noting and is heavily effected by the action event type is &lt;code&gt;GITHUB_EVENT_PATH&lt;/code&gt;. This variable contains the directory within your runner to a temporarily stored &lt;code&gt;event.json&lt;/code&gt; file. This file contains substantial metadata regarding the specific event triggered within the workflow and can be fed into a json object for easy access to specific data nodes.&lt;/p&gt;

&lt;p&gt;Every event type has it's own structured version of the file. So what exists in a &lt;code&gt;pull_request&lt;/code&gt;:&lt;code&gt;event.json&lt;/code&gt; will not exactly match the nodes in a &lt;code&gt;push&lt;/code&gt;:&lt;code&gt;event.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/blob/main/.github/workflows/ex2-access-variables.yml" rel="noopener noreferrer"&gt;&lt;strong&gt;Workflow&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;#Example 2.3   &lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Print Json from Action Event File&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./PowershellEventFile.ps1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/blob/main/Powershell/GithubEventFile.ps1" rel="noopener noreferrer"&gt;&lt;strong&gt;File&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="s2"&gt;"Event metadata file path: &lt;/span&gt;&lt;span class="nv"&gt;$Env&lt;/span&gt;&lt;span class="s2"&gt;:GITHUB_EVENT_PATH&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;n&lt;span class="s2"&gt;"
"&lt;/span&gt;File Contents:&lt;span class="s2"&gt;"
&lt;/span&gt;&lt;span class="nv"&gt;$EVENT_FILE&lt;/span&gt;&lt;span class="s2"&gt; = Get-Content -Path &lt;/span&gt;&lt;span class="nv"&gt;$Env&lt;/span&gt;&lt;span class="s2"&gt;:GITHUB_EVENT_PATH
Write-Host &lt;/span&gt;&lt;span class="nv"&gt;$EVENT_FILE&lt;/span&gt;&lt;span class="s2"&gt;

&lt;/span&gt;&lt;span class="nv"&gt;$EVENT_JSON&lt;/span&gt;&lt;span class="s2"&gt; = &lt;/span&gt;&lt;span class="nv"&gt;$EVENT_FILE&lt;/span&gt;&lt;span class="s2"&gt; | ConvertFrom-Json
"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="s2"&gt;nSample selectors"&lt;/span&gt;
Write-Host &lt;span class="s2"&gt;"OBJECT.head_commit.author.username:"&lt;/span&gt; &lt;span class="nv"&gt;$EVENT_JSON&lt;/span&gt;.head_commit.author.username
Write-Host &lt;span class="s2"&gt;"OBJECT.head_commit.url:"&lt;/span&gt; &lt;span class="nv"&gt;$EVENT_JSON&lt;/span&gt;.head_commit.url
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/runs/5219495371?check_suite_focus=true" rel="noopener noreferrer"&gt;&lt;strong&gt;Console Output&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Event metadata file path: D:&lt;span class="se"&gt;\a\_&lt;/span&gt;temp&lt;span class="se"&gt;\_&lt;/span&gt;github_workflow&lt;span class="se"&gt;\e&lt;/span&gt;vent.json
File Contents: &lt;span class="o"&gt;(&lt;/span&gt;see above console &lt;span class="nb"&gt;link&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

Sample selectors
OBJECT.head_commit.author.username: Mulpeter91
OBJECT.head_commit.url: https://github.com/Mulpeter91/Github-Actionman/commit/443da01e18050bd8912d3fac24a86f0c340a2ea8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;h2&gt;
  
  
  3. &lt;a id="example-3"&gt;&lt;/a&gt;Calling Composite Actions ⚙️
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.github.com/en/actions/creating-actions/creating-a-composite-action" rel="noopener noreferrer"&gt;Composite actions&lt;/a&gt; are a specific type of workflow file which are designed to abstract out and reuse a set of instructions for one or more requesting workflows. They are typically stored in their own repositories, such as &lt;a href="https://github.com/actions" rel="noopener noreferrer"&gt;Github's own shared actions&lt;/a&gt; or &lt;a href="https://github.com/google-github-actions" rel="noopener noreferrer"&gt;Google's integration actions&lt;/a&gt;, but they can also be stored and executed in the same repository.&lt;/p&gt;

&lt;p&gt;A step utilises the &lt;code&gt;uses&lt;/code&gt; keyword when executing a &lt;code&gt;composite action&lt;/code&gt;. In the below example you will notice two steps each using a composite action. The first is using github's shared &lt;code&gt;actions/checkout@v2&lt;/code&gt; and the other is using our local &lt;code&gt;composite action&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Composite actions depend on targeted releases to know which version of the code to execute. In the case of &lt;code&gt;checkout@v2&lt;/code&gt; this is referencing release &lt;code&gt;v2&lt;/code&gt; in the &lt;code&gt;checkout&lt;/code&gt; repository. You need to checkout your code in order to build it, test it or in our case execute composite actions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/blob/main/.github/workflows/ex3-composite-action.yml" rel="noopener noreferrer"&gt;&lt;strong&gt;Workflow&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;3 - Running a local Composite Action&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
        &lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;another-branch&lt;/span&gt;
    &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Run-Composite-Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Print message from another action&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;windows-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;                 &lt;span class="c1"&gt;# &amp;lt;- Required to checkout your code in order to access composite actions from with the repo&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Use hello world composite action&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./.github/actions/hello-world&lt;/span&gt;       &lt;span class="c1"&gt;# &amp;lt;- Use keyword for calling other actions&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;composite action&lt;/code&gt; file requires a &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;description&lt;/code&gt; field with an optional &lt;code&gt;author&lt;/code&gt; field. The run also needs to add &lt;code&gt;using: 'composite'&lt;/code&gt; before executing its steps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/blob/main/.github/actions/hello-world/action.yml" rel="noopener noreferrer"&gt;&lt;strong&gt;Composite Action&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Print Hello World&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prints a Hello World message.&lt;/span&gt;
&lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Robert Mulpeter @Mulpeter91&lt;/span&gt;

&lt;span class="na"&gt;runs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;using&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;composite"&lt;/span&gt;                &lt;span class="c1"&gt;# &amp;lt;- Required declaration of a composite action.&lt;/span&gt;
  &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Write-Host "Hello World from Composite Action!"&lt;/span&gt;
      &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pwsh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/runs/5173467513?check_suite_focus=true" rel="noopener noreferrer"&gt;&lt;strong&gt;Console Output&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Run ./.github/actions/hello-world
Run Write-Host &lt;span class="s2"&gt;"Hello World from Composite Action!"&lt;/span&gt;
Hello World from Composite Action!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another important point regarding &lt;code&gt;composite actions&lt;/code&gt; is that they must be defined inside a file called either &lt;code&gt;action.yml&lt;/code&gt; or &lt;code&gt;action.yaml&lt;/code&gt;. It is recommended that if you have multiple composite actions in the same repo that you house them in their own directories within the &lt;code&gt;.github&lt;/code&gt; directory. While these directories can contain other files such as docker files, they must contain &lt;strong&gt;one&lt;/strong&gt; &lt;code&gt;action&lt;/code&gt; file. See working &lt;a href="https://github.com/Mulpeter91/Github-Actionman/tree/main/.github/actions" rel="noopener noreferrer"&gt;repo&lt;/a&gt; for an example.&lt;/p&gt;


&lt;h2&gt;
  
  
  4. &lt;a id="example-4"&gt;&lt;/a&gt;Setting and Passing Variables 🤾
&lt;/h2&gt;

&lt;p&gt;The below &lt;code&gt;step&lt;/code&gt; examples are all run on the same &lt;code&gt;workflow&lt;/code&gt; file and combine parts of the previous code with the added fun of setting variables from outside the &lt;code&gt;yml&lt;/code&gt; file and passing variables around the workflow.&lt;/p&gt;
&lt;h3&gt;
  
  
  4.1 Passing Parameters to Composite Action
&lt;/h3&gt;

&lt;p&gt;In the below example we are using a &lt;code&gt;composite action&lt;/code&gt; much like example 3 but with &lt;code&gt;input&lt;/code&gt; parameters. The &lt;code&gt;step&lt;/code&gt; passing these named parameters to the action with the &lt;code&gt;with&lt;/code&gt; keyword and &lt;code&gt;&amp;lt;variable&amp;gt;&lt;/code&gt; name, in this case 'message'.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/blob/main/.github/workflows/ex4-passing-variables.yml" rel="noopener noreferrer"&gt;&lt;strong&gt;Job 1 / Example 1&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Create-Variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Creating and passing variables&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;windows-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;#Example 4.1&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Use print message composite action&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./.github/actions/print-message&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;                                 &lt;span class="c1"&gt;# &amp;lt;- With keyword to signify parameters&lt;/span&gt;
          &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cobra&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Kai&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;never&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;dies"&lt;/span&gt;     &lt;span class="c1"&gt;# &amp;lt;- Named parameter in the called action.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The composite action lists its parameters with the &lt;code&gt;inputs&lt;/code&gt; keyword. Parameters can be &lt;code&gt;required: true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;, include a &lt;code&gt;description&lt;/code&gt; and a &lt;code&gt;default&lt;/code&gt; value if no value is passed. In our case, a &lt;code&gt;message&lt;/code&gt; value is sent but a &lt;code&gt;version&lt;/code&gt; value is not.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/blob/main/.github/actions/print-message/action.yml" rel="noopener noreferrer"&gt;&lt;strong&gt;Composite Action&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Print Parameters&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prints a message passed from the workflow.&lt;/span&gt;
&lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Robert Mulpeter @Mulpeter91&lt;/span&gt;

&lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;       &lt;span class="c1"&gt;# &amp;lt;- keyword for defining action parameters.     &lt;/span&gt;
  &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;be&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;printed"&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;version."&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;🤟🏻"&lt;/span&gt;

&lt;span class="na"&gt;runs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;using&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;composite"&lt;/span&gt;
  &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Write-Host ${{ inputs.message }} ${{ inputs.version }}&lt;/span&gt;
      &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pwsh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/runs/5173627256?check_suite_focus=true" rel="noopener noreferrer"&gt;&lt;strong&gt;Console Output&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Run ./.github/actions/print-message
Run Write-Host Cobra Kai never dies 🤟🏻
Cobra Kai never dies 🤟🏻
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.2 Set Variables from Environment File
&lt;/h3&gt;

&lt;p&gt;The following example combines a parameterised composite action with reading the contents of an &lt;code&gt;.env&lt;/code&gt; file into the environment variables for access by the workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/blob/main/.github/workflows/ex4-passing-variables.yml" rel="noopener noreferrer"&gt;&lt;strong&gt;Job 1 / Example 2&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;#Example 4.2&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set variables from environment file&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./.github/actions/read-env-file&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;filePath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./.github/variables/variables.env&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using &lt;code&gt;&amp;gt;&amp;gt; $Env:GITHUB_ENV&lt;/code&gt; instructs github to read the variable into the environment variable dictionary.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/blob/main/.github/actions/read-env-file/action.yml" rel="noopener noreferrer"&gt;&lt;strong&gt;Composite Action&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Read Env Variables from file&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Reads environment variables from a passed .env file.&lt;/span&gt;
&lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Robert Mulpeter @Mulpeter91&lt;/span&gt;

&lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;filePath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;File&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;path&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;variable&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;file."&lt;/span&gt;
    &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./.github/variables*&lt;/span&gt;

&lt;span class="na"&gt;runs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;using&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;composite"&lt;/span&gt;
  &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;Get-Content ${{ inputs.filePath }} &amp;gt;&amp;gt; $Env:GITHUB_ENV   # &amp;lt;- Adding directly $Env:GITHUB_ENV saves at the workflow level&lt;/span&gt;
      &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pwsh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is advised to keep all variable related files within the &lt;code&gt;.github&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/blob/main/.github/variables/variables.env" rel="noopener noreferrer"&gt;&lt;strong&gt;Input File&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;DOJO_1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Miyagi-Do Karate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/runs/5173627256?check_suite_focus=true" rel="noopener noreferrer"&gt;&lt;strong&gt;Console Output&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Run Get-Content ./Powershell/Variables.ps1 &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$Env&lt;/span&gt;:GITHUB_ENV
  Get-Content ./Powershell/Variables.ps1 &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$Env&lt;/span&gt;:GITHUB_ENV
  &lt;span class="nb"&gt;env&lt;/span&gt;:
    DOJO_1: Miyagi-Do Karate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.3 Set Variables from Powershell File
&lt;/h3&gt;

&lt;p&gt;The following example achieves the same outcome of example 4.2 but adds environment variables by executing a &lt;code&gt;powershell&lt;/code&gt; script directly in the workflow step.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/blob/main/.github/workflows/ex4-passing-variables.yml" rel="noopener noreferrer"&gt;&lt;strong&gt;Job 1 / Example 3&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;#Example 4.3&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set variables from powershell file&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Get-Content ./Powershell/Variables.ps1 &amp;gt;&amp;gt; $Env:GITHUB_ENV&lt;/span&gt;   
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/blob/main/Powershell/Variables.ps1" rel="noopener noreferrer"&gt;&lt;strong&gt;Input File&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;DOJO_2&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Eagle Fang Karate
&lt;span class="nv"&gt;DOJO_3&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Cobra-Kai Karate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/runs/5173627256?check_suite_focus=true" rel="noopener noreferrer"&gt;&lt;strong&gt;Console Output&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Run Get-Content ./Powershell/Variables.ps1 &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$Env&lt;/span&gt;:GITHUB_ENV
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.4 Set Variables from Local Step Variable
&lt;/h3&gt;

&lt;p&gt;The below example takes a local environment variable declared in the step and reads it directly into the github environment dictionary. Note from the below console output, that the variable &lt;code&gt;$LOCAL_VARIABLE&lt;/code&gt; has been read into the dictionary under variable &lt;code&gt;$WORKFLOW_VARIABLE&lt;/code&gt; which is accessible in the subsequent &lt;code&gt;Inspect Environment Variables&lt;/code&gt; step.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/blob/main/.github/workflows/ex4-passing-variables.yml" rel="noopener noreferrer"&gt;&lt;strong&gt;Job 1 / Example 4&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;#Example 4.4&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set local step variable to environment variable&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;echo "WORKFLOW_VARIABLE=$(echo ${Env:LOCAL_VARIABLE})" &amp;gt;&amp;gt; $Env:GITHUB_ENV&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;LOCAL_VARIABLE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Karate Kid&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Inspect Environment Variables&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;env&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/runs/5231803339?check_suite_focus=true" rel="noopener noreferrer"&gt;&lt;strong&gt;Console Output&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"WORKFLOW_VARIABLE=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;Env&lt;/span&gt;:LOCAL_VARIABLE&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$Env&lt;/span&gt;:GITHUB_ENV
&lt;span class="nb"&gt;env&lt;/span&gt;:
  DOJO_1: Miyagi-Do Karate
  DOJO_2: Eagle Fang Karate
  DOJO_3: Cobra-Kai Karate
  LOCAL_VARIABLE: Karate Kid

Run &lt;span class="nb"&gt;env
env&lt;/span&gt;:
  DOJO_1: Miyagi-Do Karate
  DOJO_2: Eagle Fang Karate
  DOJO_3: Cobra-Kai Karate
  WORKFLOW_VARIABLE: Karate Kid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.5 Pass Variable to Dependant Job
&lt;/h3&gt;

&lt;p&gt;We previously noted that &lt;code&gt;jobs&lt;/code&gt; are run concurrently by default and that variables are scoped to the element they are defined in. The following example illustrates how you can enforce a dependency between jobs to have them run consecutively to each other by using the &lt;code&gt;needs&lt;/code&gt; array and pass a variable from the initial job to the &lt;code&gt;dependent job&lt;/code&gt; using the &lt;code&gt;outputs&lt;/code&gt; keyword rather than sending everything to the high level environment dictionary.&lt;/p&gt;

&lt;p&gt;The below step is extracted from the first job &lt;code&gt;create-variables&lt;/code&gt; and uses the &lt;code&gt;outputs&lt;/code&gt; keyword with an object reference to step &lt;code&gt;step_output&lt;/code&gt;. This step in turn uses the &lt;code&gt;::set-ouput name=NAME::Value&lt;/code&gt; command to set the outputted variable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/blob/main/.github/workflows/ex4-passing-variables.yml" rel="noopener noreferrer"&gt;&lt;strong&gt;Job 1 / Example 5&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;create-variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Creating and passing variables&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;windows-latest&lt;/span&gt;
    &lt;span class="na"&gt;outputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;output1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ steps.step_output.outputs.TONIGHTS_DINNER }}&lt;/span&gt;

    &lt;span class="c1"&gt;#Example 4.5&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;step_output&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create variable output from step&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;echo "::set-output name=TONIGHTS_DINNER::Burrito"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next step which is in the subsequent &lt;code&gt;Obtain-Variables&lt;/code&gt; job then uses the &lt;code&gt;needs&lt;/code&gt; keyword to wait for the referenced job to complete. The step then references the outputted variable and assigns it to the internal &lt;code&gt;Dinner&lt;/code&gt; variable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/blob/main/.github/workflows/ex4-passing-variables.yml" rel="noopener noreferrer"&gt;&lt;strong&gt;Job 2 / Example 5&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Obtain-Variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;Create-Variables&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;       &lt;span class="c1"&gt;# &amp;lt;- Jobs run concurrently by default. Over this with the 'needs' keyword to set dependents.&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Reading previous variables&lt;/span&gt;
  &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;windows-latest&lt;/span&gt;

  &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;#Example 4.5&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Print output variable&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;Write-Host "Tonights dinner will be " $Env:Dinner&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Dinner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ needs.create-variables.outputs.dinner }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/runs/5235670515?check_suite_focus=true" rel="noopener noreferrer"&gt;&lt;strong&gt;Console Output&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Run Write-Host &lt;span class="s2"&gt;"Tonights dinner will be"&lt;/span&gt; &lt;span class="nv"&gt;$Env&lt;/span&gt;:Dinner
Tonights dinner will be Burrito
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;h2&gt;
  
  
  5. Web Requests
&lt;/h2&gt;

&lt;p&gt;The below workflow demonstrates a series of simple web calls to the &lt;a href="https://docs.github.com/en/rest/reference/pulls" rel="noopener noreferrer"&gt;Github Api&lt;/a&gt; &lt;code&gt;pulls&lt;/code&gt; endpoint, which returns information  on pull requests. You can feed the response into a json object to access relevant data. The below &lt;code&gt;Invoke-WebRequest&lt;/code&gt; calls will work because this repo is public. If private you will need to &lt;a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token" rel="noopener noreferrer"&gt;create&lt;/a&gt; an OAuth &lt;code&gt;Personal Access Token&lt;/code&gt; to the header with &lt;code&gt;-Headers @{"Authorization"="Bearer &amp;lt;token&amp;gt;"}&lt;/code&gt;. If the repository belongs to an organisation to which you are a member you will need authorize that created token to enable access via &lt;code&gt;configure SSO&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/blob/main/.github/workflows/ex5-web-requests.yml" rel="noopener noreferrer"&gt;&lt;strong&gt;Workflow&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5 - Process Web Requests&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;
        &lt;span class="nv"&gt;main&lt;/span&gt;
    &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Obtain-Pull-Request-Data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Call Github API&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;windows-latest&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;PR_STATE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;closed&lt;/span&gt;      &lt;span class="c1"&gt;# &amp;lt;- query parameters to github are case sensitive&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Call the Github /pulls endpoint&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./Powershell/GithubWebRequests.ps1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/blob/main/Powershell/GithubWebRequests.ps1" rel="noopener noreferrer"&gt;&lt;strong&gt;Input File&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="s2"&gt;"This will return a list of all open pull requests:"&lt;/span&gt;
&lt;span class="nv"&gt;$URI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://api.github.com/repos/&lt;/span&gt;&lt;span class="nv"&gt;$Env&lt;/span&gt;&lt;span class="s2"&gt;:GITHUB_REPOSITORY/pulls"&lt;/span&gt;
Write-Host &lt;span class="nv"&gt;$URI&lt;/span&gt;

&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;nThis will &lt;span class="k"&gt;return &lt;/span&gt;all pull requests of a specified state:&lt;span class="s2"&gt;"
&lt;/span&gt;&lt;span class="nv"&gt;$URI&lt;/span&gt;&lt;span class="s2"&gt; = "&lt;/span&gt;https://api.github.com/repos/&lt;span class="nv"&gt;$Env&lt;/span&gt;:GITHUB_REPOSITORY/pulls?state&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$Env&lt;/span&gt;:PR_STATE&lt;span class="s2"&gt;"
Write-Host &lt;/span&gt;&lt;span class="nv"&gt;$URI&lt;/span&gt;&lt;span class="s2"&gt;

"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="s2"&gt;nThis will return a specific pull request:"&lt;/span&gt;
&lt;span class="nv"&gt;$PR_NUMBER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$Env&lt;/span&gt;:GITHUB_REF_NAME &lt;span class="nt"&gt;-replace&lt;/span&gt; &lt;span class="s2"&gt;"/.*"&lt;/span&gt; &lt;span class="c"&gt;# &amp;lt;- You can also get the PR number from the pull request event file.&lt;/span&gt;
&lt;span class="nv"&gt;$URI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://api.github.com/repos/&lt;/span&gt;&lt;span class="nv"&gt;$Env&lt;/span&gt;&lt;span class="s2"&gt;:GITHUB_REPOSITORY/pulls/&lt;/span&gt;&lt;span class="nv"&gt;$PR_NUMBER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
Write-Host &lt;span class="nv"&gt;$URI&lt;/span&gt;
&lt;span class="nv"&gt;$RESPONSE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; Invoke-WebRequest &lt;span class="nt"&gt;-Uri&lt;/span&gt; &lt;span class="nv"&gt;$URI&lt;/span&gt; &lt;span class="nt"&gt;-Method&lt;/span&gt; Get &lt;span class="nt"&gt;-TimeoutSec&lt;/span&gt; 480
Write-Host &lt;span class="nv"&gt;$RESPONSE&lt;/span&gt;

&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;nAccessing variables from the object: &lt;span class="s2"&gt;"
&lt;/span&gt;&lt;span class="nv"&gt;$JSON_OBJECT&lt;/span&gt;&lt;span class="s2"&gt; = &lt;/span&gt;&lt;span class="nv"&gt;$RESPONSE&lt;/span&gt;&lt;span class="s2"&gt; | ConvertFrom-Json
Write-Host "&lt;/span&gt;HTML URL:&lt;span class="s2"&gt;" &lt;/span&gt;&lt;span class="nv"&gt;$JSON_OBJECT&lt;/span&gt;&lt;span class="s2"&gt;.html_url
Write-Host "&lt;/span&gt;TITLE:&lt;span class="s2"&gt;" &lt;/span&gt;&lt;span class="nv"&gt;$JSON_OBJECT&lt;/span&gt;&lt;span class="s2"&gt;.title
Write-Host "&lt;/span&gt;BODY:&lt;span class="s2"&gt;" &lt;/span&gt;&lt;span class="nv"&gt;$JSON_OBJECT&lt;/span&gt;&lt;span class="s2"&gt;.body
Write-Host "&lt;/span&gt;USER:&lt;span class="s2"&gt;" &lt;/span&gt;&lt;span class="nv"&gt;$JSON_OBJECT&lt;/span&gt;&lt;span class="s2"&gt;.user.login
Write-Host "&lt;/span&gt;REQUESTED REVIEWERS:&lt;span class="s2"&gt;" &lt;/span&gt;&lt;span class="nv"&gt;$JSON_OBJECT&lt;/span&gt;&lt;span class="s2"&gt;.requested_reviewers
Write-Host "&lt;/span&gt;MERGE_COMMIT_SHA:&lt;span class="s2"&gt;" &lt;/span&gt;&lt;span class="nv"&gt;$JSON_OBJECT&lt;/span&gt;&lt;span class="s2"&gt;.merge_commit_sha
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/Mulpeter91/Github-Actionman/runs/5231450238?check_suite_focus=true" rel="noopener noreferrer"&gt;&lt;strong&gt;Console Output&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;This will &lt;span class="k"&gt;return &lt;/span&gt;a list of all open pull requests:
https://api.github.com/repos/Mulpeter91/Github-Actionman/pulls

This will &lt;span class="k"&gt;return &lt;/span&gt;all pull requests of a specified state:
https://api.github.com/repos/Mulpeter91/Github-Actionman/pulls?state&lt;span class="o"&gt;=&lt;/span&gt;closed

This will &lt;span class="k"&gt;return &lt;/span&gt;a specific pull request:
https://api.github.com/repos/Mulpeter91/Github-Actionman/pulls/24

Accessing variables from the object: 
HTML URL: https://github.com/Mulpeter91/Github-Actionman/pull/24
TITLE: Test Title
BODY: Test Body
USER: Mulpeter91
REQUESTED REVIEWERS: 
MERGE_COMMIT_SHA: bd98939094bdb3d775966900ec43a126cf5fac80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;h2&gt;
  
  
  &lt;a id="example-5"&gt;&lt;/a&gt;Conclusion
&lt;/h2&gt;

&lt;p&gt;The purpose of this article and these examples was to give you an introduction to basic concepts and syntax in order to continue learning github actions with a clearer vision of the platform. But this is just the tip of the iceberg. Github actions are capable of far more precise workflows with the use of more complex syntax.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>devops</category>
      <category>automation</category>
      <category>github</category>
    </item>
  </channel>
</rss>
