<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Adil on code]]></title><description><![CDATA[I am a software engineer with 15+ years of experience, mentor with passion, interviewer and a nice person. Here I share notes that I find interesting to you.]]></description><link>https://adil.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1645263113960/GiJL6daCf.png</url><title>Adil on code</title><link>https://adil.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Thu, 16 Apr 2026 20:58:30 GMT</lastBuildDate><atom:link href="https://adil.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Agile effort estimation techniques]]></title><description><![CDATA[Agile effort estimation techniques are approaches used in Agile project management to estimate the amount of time, work, or resources required to complete a specific task, user story, or project. These techniques are designed to be flexible, collabor...]]></description><link>https://adil.dev/agile-effort-estimation-techniques</link><guid isPermaLink="true">https://adil.dev/agile-effort-estimation-techniques</guid><category><![CDATA[agile]]></category><category><![CDATA[project management]]></category><category><![CDATA[Agile Software Development]]></category><category><![CDATA[Scrum]]></category><dc:creator><![CDATA[Adil]]></dc:creator><pubDate>Sat, 30 Sep 2023 00:43:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1696034407612/4b0e951e-16f1-4b12-8abe-c5f1f736e325.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Agile effort estimation techniques are approaches used in Agile project management to estimate the amount of time, work, or resources required to complete a specific task, user story, or project. These techniques are designed to be flexible, collaborative, and responsive to change, which aligns with the principles of Agile development. In this post, we will explore some of them.</p>
<h1 id="heading-1planning-poker">1.Planning poker</h1>
<p>Planning poker is a collaborative estimation technique that uses a deck of cards with values (e.g., Fibonacci sequence) to estimate the complexity of user stories. Team members take turns presenting their estimates, and discussions continue until a consensus is reached. It encourages team participation and minimizes anchoring biases.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762502140829/d14d7560-f96e-4fff-8183-57c5a2550025.png" alt="Generated using AI" class="image--center mx-auto" /></p>
<h2 id="heading-how-to-do">How to do?</h2>
<p>The Agile team, which typically includes developers, testers, and other relevant members, gathers for an estimation session. The product backlog or a list of user stories or tasks to be estimated is ready for discussion. Each participant should have a deck of Planning Poker cards or access to a digital tool designed for Planning Poker. Cards often have values like the Fibonacci sequence (1, 2, 3, 5, 8, 13, etc.), while digital tools display these values for selection.</p>
<p>A moderator or facilitator, often a Scrum Master or Product Owner, leads the session. Their role is to guide the discussion, ensure everyone participates, and keep the process on track.</p>
<p>The moderator selects one user story or task from the backlog for estimation and presents it to the team. The item's description and acceptance criteria may also be shared.</p>
<p>Each team member individually selects a Planning Poker card that represents their estimate of the effort or complexity of the item. They do this privately without revealing their choice to others.</p>
<p>Once everyone has selected a card, the team members simultaneously reveal their chosen cards to the group. If using physical cards, they can reveal them by flipping them face-up at the same time. If using digital tools, they press a button to reveal their estimates simultaneously.</p>
<p>If there is a wide range of estimates, team members briefly discuss the reasoning behind their choices. This discussion helps the team reach a common understanding of the work item. After discussion, team members repeat the estimation process, selecting new cards if their initial estimates have changed. The process of discussion and card selection is repeated until a consensus is reached, or until a predefined time limit is reached.</p>
<p>Once a consensus estimate is reached, the final estimate is recorded and associated with the user story or task in the backlog. This estimate is used for planning and prioritization.</p>
<h2 id="heading-why-the-fibonacci-sequence">Why the Fibonacci sequence?</h2>
<p>The Fibonacci sequence is a non-linear scale, which means that the gap between successive numbers increases as you move up the sequence. This reflects the reality that as work items become more complex or larger, it becomes increasingly challenging to estimate their precise effort or duration. In Agile, the focus is on relative sizing and understanding that a task that is twice as large as another might take significantly more effort.</p>
<p>Using linear scales (e.g., 1, 2, 3, 4, 5) can give a false sense of precision when estimating work. It's difficult for humans to consistently and accurately estimate effort in linear units, such as hours. The Fibonacci sequence acknowledges this uncertainty and encourages teams to think in terms of broader categories.</p>
<h2 id="heading-alternatives">Alternatives</h2>
<p>While the Fibonacci sequence is a widely used scale in Agile estimation, there are several alternatives that teams can consider depending on their preferences and specific needs. These alternative estimation scales include:</p>
<ol>
<li><p><strong>T-shirt Sizes:</strong> Instead of numeric values, teams assign T-shirt sizes (e.g., XS, S, M, L, XL) to represent the relative size and complexity of user stories or tasks. This approach is easy to understand and is useful for high-level, coarse-grained estimation.</p>
</li>
<li><p><strong>Custom Scales:</strong> Teams can create their custom estimation scales based on their specific context and preferences. For example, a team might create a scale that includes values like "Trivial," "Simple," "Moderate," "Complex," and "Very Complex" to reflect the nature of their work.</p>
</li>
</ol>
<h2 id="heading-tools-for-planning-poker">Tools for Planning Poker</h2>
<p>There are several free Planning Poker tools and applications available that teams can use to facilitate Agile estimation and collaborative planning sessions. These tools often offer features like virtual card decks, real-time collaboration, and integration with project management or Agile tools. Here is some of them I tried:</p>
<p><strong>PlanITpoker:</strong> <a target="_blank" href="https://www.planitpoker.com/"><strong>https://www.planitpoker.com/</strong></a></p>
<p><strong>Pointing Poker:</strong> <a target="_blank" href="https://www.pointingpoker.com/"><strong>https://www.pointingpoker.com/</strong></a></p>
<p><strong>Scrumvee:</strong> <a target="_blank" href="https://www.scrumvee.com/"><strong>https://www.scrumvee.com/</strong></a></p>
<h1 id="heading-2dot-voting">2.<strong>Dot Voting</strong></h1>
<p>Dot Voting is an Agile estimation technique suitable for sprint planning, especially when dealing with a relatively small number of items in the Sprint Backlog. It offers a collaborative way for team members to collectively prioritize and allocate effort estimates to user stories or tasks.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762503308583/596c2a1b-1d91-4fc2-8119-84e4be567c93.png" alt="Generated using AI" class="image--center mx-auto" /></p>
<p>Before the Dot Voting session, gather small dot stickers, each color-coded to represent different levels of estimated effort. For example, you can use green for Small (S), blue for Medium (M), orange for Large (L), and red for Extra Large (XL).</p>
<p>Write down the user stories or tasks to be estimated on separate pieces of paper or cards. Place these items on a table or display them on a wall within the team's workspace. Ensure that everyone can easily see and access the items.</p>
<p>Team members are given a set number of dot stickers in each color category corresponding to the estimated effort levels. For instance, each team member might receive a certain number of green, blue, orange, and red stickers.</p>
<p>Team members physically walk around the table or the wall display and assess the items. They then add their colored dot stickers to the items they believe should be prioritized or where they estimate the effort is most needed. Team members can distribute their stickers freely among the items based on their judgments.</p>
<p>Once all team members have allocated their stickers, you can observe which items have accumulated the most dots of each color. The items with more dots indicate higher levels of prioritization or estimated effort.</p>
<p>Depending on the outcomes and the team's preference, you can facilitate a brief discussion to address any significant differences in estimation. This discussion allows team members to explain their rationale and reach a consensus on prioritization or effort allocation.</p>
<h1 id="heading-3the-bucket-system">3.<strong>The</strong> Bucket <strong>System</strong></h1>
<p>The Bucket System is an Agile estimation technique used to categorize and prioritize tasks, user stories, or backlog items based on their perceived size, complexity, or effort. It provides a simple and effective way for Agile teams to quickly group work items into predefined buckets or categories, allowing for easier prioritization and allocation of resources.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1762503374895/873ff24c-ff30-42d9-aec7-3967054c3445.png" alt class="image--center mx-auto" /></p>
<p>Before starting the Bucket System estimation process, gather the team, including developers, testers, and relevant stakeholders, for a collaborative estimation session.</p>
<p>Define the criteria for categorizing items into buckets. These criteria can vary depending on the team's context but often include factors like complexity, effort, risk, or size. Decide on the number and names of buckets that will be used for categorization. Common bucket names include "Small," "Medium," "Large," and "Extra Large," but you can customize them to match your team's needs.</p>
<p>Present a list of user stories, tasks, or backlog items that need to be estimated. These items should be clearly defined, and their descriptions and acceptance criteria should be readily available to the team.</p>
<p>Begin the categorization process by discussing each item one by one. The team members collectively decide which bucket best represents the size, complexity, or effort required to complete the item.</p>
<p>Place each item into the appropriate bucket based on the consensus reached during the discussion. It's essential to have the entire team agree on the categorization for each item.</p>
<p>After categorizing all the items, the team can prioritize the work based on the bucket assignments. Typically, items in smaller buckets are tackled first, followed by those in larger buckets, but this can vary depending on project priorities.</p>
<p>It's important to revisit the Bucket System regularly, especially as new information becomes available or as the team gains a better understanding of the work. Refinement and iteration ensure that items are continuously evaluated and correctly categorized.</p>
<h2 id="heading-largeuncertainsmall"><strong>Large/Uncertain/Small</strong></h2>
<p>The "Large/Uncertain/Small" method is a variation of the Bucket System used in Agile estimation. It categorizes tasks, user stories, or backlog items into three buckets: Large (high effort or uncertainty), Uncertain (moderate effort or uncertainty), and Small (low effort or certainty). This approach helps Agile teams quickly prioritize and allocate work items based on their perceived size and uncertainty, facilitating efficient planning and resource allocation.</p>
<h1 id="heading-4expert-judgment">4.<strong>Expert Judgment</strong></h1>
<p>Expert Judgment is an Agile estimation technique that relies on the expertise and insights of individuals or subject matter experts within the team to assess the effort, complexity, or duration of tasks, user stories, or project components. It is a qualitative approach that leverages the knowledge and experience of team members to provide informed estimates based on their understanding of the work.</p>
<p>Steps:</p>
<ol>
<li><p>Ensure that the Agile team, including developers, testers, and relevant stakeholders, is present for the estimation session. The participation of individuals with diverse expertise is valuable.</p>
</li>
<li><p>Introduce the tasks, user stories, or items that need to be estimated. Provide a clear description of each item, including acceptance criteria and any relevant background information.</p>
</li>
<li><p>Encourage team members to share their expert judgments regarding the effort, complexity, or duration of the items under consideration. Each team member provides their estimation based on their individual expertise.</p>
</li>
<li><p>Facilitate a discussion among team members to address any questions or concerns regarding the items being estimated. This discussion allows experts to share their insights and rationale for their estimations.</p>
</li>
<li><p>After individual estimations and discussions, work toward reaching a consensus estimate for each item. This consensus may involve adjusting estimations based on the input and expertise of the team members.</p>
</li>
</ol>
<h1 id="heading-conclusion">Conclusion</h1>
<p>In summary, Agile effort estimation techniques are essential tools for Agile teams to plan and manage their work effectively. These techniques enable teams to assign relative effort, prioritize tasks, and make informed decisions based on collective input. Some popular Agile estimation techniques include Planning Poker, Dot Voting, the Bucket System, and Expert Judgment.</p>
<ul>
<li><p><strong>Planning Poker</strong> promotes collaborative estimation through card-based voting and discussions, fostering alignment and consensus within the team.</p>
</li>
<li><p><strong>Dot Voting</strong> is a visual technique for prioritizing tasks based on team members' preferences, encouraging participation and transparency.</p>
</li>
<li><p><strong>The Bucket System</strong> categorizes work items into predefined buckets, simplifying prioritization and resource allocation.</p>
</li>
<li><p><strong>Expert Judgment</strong> leverages the expertise of team members to provide informed estimates, particularly valuable for complex or novel tasks.</p>
</li>
</ul>
<p>These Agile estimation techniques, along with others, serve to enhance Agile project planning, promote collaboration, and enable teams to adapt and deliver value effectively. By selecting the most suitable method for their context, Agile teams can refine their estimations, prioritize work, and achieve successful project outcomes.</p>
<p>There are various other Agile estimation methods beyond the ones discussed here as well. These methods may include custom scales, affinity mapping, reference stories, and more. Agile teams often choose the estimation approach that best aligns with their specific context, goals, and team dynamics. The key is to select the method that facilitates effective planning, prioritization, and collaboration within the Agile framework.</p>
]]></content:encoded></item><item><title><![CDATA[How to choose "closest" AWS region?]]></title><description><![CDATA[In today's digitally interconnected world, the speed and efficiency of your cloud infrastructure are crucial. Whether you're hosting a website, running applications, or managing data, the geographic location of your cloud resources can significantly ...]]></description><link>https://adil.dev/how-to-choose-closest-aws-region</link><guid isPermaLink="true">https://adil.dev/how-to-choose-closest-aws-region</guid><category><![CDATA[AWS]]></category><category><![CDATA[infrastructure]]></category><category><![CDATA[networking]]></category><category><![CDATA[high availability]]></category><category><![CDATA[latency]]></category><dc:creator><![CDATA[Adil]]></dc:creator><pubDate>Tue, 19 Sep 2023 07:00:12 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/Q1p7bh3SHj8/upload/fbc9151a052889325aa708f93fa6fd2e.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In today's digitally interconnected world, the speed and efficiency of your cloud infrastructure are crucial. Whether you're hosting a website, running applications, or managing data, the geographic location of your cloud resources can significantly impact performance. AWS, Azure and other cloud providers offer various regions to host your resources. When you design a system it is important to choose the right region for the infrastructure. But how?</p>
<p>A while ago I had a chat with buddies about choosing the "right" AWS region for their solution. The target users were from Azerbaijan and some people suggested that they should use the Bahrain region because it is the closest.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695024102201/465f7678-f532-45e2-9907-b374aa387e63.png" alt class="image--center mx-auto" /></p>
<p>This is how I got the idea for this blog article.</p>
<p>Of course, when we say the "right" region there are many factors such as speed, price, regulations etc. In this blog, we will focus on speed only.</p>
<p>One crucial factor to consider is network hop distance, which directly affects latency and data transfer speeds.</p>
<h1 id="heading-hop-distance">Hop distance?</h1>
<p>When it comes to selecting the right AWS region for your cloud resources, the first idea that comes to mind is to opt for the region that's physically closest to your location. It seems like a logical choice; after all, shorter physical distances should mean faster connections, right? Well, not necessarily.</p>
<p>What many people fail to realize is that the internet is a complex web of interconnected networks, and data doesn't always take the most direct route. Instead, it hops through a series of routers and switches, each introducing a slight delay known as latency. This is where the concept of network hop distance comes into play.</p>
<p><img src="https://th.bing.com/th/id/OIG..wQPuxpvuDy.2K5nWg8u?pid=ImgGn" alt="Create an illustration that explains the &quot;hop distance&quot; in computer networks. Illustration must include the map of geographical regions and with arrows show the distances. It can include network devices too." /></p>
<p>Network hop distance is the number of network hops (or routers) data packets that must traverse between the source and destination. Network hop distance is a more accurate measure of network performance. Lower hop distance typically results in lower latency, faster data transfers, and an improved user experience, regardless of physical distance.</p>
<h1 id="heading-so-how-to-choose-the-aws-region">So how to choose the AWS region?</h1>
<p>To determine the AWS region that offers the lowest network hop distance for your users, follow these steps:</p>
<h3 id="heading-1-identify-your-user-base"><strong>1. Identify Your User Base</strong></h3>
<p>Start by identifying the geographic locations of your primary user base, just as you did in the scenario with friends.</p>
<h3 id="heading-2-locate-aws-regions"><strong>2. Locate AWS Regions</strong></h3>
<p>AWS provides data centers, known as regions, across the globe. Each region consists of multiple Availability Zones, which are essentially separate data centers within the same geographic area. AWS regions are located in North America, South America, Europe, Asia, Australia, and the Middle East. Visit the <a target="_blank" href="https://aws.amazon.com/about-aws/global-infrastructure/"><strong>AWS Global Infrastructure</strong></a> page to see a list of AWS regions and their locations.</p>
<h3 id="heading-3-measure-network-hop-distance"><strong>3. Measure Network Hop Distance</strong></h3>
<p>You can use network diagnostic tools like <code>traceroute</code> or <code>ping</code> to find the hop distance between your users and various AWS regions, regardless of physical proximity.</p>
<p><strong>Traceroute</strong>: Open your command prompt or terminal and run the <code>traceroute</code> command followed by the IP address or domain name of the AWS region. For example:</p>
<ul>
<li><pre><code class="lang-bash">  traceroute ec2.us-east-1.amazonaws.com
</code></pre>
</li>
</ul>
<p>This will display a list of routers (hops) and their round-trip times (latency) between your location and the AWS region.</p>
<p>If you want to see something visual, just for consideration you can visit <a target="_blank" href="https://www.submarinecablemap.com/">https://www.submarinecablemap.com/</a>. This web page has an interactive map of cables by most of the companies. However, I do not recommend you to rely on it as it will not be accurate.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Choosing the closest AWS region based on network hop distance is a fundamental step in optimizing the performance of your cloud-based applications and services. By identifying your user base, locating AWS regions, and measuring hop distances, you can make an informed decision that minimizes latency and provides the best possible user experience.</p>
<p>Remember that network conditions can change over time, so it's a good practice to periodically reevaluate your AWS region choice to ensure optimal performance for your users. With the right region selection, you can harness the full potential of AWS and deliver a seamless and responsive online experience.</p>
]]></content:encoded></item><item><title><![CDATA[Deployment pipeline for NextJS with Azure Static Web Apps and GitHub Actions]]></title><description><![CDATA[Introduction
In today's fast-paced digital landscape, having a reliable and scalable platform to host your web applications is crucial. Azure Static Web Apps, offered by Microsoft Azure, is a powerful solution for deploying static websites and single...]]></description><link>https://adil.dev/deployment-pipeline-for-nextjs-with-azure-static-web-apps-and-github-actions</link><guid isPermaLink="true">https://adil.dev/deployment-pipeline-for-nextjs-with-azure-static-web-apps-and-github-actions</guid><category><![CDATA[Azure]]></category><category><![CDATA[AWS Amplify]]></category><category><![CDATA[Azure Static Web Apps]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[GitHub Actions]]></category><dc:creator><![CDATA[Adil]]></dc:creator><pubDate>Mon, 18 Sep 2023 05:58:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1695023229812/fcf3d7a5-3595-4a9e-8d80-8ed957327a85.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>In today's fast-paced digital landscape, having a reliable and scalable platform to host your web applications is crucial. Azure Static Web Apps, offered by Microsoft Azure, is a powerful solution for deploying static websites and single-page applications with ease.</p>
<p>In this blog post, we'll walk you through the process of deploying a static Next.js app to Azure Static Web Apps using GitHub. You'll learn how to set up your environment, configure Azure, automate the deployment process with GitHub Actions, and finally, enjoy the benefits of a highly available and globally distributed web application.</p>
<p>So, whether you're a seasoned developer looking to streamline your deployment workflow or a newcomer eager to explore modern web development practices, this guide is for you. Let's dive in and discover how to harness the power of Azure Static Web Apps for hosting your Next.js projects.</p>
<h1 id="heading-create-nextjs-application">Create NextJS application</h1>
<p>First of all, we need a sample NextJS application. This can be your existing NextJS application too. In this tutorial, we will use a sample from Vercel based on the tutorial [1].</p>
<p>Type the following command in your terminal to create a sample NextJS application in <code>nextjs-blog</code> directory.</p>
<pre><code class="lang-bash">npx create-next-app@latest nextjs-blog --use-npm --example <span class="hljs-string">"https://github.com/vercel/next-learn/tree/main/basics/learn-starter"</span>
</code></pre>
<p>After the app is created test it to make sure it works.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> nextjs-blog
npm install
npm run dev
</code></pre>
<p>Go to your browser and check the URL (http://localhost:3000).</p>
<p>As we want to deploy it to Azure Static Web Apps we need to do some tricks, in particular, we want to export the NextJS app statically.</p>
<p>Create a file <code>next.config.js</code> in the home folder of the application with the following content:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">module</span>.exports = {
    <span class="hljs-attr">images</span>: {
        <span class="hljs-attr">unoptimized</span>: <span class="hljs-literal">true</span>
    },
    <span class="hljs-attr">trailingSlash</span>: <span class="hljs-literal">true</span>,
    <span class="hljs-attr">output</span>: <span class="hljs-string">'export'</span>
}
</code></pre>
<p>Now, let's try to build</p>
<pre><code class="lang-javascript">npm run build
</code></pre>
<p>If successful you will see a newly created directory <code>/out</code>. This directory contains static HTML/JS/CSS files compiled from your NextJS app.</p>
<p>Hooray, we are ready to deploy it to Azure using the Static Web Apps service.</p>
<h1 id="heading-set-up-the-github-repository">Set up the GitHub repository</h1>
<p>Create a GitHub repository and upload your NextJS application to that repository.</p>
<h1 id="heading-deploy-to-static-web-apps">Deploy to Static Web Apps</h1>
<p>In this stage, we want to explore how Static Web Apps work and do a basic setup. In the next phase, we will refine our pipeline.</p>
<p>In this tutorial, I will follow the steps from the tutorial published on Microsoft's web page [2].</p>
<ol>
<li><p>Go to the Azure portal</p>
</li>
<li><p>Search for <code>Static Web Apps</code></p>
</li>
<li><p>Click <code>Create</code></p>
</li>
</ol>
<p>Enter the necessary data in the form and Sign in with GitHub:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695011019591/600595c8-cc8e-4678-aaf7-cca89faf8d09.png" alt class="image--center mx-auto" /></p>
<p>Follow the instructions and workflow file will be created automatically in your repository with the following content (we will edit it in the next section):</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Azure</span> <span class="hljs-string">Static</span> <span class="hljs-string">Web</span> <span class="hljs-string">Apps</span> <span class="hljs-string">CI/CD</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">main</span>
  <span class="hljs-attr">pull_request:</span>
    <span class="hljs-attr">types:</span> [<span class="hljs-string">opened</span>, <span class="hljs-string">synchronize</span>, <span class="hljs-string">reopened</span>, <span class="hljs-string">closed</span>]
    <span class="hljs-attr">branches:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">main</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build_and_deploy_job:</span>
    <span class="hljs-attr">if:</span> <span class="hljs-string">github.event_name</span> <span class="hljs-string">==</span> <span class="hljs-string">'push'</span> <span class="hljs-string">||</span> <span class="hljs-string">(github.event_name</span> <span class="hljs-string">==</span> <span class="hljs-string">'pull_request'</span> <span class="hljs-string">&amp;&amp;</span> <span class="hljs-string">github.event.action</span> <span class="hljs-type">!=</span> <span class="hljs-string">'closed'</span><span class="hljs-string">)</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">and</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">Job</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">submodules:</span> <span class="hljs-literal">true</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">And</span> <span class="hljs-string">Deploy</span>
        <span class="hljs-attr">id:</span> <span class="hljs-string">builddeploy</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">Azure/static-web-apps-deploy@v1</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">azure_static_web_apps_api_token:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_&lt;GENERATED_HOSTNAME&gt;</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">repo_token:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.GITHUB_TOKEN</span> <span class="hljs-string">}}</span> <span class="hljs-comment"># Used for Github integrations (i.e. PR comments)</span>
          <span class="hljs-attr">action:</span> <span class="hljs-string">"upload"</span>
          <span class="hljs-comment">###### Repository/Build Configurations - These values can be configured to match your app requirements. ######</span>
          <span class="hljs-comment"># For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig</span>
          <span class="hljs-attr">app_location:</span> <span class="hljs-string">"/"</span> <span class="hljs-comment"># App source code path</span>
          <span class="hljs-attr">api_location:</span> <span class="hljs-string">""</span> <span class="hljs-comment"># Api source code path - optional</span>
          <span class="hljs-attr">output_location:</span> <span class="hljs-string">"out"</span> <span class="hljs-comment"># Built app content directory - optional</span>
          <span class="hljs-comment">###### End of Repository/Build Configurations ######</span>

  <span class="hljs-attr">close_pull_request_job:</span>
    <span class="hljs-attr">if:</span> <span class="hljs-string">github.event_name</span> <span class="hljs-string">==</span> <span class="hljs-string">'pull_request'</span> <span class="hljs-string">&amp;&amp;</span> <span class="hljs-string">github.event.action</span> <span class="hljs-string">==</span> <span class="hljs-string">'closed'</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">Close</span> <span class="hljs-string">Pull</span> <span class="hljs-string">Request</span> <span class="hljs-string">Job</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Close</span> <span class="hljs-string">Pull</span> <span class="hljs-string">Request</span>
        <span class="hljs-attr">id:</span> <span class="hljs-string">closepullrequest</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">Azure/static-web-apps-deploy@v1</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">azure_static_web_apps_api_token:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_&lt;GENERATED_HOSTNAME&gt;</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">action:</span> <span class="hljs-string">"close"</span>
</code></pre>
<p>The basic pipeline is set. Whenever you raise a pull request in your repository GitHub Action will be triggered and deploy your web app into Azure.</p>
<p>The wizard in the previous step created a workflow file and pushed it into your repository. And also necessary secrets (<code>AZURE_STATIC_WEB_APPS_API_TOKEN_&lt;GENERATED_HOSTNAME&gt;</code>) has been created for you to integrate GitHub with Azure. You can see it in the settings of your GitHub repository.</p>
<p>When PR is created the workflow will be triggered and after a while, the endpoint URL will be seen in the comments section:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695011756361/04701b6f-688c-43a7-acf0-dee9a5fdc674.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-multiple-staged-deployment">Multiple staged deployment</h1>
<p>When your webpage goes to production and gains an audience you won't publish any experimental untested code into production. On the other hand, you still need some environment where you want to see the output of the latest codes before deciding to publish. Here the idea of multi-staged deployment comes.</p>
<p>The diagram below explains the high-level idea:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695012829791/142bc3aa-cc07-4533-bfe4-4d0ae6b21991.png" alt class="image--center mx-auto" /></p>
<p>Now, let's implement it. At first, we will edit our workflow file and we will trigger deployment on PR only for the development environment (we will call it preview).</p>
<p>Magically, when you raise a PR Azure Static Web Apps (actually Azure scripts that GHA uses) and create a temporary environment. The URL will be published as a comment in the PR. Therefore, the preview environment is done for us out of the box.</p>
<p>Now we want a beta environment. Any code that is merged into the <code>main</code> branch will trigger an action to deploy it to a <code>beta</code> environment without approval. To make things easier we will use an already existing environment as a preview of and beta. Because Azure already did all the magic for us.</p>
<p>Now it is my turn to create a production environment. We go to Azure portal -&gt; Static Web Apps -&gt; Create.</p>
<p>This time under the source we chose <strong>Other</strong>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695015816606/b85146c2-8353-4863-b4e8-76dfc1fd1c29.png" alt class="image--center mx-auto" /></p>
<ol>
<li>After the app is created go to the Overview page and click "Manage deployment token":</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695015860546/35fdc9f2-38aa-4de6-833c-418a696b7677.png" alt class="image--center mx-auto" /></p>
<ol>
<li><p>Copy the token.</p>
</li>
<li><p>Then go to the GitHub repository. Click Settings.</p>
</li>
<li><p>Secrets and Variables -&gt; Actions</p>
<p> <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695015946058/f3b98060-0aeb-4e19-9718-9d161923fc07.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>New repository secret.</p>
</li>
<li><p>Paste the token and give a name. In my example the name was <code>AZURE_STATIC_WEB_APPS_API_TOKEN_PRODUCTION</code></p>
</li>
</ol>
<p>Now it is time to edit our workflow file. Here is my final workflow file:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Azure</span> <span class="hljs-string">Static</span> <span class="hljs-string">Web</span> <span class="hljs-string">Apps</span> <span class="hljs-string">CI/CD</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">main</span>
  <span class="hljs-attr">pull_request:</span>
    <span class="hljs-attr">types:</span> [<span class="hljs-string">opened</span>, <span class="hljs-string">synchronize</span>, <span class="hljs-string">reopened</span>, <span class="hljs-string">closed</span>]
    <span class="hljs-attr">branches:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">main</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build_and_deploy_job:</span>
    <span class="hljs-attr">needs:</span> [<span class="hljs-string">build_and_deploy_to_beta</span>]
    <span class="hljs-attr">if:</span> <span class="hljs-string">github.event_name</span> <span class="hljs-string">==</span> <span class="hljs-string">'push'</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">PROD</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-attr">name:</span> <span class="hljs-string">production</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">submodules:</span> <span class="hljs-literal">true</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">And</span> <span class="hljs-string">Deploy</span>
        <span class="hljs-attr">id:</span> <span class="hljs-string">builddeploy</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">Azure/static-web-apps-deploy@v1</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">azure_static_web_apps_api_token:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_PRODUCTION</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">repo_token:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.GITHUB_TOKEN</span> <span class="hljs-string">}}</span> <span class="hljs-comment"># Used for Github integrations (i.e. PR comments)</span>
          <span class="hljs-attr">action:</span> <span class="hljs-string">"upload"</span>
          <span class="hljs-comment">###### Repository/Build Configurations - These values can be configured to match your app requirements. ######</span>
          <span class="hljs-comment"># For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig</span>
          <span class="hljs-attr">app_location:</span> <span class="hljs-string">"/"</span> <span class="hljs-comment"># App source code path</span>
          <span class="hljs-attr">api_location:</span> <span class="hljs-string">""</span> <span class="hljs-comment"># Api source code path - optional</span>
          <span class="hljs-attr">output_location:</span> <span class="hljs-string">"out"</span> <span class="hljs-comment"># Built app content directory - optional</span>
          <span class="hljs-comment">###### End of Repository/Build Configurations ######</span>
        <span class="hljs-attr">env:</span> <span class="hljs-comment"># Add environment variables here</span>
          <span class="hljs-attr">IS_STATIC_EXPORT:</span> <span class="hljs-literal">true</span>      

  <span class="hljs-attr">build_and_deploy_to_dev:</span>
    <span class="hljs-attr">if:</span> <span class="hljs-string">(github.event_name</span> <span class="hljs-string">==</span> <span class="hljs-string">'pull_request'</span> <span class="hljs-string">&amp;&amp;</span> <span class="hljs-string">github.event.action</span> <span class="hljs-type">!=</span> <span class="hljs-string">'closed'</span><span class="hljs-string">)</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">DEV</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-attr">name:</span> <span class="hljs-string">development</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">submodules:</span> <span class="hljs-literal">true</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">And</span> <span class="hljs-string">Deploy</span>
        <span class="hljs-attr">id:</span> <span class="hljs-string">builddeploy</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">Azure/static-web-apps-deploy@v1</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">azure_static_web_apps_api_token:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_LEMON_ROCK_00E996803</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">repo_token:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.GITHUB_TOKEN</span> <span class="hljs-string">}}</span> <span class="hljs-comment"># Used for Github integrations (i.e. PR comments)</span>
          <span class="hljs-attr">action:</span> <span class="hljs-string">"upload"</span>
          <span class="hljs-comment">###### Repository/Build Configurations - These values can be configured to match your app requirements. ######</span>
          <span class="hljs-comment"># For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig</span>
          <span class="hljs-attr">app_location:</span> <span class="hljs-string">"/"</span> <span class="hljs-comment"># App source code path</span>
          <span class="hljs-attr">api_location:</span> <span class="hljs-string">""</span> <span class="hljs-comment"># Api source code path - optional</span>
          <span class="hljs-attr">output_location:</span> <span class="hljs-string">"out"</span> <span class="hljs-comment"># Built app content directory - optional</span>
          <span class="hljs-comment">###### End of Repository/Build Configurations ######</span>
        <span class="hljs-attr">env:</span> <span class="hljs-comment"># Add environment variables here</span>
          <span class="hljs-attr">IS_STATIC_EXPORT:</span> <span class="hljs-literal">true</span>        
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Comment</span> <span class="hljs-string">URL</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/github-script@v6</span>
        <span class="hljs-attr">env:</span>
          <span class="hljs-attr">STATIC_WEB_APP_URL:</span> <span class="hljs-string">${{</span> <span class="hljs-string">steps.builddeploy.outputs.static_web_app_url</span> <span class="hljs-string">}}</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">script:</span> <span class="hljs-string">|
            console.log(JSON.stringify(process.env))
            github.rest.issues.createComment({
                issue_number: context.issue.number,
                owner: context.repo.owner,
                repo: context.repo.repo,
                body: '👋 Eşq olsun!\nWeb sayt müvəqqəti olaraq bu ünvanda yerləşdirildi: ' + process.env["STATIC_WEB_APP_URL"]
              })
</span>
  <span class="hljs-attr">build_and_deploy_to_beta:</span>
    <span class="hljs-attr">if:</span> <span class="hljs-string">github.event_name</span> <span class="hljs-string">==</span> <span class="hljs-string">'push'</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">BETA</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-attr">name:</span> <span class="hljs-string">development</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">submodules:</span> <span class="hljs-literal">true</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">And</span> <span class="hljs-string">Deploy</span>
        <span class="hljs-attr">id:</span> <span class="hljs-string">builddeploy</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">Azure/static-web-apps-deploy@v1</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">azure_static_web_apps_api_token:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_LEMON_ROCK_00E996803</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">repo_token:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.GITHUB_TOKEN</span> <span class="hljs-string">}}</span> <span class="hljs-comment"># Used for Github integrations (i.e. PR comments)</span>
          <span class="hljs-attr">action:</span> <span class="hljs-string">"upload"</span>
          <span class="hljs-comment">###### Repository/Build Configurations - These values can be configured to match your app requirements. ######</span>
          <span class="hljs-comment"># For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig</span>
          <span class="hljs-attr">app_location:</span> <span class="hljs-string">"/"</span> <span class="hljs-comment"># App source code path</span>
          <span class="hljs-attr">api_location:</span> <span class="hljs-string">""</span> <span class="hljs-comment"># Api source code path - optional</span>
          <span class="hljs-attr">output_location:</span> <span class="hljs-string">"out"</span> <span class="hljs-comment"># Built app content directory - optional</span>
          <span class="hljs-comment">###### End of Repository/Build Configurations ######</span>
        <span class="hljs-attr">env:</span> <span class="hljs-comment"># Add environment variables here</span>
          <span class="hljs-attr">IS_STATIC_EXPORT:</span> <span class="hljs-literal">true</span>     

  <span class="hljs-attr">close_pull_request_job:</span>
    <span class="hljs-attr">if:</span> <span class="hljs-string">github.event_name</span> <span class="hljs-string">==</span> <span class="hljs-string">'pull_request'</span> <span class="hljs-string">&amp;&amp;</span> <span class="hljs-string">github.event.action</span> <span class="hljs-string">==</span> <span class="hljs-string">'closed'</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">Close</span> <span class="hljs-string">Pull</span> <span class="hljs-string">Request</span> <span class="hljs-string">Job</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Close</span> <span class="hljs-string">Pull</span> <span class="hljs-string">Request</span>
        <span class="hljs-attr">id:</span> <span class="hljs-string">closepullrequest</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">Azure/static-web-apps-deploy@v1</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">azure_static_web_apps_api_token:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_LEMON_ROCK_00E996803</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">action:</span> <span class="hljs-string">"close"</span>
</code></pre>
<p>I have three jobs:</p>
<ul>
<li><p><code>build_and_deploy_to_dev</code> - a job to deploy to the preview environment.</p>
</li>
<li><p><code>build_and_deploy_to_beta</code> - a job to deploy to the beta</p>
</li>
<li><p><code>build_and_deploy_job</code> - a job to deploy to the production</p>
</li>
</ul>
<p>To demonstrate some features I created an environment variable <code>STATIC_WEB_APP_URL</code> in <code>build_and_deploy_to_dev</code> job. This variable will contain content from the output of the previous step [3][4]. The next step will use this environment variable to put a comment in PR [5].</p>
<p>Another important point is we need an approval mechanism for production deployment. To achieve this:</p>
<ol>
<li><p>In GitHub go to Settings.</p>
</li>
<li><p>Environment -&gt; New Environment</p>
</li>
<li><p>Environment name: <code>production</code> (because in workflow file in <code>build_and_deploy_job</code> we used the same name under <code>environment</code> attribute.</p>
</li>
<li><p>Create</p>
</li>
<li><p>Now you can add reviewers.</p>
</li>
</ol>
<p>Done :)</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Deploying a Next.js application to Azure Static Web Apps through GitHub Actions provides you with a robust and efficient workflow. It enables you to focus on what matters most—building amazing web experiences—while automation takes care of the deployment process.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1695016360498/89b68fc1-7f1e-48fa-a856-1bd55ef37d3c.png" alt class="image--center mx-auto" /></p>
<p>As you've learned in this guide, Azure Static Web Apps offers numerous advantages, including scalability, global availability, and effortless integration with your GitHub repositories. With a simple push to your main branch, your changes are automatically deployed to the Azure cloud without worrying about infrastructure management. Azure Static Web Apps and GitHub Actions give you the tools you need to succeed in this environment.</p>
<p>We hope this guide has been valuable in your journey towards efficient Next.js deployments on Azure. Now, go ahead and leverage this newfound knowledge to take your web applications to the next level. Happy coding!</p>
<h1 id="heading-references">References</h1>
<ol>
<li><p><a target="_blank" href="https://nextjs.org/learn/basics/create-nextjs-app">https://nextjs.org/learn/basics/create-nextjs-app</a></p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/azure/static-web-apps/getting-started?tabs=vanilla-javascript">https://learn.microsoft.com/en-us/azure/static-web-apps/getting-started?tabs=vanilla-javascript</a></p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/azure/static-web-apps/review-publish-pull-requests">https://learn.microsoft.com/en-us/azure/static-web-apps/review-publish-pull-requests</a></p>
</li>
<li><p><a target="_blank" href="https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idoutputs">https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idoutputs</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/actions/github-script#comment-on-an-issue">https://github.com/actions/github-script#comment-on-an-issue</a></p>
</li>
</ol>
]]></content:encoded></item></channel></rss>