<?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: Agustinus Theodorus</title>
    <description>The latest articles on DEV Community by Agustinus Theodorus (@agustinustheo).</description>
    <link>https://dev.to/agustinustheo</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%2F453561%2F060d3550-d418-4bcd-a75c-e4d68d0075ec.jpg</url>
      <title>DEV Community: Agustinus Theodorus</title>
      <link>https://dev.to/agustinustheo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/agustinustheo"/>
    <language>en</language>
    <item>
      <title>How to Deploy Flutter Web to Netlify Using CI/CD and Azure Pipelines</title>
      <dc:creator>Agustinus Theodorus</dc:creator>
      <pubDate>Wed, 20 Jan 2021 14:44:42 +0000</pubDate>
      <link>https://dev.to/agustinustheo/how-to-deploy-flutter-web-to-netlify-using-ci-cd-and-azure-pipelines-20ga</link>
      <guid>https://dev.to/agustinustheo/how-to-deploy-flutter-web-to-netlify-using-ci-cd-and-azure-pipelines-20ga</guid>
      <description>&lt;p&gt;Developing web apps has become easier over the years. With Flutter it became very easy and fun. But to be honest, deploying it is sometimes a pain. Most services are not ready for Flutter projects being hosted on the web. Sure, &lt;strong&gt;&lt;em&gt;some are&lt;/em&gt;&lt;/strong&gt; but it needs a bit of tinkering.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Zma6h_d0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2AZuxm0Houm1FyBdTE" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Zma6h_d0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2AZuxm0Houm1FyBdTE" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I don’t mind tinkering a bit, I mean… Why not?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here in this tutorial, I am going to share with you how to implement CI/CD on your Flutter web deployments using Azure DevOps Pipelines. And best of all, we are going to use Netlify! Why do I sound excited? Because honestly, Netlify is very easy to use. Now, without further ado let’s get to it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing Dependencies
&lt;/h3&gt;

&lt;p&gt;Before we start, we need to install the required dependencies beforehand.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Installing the Flutter plugin
&lt;/h4&gt;

&lt;p&gt;Well, you can use the &lt;a href="https://marketplace.visualstudio.com/items?itemName=aloisdeniel.flutter"&gt;Flutter plugin for DevOps&lt;/a&gt; a dev already made the tool for us. Thanks, &lt;a href="https://marketplace.visualstudio.com/publishers/aloisdeniel"&gt;Aloïs&lt;/a&gt; for doing the heavy work! We can use this tool for our purpose.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DTSII1kW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AngPggahl55mBGRJ-FGlSRg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DTSII1kW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AngPggahl55mBGRJ-FGlSRg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After clicking that button, you would be shown on this screen:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JHn1791N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2A52i3t0Qhvy239I_MS3GPpA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JHn1791N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2A52i3t0Qhvy239I_MS3GPpA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now in what you have to do is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Choose the &lt;strong&gt;organization&lt;/strong&gt; you want to install.&lt;/li&gt;
&lt;li&gt;Click install.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  2. Installing the Nelitfy plugin
&lt;/h4&gt;

&lt;p&gt;Install the &lt;a href="https://marketplace.visualstudio.com/items?itemName=aliencube.netlify-cli-extensions"&gt;Netlify plugin for DevOps&lt;/a&gt;. Thanks, &lt;a href="https://marketplace.visualstudio.com/publishers/aliencube"&gt;Aliencube&lt;/a&gt; for doing the heavy work! We can use this tool for our purpose.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--g1JmjzbI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2Ajv3I_5-xsOTw5rvU9OwA8A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--g1JmjzbI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2Ajv3I_5-xsOTw5rvU9OwA8A.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After clicking that button, you would be shown on this screen:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xIov4TRt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AMuPn6jiFUqW8KnVkxl4Xww.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xIov4TRt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AMuPn6jiFUqW8KnVkxl4Xww.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now in what you have to do is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Choose the &lt;strong&gt;organization&lt;/strong&gt; you want to install.&lt;/li&gt;
&lt;li&gt;Click install.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Creating your Netlify site
&lt;/h3&gt;

&lt;p&gt;This section will discuss how you can create an empty Netlify site using Netlify CLI. We will be using npm to install it for us. In my case, I use Ubuntu 18.04 as the host OS for the npm installation.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Install Netlify CLI
&lt;/h4&gt;

&lt;p&gt;To install Netlify CLI you just need to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install netlify-cli -g

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

&lt;/div&gt;



&lt;p&gt;After the installation is complete, check if it’s installed correctly by running this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;netlify

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Log in to Netlify from the CLI
&lt;/h4&gt;

&lt;p&gt;Before you can start using the CLI, Netlify needs you to authenticate yourself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;netlify login

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

&lt;/div&gt;



&lt;p&gt;Then a browser window will open:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nhR9_AHX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2A4FnW4DUyG4w5_kPC.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nhR9_AHX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2A4FnW4DUyG4w5_kPC.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Creating a blank site
&lt;/h4&gt;

&lt;p&gt;After finishing your login, create a blank site using this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;netlify sites:create --name _&amp;lt;site name&amp;gt;_

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  4. Retrieving your Site ID and personal access token
&lt;/h4&gt;

&lt;p&gt;To run continuous development remotely you would need both your site ID and personal access token to help you&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yb_YcsKn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2APxWjk8axlVeVwmUt33_gQw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yb_YcsKn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2APxWjk8axlVeVwmUt33_gQw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Retrieve your Site ID by:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Going into the site settings.&lt;/li&gt;
&lt;li&gt;Copy the API ID value.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The next step would be to retrieve the personal access token.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fxhW65Uk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2Atbk9PgZpJudHMFp6kUvdvg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fxhW65Uk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2Atbk9PgZpJudHMFp6kUvdvg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go to the User settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DMy-ma1Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AAKe8XmKjoeIzeCfples1MA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DMy-ma1Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AAKe8XmKjoeIzeCfples1MA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To get an access token, you would have to make a new one:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the Applications tab.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;New access token&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Copy and save the access token shown on the next screen, and save it because you will need it for later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the CI/CD Pipeline
&lt;/h3&gt;

&lt;p&gt;This part is my favorite because it uses Azure DevOps. I honestly love the pipeline building experience using the UI (e.g the classic editor). But how do you build Flutter projects using Azure DevOps you ask?&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Creating the CI pipeline
&lt;/h4&gt;

&lt;p&gt;If you are using Azure DevOps there is no way we can attach a CI/CD pipeline from Netlify’s side as with Github, Gitlab, or Bitbucket. So, we have to get down and dirty and do it ourselves (well with a little help).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WFef_dfP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AtlnoTcTVMomfdREqv4-3gg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WFef_dfP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AtlnoTcTVMomfdREqv4-3gg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, create your pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click on &lt;strong&gt;Pipelines&lt;/strong&gt; on the left pane.&lt;/li&gt;
&lt;li&gt;Open the &lt;strong&gt;Pipelines&lt;/strong&gt; directory.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;New pipeline&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now the beautiful thing about Azure DevOps is they have a UI for all of this, so you don’t need to use YAML at all. Though you can generate YAML code from the UI. Using the classic editor, you don’t have two remember YAML syntaxes and can easily make deployment steps using the visuals.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--12q5BcNT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AQedkUDLpwccXAdxvYegBYg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--12q5BcNT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AQedkUDLpwccXAdxvYegBYg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can always configure using YAML in other services, but let’s face it, using UI is so much better. To enable pipeline configurations using the UI, when you are creating your pipeline click the small &lt;strong&gt;use classic editor&lt;/strong&gt; link below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--csF9fym2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AkkHm8ht19fXaH29NTHqcyw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--csF9fym2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AkkHm8ht19fXaH29NTHqcyw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After selecting the classic editor, configure your project:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YzzMXcAT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AeKEEhy8lVmAWILNp5D8kcg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YzzMXcAT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AeKEEhy8lVmAWILNp5D8kcg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These configurations would be needed to state which project you will be using in the pipeline, start by:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Selecting Azure Repos Git, to select repositories from Azure DevOps.&lt;/li&gt;
&lt;li&gt;Selecting your team project.&lt;/li&gt;
&lt;li&gt;Selecting the repository you want to CI.&lt;/li&gt;
&lt;li&gt;Select the repository branch.&lt;/li&gt;
&lt;li&gt;Click continue.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sj9ZpKef--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AXy65VtOhVJU4j-Td-3Pk7w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sj9ZpKef--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AXy65VtOhVJU4j-Td-3Pk7w.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the &lt;strong&gt;Empty job&lt;/strong&gt; button to create a clean slate for our Flutter deployment configuration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T_-DyGpx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2ATS7XNzRgBE7XTmMSC879Jw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T_-DyGpx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2ATS7XNzRgBE7XTmMSC879Jw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After &lt;strong&gt;Agent job 1&lt;/strong&gt; show up you need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click the &lt;strong&gt;+&lt;/strong&gt; button to add new tasks in the pipeline.&lt;/li&gt;
&lt;li&gt;Search for &lt;strong&gt;Flutter Install&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Flutter Install&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--014RjK-i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AXGnxKbjSWXkEBuElDjgNAg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--014RjK-i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AXGnxKbjSWXkEBuElDjgNAg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After adding Flutter install we can add the Flutter test task to enable testing in our pipeline before being built and deployed. But because I prepared a small app and I am focusing on deployments I wouldn’t be adding testing to the task list.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fSZvf2lV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2A1wCLnwZr7P-flEIcxA3W8g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fSZvf2lV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2A1wCLnwZr7P-flEIcxA3W8g.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, add two &lt;strong&gt;Flutter Command&lt;/strong&gt; tasks to the pipeline. FYI, tasks are forms of stages deliberately visualizing how our CI/CD pipeline connects.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Let’s face it, using UI is so much better.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--i4V7hKWh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AEFSPGRwA00ZhLFDP72DNrQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i4V7hKWh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AEFSPGRwA00ZhLFDP72DNrQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first &lt;strong&gt;Flutter Command&lt;/strong&gt; task will be to enable web configurations (i.e allow builds for web projects).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click the &lt;strong&gt;Flutter Command&lt;/strong&gt; task.&lt;/li&gt;
&lt;li&gt;Change the display name to &lt;strong&gt;Flutter Enable Web&lt;/strong&gt; (optional).&lt;/li&gt;
&lt;li&gt;Add the Flutter arguments to enable web configurations:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;config --enable-web

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fotmUMwY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AoeQhNtLL0XWYoPA0Uzh51Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fotmUMwY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AoeQhNtLL0XWYoPA0Uzh51Q.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To build the web project, we have to run it manually using the &lt;strong&gt;Flutter Command&lt;/strong&gt; task.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click the &lt;strong&gt;Flutter Command&lt;/strong&gt; task.&lt;/li&gt;
&lt;li&gt;Change the display name to &lt;strong&gt;Flutter Run Build Web&lt;/strong&gt; (optional).&lt;/li&gt;
&lt;li&gt;Add the Flutter arguments to build web projects:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;build web

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--trh-wddr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AxsFcjMbriYuUmwspfakwLw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--trh-wddr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AxsFcjMbriYuUmwspfakwLw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add a new task to &lt;strong&gt;Copy files&lt;/strong&gt; :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click the &lt;strong&gt;+&lt;/strong&gt; button to add a new task.&lt;/li&gt;
&lt;li&gt;Search for &lt;strong&gt;copy files&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Add the &lt;strong&gt;Copy files&lt;/strong&gt; task.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--slbctUok--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AJcHH8-BvCC1_pmuI7oDiNQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--slbctUok--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AJcHH8-BvCC1_pmuI7oDiNQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After we build the project, build files will need to be copied to the artifacts directory:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click the &lt;strong&gt;Copy Files&lt;/strong&gt; task.&lt;/li&gt;
&lt;li&gt;Change the source folder to &lt;strong&gt;$(Build.SourcesDirectory)/build/web&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Change the target folder to &lt;strong&gt;$(Build.ArtifactStagingDirectory)&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--q64bCgI8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2Ai2HONWrqH04lMo1WEatx0w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q64bCgI8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2Ai2HONWrqH04lMo1WEatx0w.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add a new task to &lt;strong&gt;Publish build artifacts&lt;/strong&gt; :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click the &lt;strong&gt;+&lt;/strong&gt; button to add a new task.&lt;/li&gt;
&lt;li&gt;Search for &lt;strong&gt;publish build artifact&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Add the &lt;strong&gt;Publish build artifacts&lt;/strong&gt; task.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nhueSAYP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AK1sbK9jzcue5qpJNITm3iw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nhueSAYP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AK1sbK9jzcue5qpJNITm3iw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After adding the &lt;strong&gt;Publish build artifacts&lt;/strong&gt; task you can change the name of the artifact after publishing in this case I changed it to &lt;strong&gt;ci-artifact&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MtDyuMHb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AWSvqzb2DlskuGHlrnIE8qw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MtDyuMHb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AWSvqzb2DlskuGHlrnIE8qw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When all is done, save the CI pipeline.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;  &lt;strong&gt;If you want to use YAML you can copy and paste this YAML file here:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pool:
  name: Azure Pipelines
steps:
- task: aloisdeniel.flutter.flutter-install.FlutterInstall@0
  displayName: 'Flutter Install'

- task: aloisdeniel.flutter.flutter-command.FlutterCommand@0
  displayName: 'Flutter Enable Web'
  inputs:
    arguments: 'config --enable-web'

- task: aloisdeniel.flutter.flutter-command.FlutterCommand@0
  displayName: 'Flutter Run Build Web'
  inputs:
    arguments: 'build web'

- task: CopyFiles@2
  displayName: 'Copy Files'
  inputs:
    SourceFolder: '$(Build.SourcesDirectory)/build/web'
    TargetFolder: '$(Build.ArtifactStagingDirectory)'

- task: PublishBuildArtifacts@1
  displayName: 'Publish Artifact: ci-artifact'
  inputs:
    ArtifactName: 'ci-artifact'

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Creating the CD pipeline
&lt;/h4&gt;

&lt;p&gt;The continuous deployment section will be used to push our builds directly to Netlify. This part is similar to most JAMStack apps such as React, Vue, Next, and Flutter Web. &lt;a href="https://codeburst.io/deploying-a-site-to-netlify-with-azure-devops-2743abb61db0"&gt;An article by Clyde D’Souza&lt;/a&gt; influenced this particular section. But of course, I modified it slightly because the project we’re using is a Flutter project.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eo0dRvTp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AOygcnF5mrnsRGgLFKBMisg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eo0dRvTp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AOygcnF5mrnsRGgLFKBMisg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open the releases pipeline, click on the Releases tab on the left side of the screen:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click the &lt;strong&gt;Pipelines&lt;/strong&gt; on the left side of the tab.&lt;/li&gt;
&lt;li&gt;Open &lt;strong&gt;Releases&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;New&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;New release pipeline&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Rnv9uXUg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2A9jXOfo-ozzfogunzdGCO_A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Rnv9uXUg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2A9jXOfo-ozzfogunzdGCO_A.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create an empty job.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oErekeq9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AH8SF23SAP0kioaI358_YTA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oErekeq9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AH8SF23SAP0kioaI358_YTA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Connect your CD pipeline with your CI pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add an artifact.&lt;/li&gt;
&lt;li&gt;Select your project.&lt;/li&gt;
&lt;li&gt;Choose your CI pipeline&lt;/li&gt;
&lt;li&gt;Add the pipeline.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MfLApIUr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2A4TAHp-48BRxcxNa7805bPQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MfLApIUr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2A4TAHp-48BRxcxNa7805bPQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enable the continuous deployment trigger to start after a successful build:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click the lightning logo to open the trigger page.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Enabled&lt;/strong&gt; button.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4BlKpW1o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AZnM9xtSoIvqoer3DITJUmw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4BlKpW1o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AZnM9xtSoIvqoer3DITJUmw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add a new task to the new CD pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open your &lt;strong&gt;Tasks&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;+&lt;/strong&gt; button.&lt;/li&gt;
&lt;li&gt;Search for &lt;strong&gt;Extract files&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Add the task to the pipeline.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uYjTegNe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AYuz4WMvTXt9tQm_4pj3MZQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uYjTegNe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AYuz4WMvTXt9tQm_4pj3MZQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Extract the artifacts according to the build Id.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pNS6gAL4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2Aw341jpMUhSmQmu0DVNk3SA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pNS6gAL4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2Aw341jpMUhSmQmu0DVNk3SA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add a new task to the new CD pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click the &lt;strong&gt;+&lt;/strong&gt; button.&lt;/li&gt;
&lt;li&gt;Search for &lt;strong&gt;Netlify&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Add the &lt;strong&gt;Install Netlify CLI&lt;/strong&gt; task to the pipeline.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GRPT_Ecj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AZ9Vq4cGKp6rd1U0YeKSbZQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GRPT_Ecj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AZ9Vq4cGKp6rd1U0YeKSbZQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add a new task to the new CD pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click the &lt;strong&gt;+&lt;/strong&gt; button.&lt;/li&gt;
&lt;li&gt;Search for &lt;strong&gt;Netlify&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Add the &lt;strong&gt;Deploy Website&lt;/strong&gt; task to the pipeline.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To connect our CD pipeline to our Netlify site, we need to have our access tokens and our site ID. We utilize pipeline variables to make it more accessible and provide secrecy to the token.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CUynfmXa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AtEpST9H8SwhfhWj8z-NsyQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CUynfmXa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AtEpST9H8SwhfhWj8z-NsyQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click the &lt;strong&gt;+ Add&lt;/strong&gt; button twice.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BA7cghUU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AHKk674mSac5xSASz-rfr2A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BA7cghUU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AHKk674mSac5xSASz-rfr2A.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will be shown with 4 input boxes. Put the name of the variable inside the left boxes and the values in the right. For convenience name the access token variable PAT, and name the other variable SiteID respectively.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--R29VBeoj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2A6Qamra986ORQOxI7nLyg8w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--R29VBeoj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2A6Qamra986ORQOxI7nLyg8w.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Change the deployment configuration:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Deploy to Netlify&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Insert your access token.&lt;/li&gt;
&lt;li&gt;Insert the Site ID.&lt;/li&gt;
&lt;li&gt;Select the build source directory.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Your CD pipeline should be finished, save the pipeline and try running it yourself! You can check the dummy site I deployed &lt;a href="https://miniature-flutter-milkstore.netlify.app/#/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;In this tutorial, you have learned how to Flutter web deployments using CI/CD and Azure DevOps. We then deployed the site on Netlify.&lt;/p&gt;

&lt;p&gt;To recap what we have done:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Installed the Flutter and Netlify dependencies.&lt;/li&gt;
&lt;li&gt;Created a blank site on Netlify.&lt;/li&gt;
&lt;li&gt;Retrieved the authorization token and site ID from Netlify.&lt;/li&gt;
&lt;li&gt;Prepared the CI/CD Pipelines.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You now have an open playbook to use when you want to automate deployments. In the next tutorial, we will be looking into how we can utilize &lt;a href="https://link.medium.com/mI4Cq5Y9Acb"&gt;Github Actions to make a CI/CD pipeline for Flutter Web and Netlify.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>azure</category>
      <category>devops</category>
    </item>
    <item>
      <title>Setting Up A Multinode RabbitMQ Cluster On Linux</title>
      <dc:creator>Agustinus Theodorus</dc:creator>
      <pubDate>Tue, 19 Jan 2021 17:51:10 +0000</pubDate>
      <link>https://dev.to/agustinustheo/setting-up-a-multinode-rabbitmq-cluster-on-linux-lhb</link>
      <guid>https://dev.to/agustinustheo/setting-up-a-multinode-rabbitmq-cluster-on-linux-lhb</guid>
      <description>&lt;p&gt;Installing RabbitMq on multiple remote servers can be a hassle. To connect multiple instances into one cluster we must first install RabbitMq on each remote server. These next two steps will walk through how we can install RabbitMq instances.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--an0bPji9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2AnoAgkXTihXU2PYuu" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--an0bPji9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2AnoAgkXTihXU2PYuu" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In this tutorial, we will be installing RabbitMq using a Centos 8 Linux distro. The RabbitMq version used in this tutorial is 3.8.9.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What is clustering for?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WgAu9z9F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2AhiLQ86ofVEj3P8Ke" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WgAu9z9F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2AhiLQ86ofVEj3P8Ke" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Well, clustering is used to combine multiple instances of RabbitMq into one giant central message queue. Clustering can be done on remote instances of RabbitMq on different servers. The purpose of the cluster is to handle massive amounts of message queues from apps, balancing the load on multiple servers rather than on a single server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add the required dependencies
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Install the required repositories
&lt;/h4&gt;

&lt;p&gt;Add the RabbitMq repository in the repo configurations file. Open the config file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo vi /etc/yum.repos.d/rabbitmq-server.repo

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

&lt;/div&gt;



&lt;p&gt;Add this to the lines below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[rabbitmq-server]  
name=rabbitmq-server  
baseurl=[https://packagecloud.io/rabbitmq/rabbitmq-server/el/7/$basearch](https://packagecloud.io/rabbitmq/rabbitmq-server/el/7/$basearch)  
repo_gpgcheck=1  
gpgcheck=0  
enabled=1  
gpgkey=[https://packagecloud.io/rabbitmq/rabbitmq-server/gpgkey](https://packagecloud.io/rabbitmq/rabbitmq-server/gpgkey)  
sslverify=1  
sslcacert=/etc/pki/tls/certs/ca-bundle.crt  
metadata_expire=300

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  Add Hostname to the &lt;code&gt;hosts&lt;/code&gt; file
&lt;/h4&gt;

&lt;p&gt;RabbitMq is built on top of Erlang. So it would make sense for us to install it beforehand. &lt;strong&gt;This part is very crucial as if you do not ad the hostname to&lt;/strong&gt; &lt;code&gt;/etc/hosts&lt;/code&gt; &lt;strong&gt;then&lt;/strong&gt; &lt;code&gt;rabbitmqctl status&lt;/code&gt; &lt;strong&gt;will not work.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo “127.0.0.1 $(hostname -s)” | sudo tee -a /etc/hosts

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting Up RabbitMq Server
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Install RabbitMq Server
&lt;/h4&gt;

&lt;p&gt;After completing the previous configuration setup steps, install RabbitMq by using this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo dnf install -y rabbitmq-server

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

&lt;/div&gt;



&lt;p&gt;After installation is completed, check if the installation is correct by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rpm -qi rabbitmq-server

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  Open Ports
&lt;/h4&gt;

&lt;p&gt;Centos has a pre-installed firewall called &lt;code&gt;firewalld&lt;/code&gt;. It blocks all ports from connecting unless asked to. So we must whitelist the TCP ports that are going to be used by RabbitMq.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo firewall-cmd --zone=public --permanent --add-port={5672,15672}/tcp  
sudo firewall-cmd --reload

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  Start the RabbitMq service
&lt;/h4&gt;

&lt;p&gt;The RabbitMq service doesn’t start on its own when you install it. You have to start it manually, then enable it to run on server startup. To start the RabbitMq service (the service might take a minute or two to start):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl start rabbitmq-server.service

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

&lt;/div&gt;



&lt;p&gt;To enable the service run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl enable rabbitmq-server.service

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

&lt;/div&gt;



&lt;p&gt;To check if the service is still running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo rabbitmqctl status

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  Enable RabbitMq Management
&lt;/h4&gt;

&lt;p&gt;If you want to enable the RabbitMq admin dashboard, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo rabbitmq-plugins enable rabbitmq_management

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

&lt;/div&gt;



&lt;p&gt;Then try to open the dashboard from the browser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://*your-server-ip*:15672

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setting Up RabbitMq Cluster
&lt;/h3&gt;

&lt;p&gt;After setting up RabbitMq on multiple servers (minimum of 2 servers) we now can continue to set up instances for the master and slave nodes. Choose one server as the master node as the cluster host, then use the other nodes as a slave cluster.&lt;/p&gt;

&lt;h4&gt;
  
  
  Setting Up The Master Node
&lt;/h4&gt;

&lt;p&gt;Whitelist the TCP port 4369 for &lt;code&gt;epmd&lt;/code&gt;, a helper discovery daemon used by RabbitMQ nodes and CLI tools, and port 25672 for instance finding.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo firewall-cmd —-zone=public —-permanent —-add-port={4369,25672}/tcp  
sudo firewall-cmd —-reload

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

&lt;/div&gt;



&lt;p&gt;Add the hosts for each cluster, in the &lt;code&gt;/etc/hosts&lt;/code&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo vi /etc/hosts

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

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;hosts&lt;/code&gt; file add the IP and hostname for each instance. The configuration would be as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node 1 IP node 1 hostname  
node 2 IP node 2 hostname  
node 3 IP node 3 hostname

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

&lt;/div&gt;



&lt;p&gt;The order doesn’t have to be master first, but it does need to have all cluster IPs and hostnames for it to work. An example configuration is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10.240.200.111 rabbitmq-1  
10.240.200.112 rabbitmq-2  
10.240.200.113 rabbitmq-3

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

&lt;/div&gt;



&lt;p&gt;Get the &lt;code&gt;.erlang.cookie&lt;/code&gt; from the master node&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo cat /var/lib/rabbitmq/.erlang.cookie

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

&lt;/div&gt;



&lt;p&gt;Save the token output in your notepad.&lt;/p&gt;

&lt;h4&gt;
  
  
  Setting Up The Slave Nodes
&lt;/h4&gt;

&lt;p&gt;Whitelist the TCP port 4369 for &lt;code&gt;epmd&lt;/code&gt; a helper discovery daemon used by RabbitMQ nodes and CLI tools, and port 25672 for instance finding.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo firewall-cmd —-zone=public —-permanent —-add-port={4369,25672}/tcp  
sudo firewall-cmd —-reload

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

&lt;/div&gt;



&lt;p&gt;Add the hosts for each cluster, in the &lt;code&gt;/etc/hosts&lt;/code&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo vi /etc/hosts

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

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;hosts&lt;/code&gt; file add the IP and hostname for each instance. The configuration would be as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node 1 IP node 1 hostname  
node 2 IP node 2 hostname  
node 3 IP node 3 hostname

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

&lt;/div&gt;



&lt;p&gt;The order doesn’t have to be master first, but it does need to have all cluster IPs and hostnames for it to work. An example configuration is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10.240.200.111 rabbitmq-1  
10.240.200.112 rabbitmq-2  
10.240.200.113 rabbitmq-3

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

&lt;/div&gt;



&lt;p&gt;Stop the &lt;code&gt;rabbitmq-server&lt;/code&gt; instance and replace the &lt;code&gt;.erlang.cookie&lt;/code&gt; inside the slave node with the masters.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo su  
systemctl stop rabbitmq-server  
echo -n “*erlang cookie from master node*” &amp;gt; /var/lib/rabbitmq/.erlang.cookie  
systemctl start rabbitmq-server

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Repeat this setup on all the nodes!&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Join The Slave Nodes With The Master Node
&lt;/h3&gt;

&lt;p&gt;Stop the &lt;code&gt;rabbitmq-server&lt;/code&gt; instance, reset the node and join it with the master node.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo rabbitmqctl stop_app  
sudo rabbitmqctl reset  
sudo rabbitmqctl join_cluster rabbit@*master node hostname*  
sudo rabbitmqctl start_app

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Reset The Master Node
&lt;/h3&gt;

&lt;p&gt;Reset the &lt;code&gt;rabbitmq-server&lt;/code&gt; in the master node.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo rabbitmqctl stop_app  
sudo rabbitmqctl reset  
sudo rabbitmqctl start_app

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check The Cluster Status
&lt;/h3&gt;

&lt;p&gt;To check the cluster status, run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo rabbitmqctl cluster_status

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In the end, when we have finished installation, login to the RabbitMq management dashboard for one of the nodes and it would have more than one cluster like so:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aA4WUy0L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2AVx0rb7MN4gugsctF" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aA4WUy0L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2AVx0rb7MN4gugsctF" alt=""&gt;&lt;/a&gt;undefined&lt;/p&gt;

&lt;p&gt;Of course, there are advantages in using manual installs for RabbitMq. The pros would be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can save space on each server by only installing RabbitMq and nothing else.&lt;/li&gt;
&lt;li&gt;Particularly on VMs, you can use Ansible to speed up the installation process by doing the repeatable tasks from a single command line.&lt;/li&gt;
&lt;li&gt;You understand thoroughly the process of building a RabbitMq instance from the ground up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then the cons would be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Managing the firewalls for each server can be complicated.&lt;/li&gt;
&lt;li&gt;It is faster for us to use Docker during container set up for each server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But if you want to read more on this topic, and read some of the references I had when making this tutorial you can check out these links below:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.rabbitmq.com/clustering.html"&gt;Official RabbitMQ Clustering Guide&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.osradar.com/how-to-install-rabbitmq-on-rhel-8-centos-8/"&gt;How to Install RabbitMQ on RHEL 8 / CentOS 8 — Linux Windows and android Tutorials (osradar.com)&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;[How to config rabbitmq server cluster &lt;a href="//github.com"&gt;3 nodes&lt;/a&gt;](&lt;a href="https://gist.github.com/pobsuwan/22aa4a9e0a217d22e12800a432933881"&gt;https://gist.github.com/pobsuwan/22aa4a9e0a217d22e12800a432933881&lt;/a&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now we have an open playbook for you to use the next time you want to setup RabbitMq on your systems manually.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>linux</category>
      <category>pubsub</category>
      <category>rabbitmq</category>
    </item>
    <item>
      <title>The Microservice Architecture Perspective</title>
      <dc:creator>Agustinus Theodorus</dc:creator>
      <pubDate>Thu, 31 Dec 2020 16:51:07 +0000</pubDate>
      <link>https://dev.to/agustinustheo/the-microservice-architecture-perspective-3a29</link>
      <guid>https://dev.to/agustinustheo/the-microservice-architecture-perspective-3a29</guid>
      <description>&lt;p&gt;Making software that serves more than a couple of thousand users can be hard. The difficulty is not in making the app itself but in how we make the app reliable. Microservices is a solution to messy problems like these. Instead of relying on one large server, we use a bunch of small ones to solve our problem. To elaborate on this subject further here are a few perspectives I have on the microservices architecture.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9ZpDJiZd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2AVzeqoAS5yZrIpeZQ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9ZpDJiZd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2AVzeqoAS5yZrIpeZQ" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  One Down, Many More To Go
&lt;/h3&gt;

&lt;p&gt;In my honest opinion, one of the reasons I go with a microservice is the reliability factor. With multiple servers, this can be the case. We add reliability to the service by adding more of them. This technique is called &lt;a href="https://www.citrix.com/en-id/glossary/load-balancing.html#:~:text=Load%20balancing%20is%20defined%20as,server%20capable%20of%20fulfilling%20them."&gt;load balancing.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CuSfVsM9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2AtrVIG9l2V7inAkov.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CuSfVsM9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2AtrVIG9l2V7inAkov.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead of burdening all the traffic to one server, you can balance it to multiple servers. So it can be nearly impossible to down the service. The best part of this is that you don’t need to have expensive high throughput servers to make this happen. For example, you can host your server on a few &lt;a href="https://www.digitalocean.com/products/droplets/"&gt;digital ocean droplets&lt;/a&gt;, instead of one large one.&lt;/p&gt;

&lt;p&gt;Though load balancing alone cannot determine a microservice, there are other characteristics that would need to be fulfilled. This is but only one of the advantages of the microservice pattern.&lt;/p&gt;

&lt;p&gt;If you are using a monolith pattern logically you can still use load balancing, the only downside would be that you would need multiple high throughput servers to serve your app. Multiplying the cost.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pay For What You Need
&lt;/h3&gt;

&lt;p&gt;Before I start, let me say. This section is debatable. I am explaining this from my point of view and my previous experiences. Because when your entire service is determined by small services, it can be easy to cut costs. We can buy only the things that we need.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_Ck5wh3X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2ArTd5CdXZV626QTVDZuK_EA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_Ck5wh3X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2ArTd5CdXZV626QTVDZuK_EA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For explanation purposes let’s say a 1 GB droplet can handle about 1k users. So to handle 5k users you probably would need to use the 8GB droplet for the price of $40 a month.&lt;/p&gt;

&lt;p&gt;Instead, you can use 3 droplets. Two 1 GB droplets and one 4 GB droplet for $30 a month. We buy two 1 GB droplets so we can use one for the service and use the other one for load balancing. With this scheme, you saved $10 a month.&lt;/p&gt;

&lt;p&gt;This is a very simple example. A better one would be when we have separate microservices that connect to each other, we can tune the prices to our exact use of computing power.&lt;/p&gt;

&lt;p&gt;For example, the donuts API may have more load than the coffee API. We can then scale up the donuts API server to be able to handle those requests. Being able to specify upgrades by service can help reduce costs tremendously.&lt;/p&gt;

&lt;h3&gt;
  
  
  Separate Your Interests
&lt;/h3&gt;

&lt;p&gt;Monoliths have this habit of merging all services together, related or not. This causes a problem when one of the services goes down, it will take the entire app down with it. If you value reliability, you wouldn’t want that.&lt;/p&gt;

&lt;p&gt;Using the microservice architecture each service can be separated, making it independent of one another. This type of API development is called domain driven development or DDD. It is a very interesting way of designing systems small that can scale big. &lt;a href="https://www.confluent.io/blog/microservices-apache-kafka-domain-driven-design/#:~:text=Microservices%20have%20a%20symbiotic%20relationship,that%20makes%20the%20system%20work."&gt;You can read more about DDD here&lt;/a&gt;. Reading more into this topic might lead you to cool system design patterns like &lt;a href="https://microservices.io/patterns/data/cqrs.html"&gt;CQRS&lt;/a&gt;, &lt;a href="https://microservices.io/patterns/data/database-per-service.html"&gt;Database per service&lt;/a&gt;, and &lt;a href="https://microservices.io/patterns/data/api-composition.html"&gt;API Composition&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PgRny_Ep--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AkKsAICXGDY_KbwOpgxSaBQ.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PgRny_Ep--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AkKsAICXGDY_KbwOpgxSaBQ.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The picture above explains my point perfectly. Connections from the client would be made to a gateway/edge API. The edge API would then connect to the multiple microservices available for each specific request. With the corresponding databases behind each specific API.&lt;/p&gt;

&lt;p&gt;Say, the user wants some books, of course, the data would be retrieved from the books API. After seeing the catalog of books, the user made up their mind and wishes to check out. The user is then connected to the check out API. Notice that all the services are independent of each other it does not coincide with one another other than the edge API. It adds reliability to the app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scale More!
&lt;/h3&gt;

&lt;p&gt;Why does this section have an exclamation mark? Because this is the main gist of using microservices. It is the best feature anyone could have asked for. Put reliability and scalability together and what do you have? A great user experience.&lt;/p&gt;

&lt;p&gt;Not all companies might need the blessing of microservices but for those that do it really does make a huge difference. All the sections before this one support this. Separable domains, cost-effectiveness, and reliability.&lt;/p&gt;

&lt;p&gt;But you do not need to scale everything. When you are building a team of services using microservices will help you in the long run, but when you are making an MVP or some other small apps you would not need to implement microservices at all. It might even slow you down!&lt;/p&gt;

&lt;p&gt;Microservices is not the grand bullet for everything, even though it has both reliability and scalability to its name. It has good things to offer for select cases, not for everyone.&lt;/p&gt;

&lt;h3&gt;
  
  
  Small and Compact
&lt;/h3&gt;

&lt;p&gt;Microservices like the name entails are very small apps that communicate with each other. With specificity in mind, teams can deploy new services quickly without breaking another.&lt;/p&gt;

&lt;p&gt;This coincides perfectly with agile teams that want to reach a certain target. Deployments are easy because it allows for easy and straightforward testing. You only need to test the things that you deploy, there is no need to test the other services along with it.&lt;/p&gt;

&lt;p&gt;Almost all the articles I’ve read about microservices applaud the ease of deployments this architecture has to offer. Though that’s not all the benefits of being small and compact.&lt;/p&gt;

&lt;p&gt;Maintainability wise, it will be much easier than monoliths. The functions are simple because the folders aren’t merged into one project. Honestly from my own experience handling a monolith, traversing the folders was very difficult. Filenames can sometimes be similar in a way that I confuse which service is which.&lt;/p&gt;

&lt;p&gt;Sure, people can say that a confusing monolith project reeks of bad code management. When you have more than 100 features in a project it does tend to get a little messy. Add to the number of teams responsible for different features contributing to the &lt;strong&gt;same codebase&lt;/strong&gt; 🤯.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I can only imagine the number of branches that repo has…&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  More Autonomy and Faster Development Speeds
&lt;/h3&gt;

&lt;p&gt;With microservice, this doesn’t have to be. Microservice brings more autonomy to the team. Working together between teams is not easy. We have our own schedules that we need to attend. But when we use the microservices concept, the pain of inter-team management becomes invisible.&lt;/p&gt;

&lt;p&gt;All you need would be a coding standard, and you would be good to go. Though more autonomy, coupled with faster development could lead to trouble &lt;strong&gt;if you don’t have good documentation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let me make this clear, working autonomously is great and all. But in the end, you still need to communicate. What better way to miscommunicate other than having no documentation. Believe me, I have experienced these kinds of things first hand. Microservices does not solve problems like these.&lt;/p&gt;

&lt;p&gt;With more autonomy teams can be more business-oriented with their goals, timelines become much shorter and development can focus more on new features.&lt;/p&gt;

&lt;h3&gt;
  
  
  With Great Power Comes Great Documentation
&lt;/h3&gt;

&lt;p&gt;Elaborating from the previous section, a good analogy for microservices would be “With great power comes great responsibility”. I am not kidding, when you have tons of services you would &lt;strong&gt;wish&lt;/strong&gt;  &lt;strong&gt;for good documentation&lt;/strong&gt;. For a good perspective here is an illustration of the Netflix microservice backend.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mQEkaKUl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2Ad9cZNb3AX_fOgC-y.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mQEkaKUl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2Ad9cZNb3AX_fOgC-y.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now imagine, how much of that would you remember. The answer is none. That’s why documentation is important. Probably using Netflix as an example is a huge exaggeration — &lt;em&gt;but hey it gets the point across.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now I know — &lt;em&gt;every application needs documentation&lt;/em&gt;. That’s true but it becomes double for microservices. There are benefits to good documentation though. The better documented the microservice is, the reusable probability of each service will be increased. This brings us to the next point.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reusability
&lt;/h3&gt;

&lt;p&gt;What I love about writing code is how much less of it I have to write. Get what I am saying? Reusable components, reusable APIs, reusable &lt;em&gt;everything&lt;/em&gt;! I would integrate every one of my apps into one large system, and if I can reuse some parts of it for another app I would do it without notice.&lt;/p&gt;

&lt;p&gt;The part that I like about microservices is that it’s very portable, I mean one service can be accessed by many. That’s why I usually try to make microservices as general as I can make it — &lt;em&gt;doesn’t mean that I won’t make it specific when I need to&lt;/em&gt;. It just comes as a natural thing to do to reuse things you made.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;To summarize microservice architectures are usually used to help increase the reliability of a system. The benefits of using a microservice architecture are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Made to be reliable.&lt;/li&gt;
&lt;li&gt;Pay for what you need.&lt;/li&gt;
&lt;li&gt;Write separate applications for each domain.&lt;/li&gt;
&lt;li&gt;Have a nature to scale.&lt;/li&gt;
&lt;li&gt;Small and compact.&lt;/li&gt;
&lt;li&gt;Separated development for teams that wants to move fast.&lt;/li&gt;
&lt;li&gt;Reusability factor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Though the microservice architecture does come with its faults. The disadvantages of using a microservice are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;With great power, comes great documentation.&lt;/li&gt;
&lt;li&gt;Small companies with few teams are not suitable for this architecture.&lt;/li&gt;
&lt;li&gt;Does not fit every business model (e.g monoliths are better for MVPs).&lt;/li&gt;
&lt;li&gt;Because it has a nature to scale, it can become bloated if not checked. We can’t all be like Netflix.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This was my perspective regarding microservices. I hope it was clear enough of an explanation.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>webdev</category>
      <category>microservices</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Automating Flutter Web Deployments to Netlify Using GitHub Actions</title>
      <dc:creator>Agustinus Theodorus</dc:creator>
      <pubDate>Mon, 28 Dec 2020 16:18:18 +0000</pubDate>
      <link>https://dev.to/agustinustheo/automating-flutter-web-deployments-to-netlify-using-github-actions-2g71</link>
      <guid>https://dev.to/agustinustheo/automating-flutter-web-deployments-to-netlify-using-github-actions-2g71</guid>
      <description>&lt;p&gt;Lately, there has been a lot of fuss over Flutter. Some people call it the future, while some say it’s overrated. But I think it’s a good framework to learn nonetheless. The sheer amount of things that can be done with Flutter is unbelievable, including Android, iOS, desktop, and web programming.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6qy-iplo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/700/0%2ArjDmgSKL-lNurUpp" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6qy-iplo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/700/0%2ArjDmgSKL-lNurUpp" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here in this tutorial, I’m going to share how to implement your Flutter web deployments using GitHub Actions. Also, we’re going to use Netlify. Why Netlify? Because, honestly, Netlify is very easy to use. Now, without further ado, let’s get to it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating Your Netlify Site
&lt;/h3&gt;

&lt;p&gt;This section will discuss how you can create an empty Netlify site using the Netlify CLI. We’ll be using npm to install it for us. In my case, I use Ubuntu 18.04 as the host OS for the npm installation.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Install the Netlify CLI
&lt;/h4&gt;

&lt;p&gt;To install the Netlify CLI, you just need to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install netlify-cli -g

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

&lt;/div&gt;



&lt;p&gt;After the installation is complete, check if it’s installed correctly by running this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;netlify

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Log in to Netlify from the CLI
&lt;/h4&gt;

&lt;p&gt;Before you can start using the CLI, Netlify needs you to authenticate yourself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;netlify login

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

&lt;/div&gt;



&lt;p&gt;Then a browser window will open:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lIfNSHJU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/700/0%2A4FnW4DUyG4w5_kPC.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lIfNSHJU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/700/0%2A4FnW4DUyG4w5_kPC.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Creating a blank site
&lt;/h4&gt;

&lt;p&gt;After finishing your login, create a blank site using this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;netlify sites:create --name _&amp;lt;site name&amp;gt;_

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  4. Retrieving your Site ID and personal access token
&lt;/h4&gt;

&lt;p&gt;To run continuous development remotely, you need both your site ID and your personal access token to help you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--u4LM6qww--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/700/1%2APxWjk8axlVeVwmUt33_gQw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--u4LM6qww--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/700/1%2APxWjk8axlVeVwmUt33_gQw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Retrieve your site ID by:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Going into the site settings.&lt;/li&gt;
&lt;li&gt;Copy the API ID value.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The next step would be to retrieve the personal access token.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--e7bNlRUY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/328/1%2Atbk9PgZpJudHMFp6kUvdvg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--e7bNlRUY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/328/1%2Atbk9PgZpJudHMFp6kUvdvg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go to the user settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j3h1RJvD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/700/1%2AAKe8XmKjoeIzeCfples1MA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j3h1RJvD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/700/1%2AAKe8XmKjoeIzeCfples1MA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To get an access token, you have to make a new one:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the Applications tab.&lt;/li&gt;
&lt;li&gt;Click “New access token.”&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Copy and save the access token shown on the next screen, and save it because you’ll need it later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set Repository Secrets
&lt;/h3&gt;

&lt;p&gt;After we’ve retrieved the access tokens and site ID, we’ll save them inside the repository secret.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Why do we need to use repository secrets? To prevent sensitive IDs or tokens from being pushed to the repository.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Zq7GHhvz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/700/1%2AZmJUTolPTUB9jV4wEESG1g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Zq7GHhvz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/700/1%2AZmJUTolPTUB9jV4wEESG1g.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To create a secret:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the repository settings.&lt;/li&gt;
&lt;li&gt;Click Secrets on the left-side tab.&lt;/li&gt;
&lt;li&gt;Click “New repository secret.”&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IjufvoZB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/700/1%2Aq7bhT-rvvr43-Ica5V5qeg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IjufvoZB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/700/1%2Aq7bhT-rvvr43-Ica5V5qeg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the “New secret” page input the secret name and value. When finished, click the “Add secret” button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_O3tYAwt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/700/1%2AwsVX08jtCaYK8_qixHKKiw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_O3tYAwt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/700/1%2AwsVX08jtCaYK8_qixHKKiw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In its entirety, we’ve added about three secrets: the GitHub personal access token, the Netlify personal access token, and the Netlify site ID.&lt;/p&gt;

&lt;h3&gt;
  
  
  Retrieving the GitHub Access Token
&lt;/h3&gt;

&lt;p&gt;Because we’re going to automate deployments using GitHub Actions, a personal access token would be required. You’d need to open your &lt;a href="https://github.com/settings/tokens"&gt;GitHub Developer Settings here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1wwnCEQk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/700/1%2AFIAEH_LGk_2ExSWE0hKyAw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1wwnCEQk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/700/1%2AFIAEH_LGk_2ExSWE0hKyAw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After opening your developer settings page:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the personal access tokens page.&lt;/li&gt;
&lt;li&gt;Generate a new token for GitHub Actions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5vt90kh7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/700/1%2A2TbMqTdUDUbTJ7pwaz2p8A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5vt90kh7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/700/1%2A2TbMqTdUDUbTJ7pwaz2p8A.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next steps would be:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Input a name for your token.&lt;/li&gt;
&lt;li&gt;Check the workflow to give access to GitHub Actions.&lt;/li&gt;
&lt;li&gt;Scroll to the bottom of the page.&lt;/li&gt;
&lt;li&gt;Click the “Generate token” button.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AXL2jO3b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/700/1%2AiL5anhz6IvIigtRGPfiF7A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AXL2jO3b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/700/1%2AiL5anhz6IvIigtRGPfiF7A.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Copy the access token and save it somewhere because it’ll be used later on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the CI/CD Workflow
&lt;/h3&gt;

&lt;p&gt;CI/CD using GitHub Actions is fairly simple. It requires us to make a YAML file. This YAML file is called a &lt;em&gt;workflow&lt;/em&gt; in GitHub Actions because it defines the steps needed to form a CI/CD.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Flutter-CI
on:
  push:
    branches: [master]
  pull_request:
    branches: [master]
  workflow_dispatch:

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

&lt;/div&gt;



&lt;p&gt;To start our workflow, we must enable builds to start after push/pull requests to the master branch, assuming all deployments would be from the master.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - uses: subosito/flutter-action@v1
      with:
        channel: beta
    - run: flutter config --enable-web
    - run: flutter build web

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

&lt;/div&gt;



&lt;p&gt;For the Flutter building process, I used an action made by subosito. You can check the &lt;a href="https://github.com/marketplace/actions/flutter-action"&gt;Flutter Actions detail here&lt;/a&gt;. For Flutter web, we first have to initialize the configurations to enable web builds. Thus, we ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flutter config --enable-web

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

&lt;/div&gt;



&lt;p&gt;Then if you want to add tests to the workflow, you can by adding the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flutter test

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

&lt;/div&gt;



&lt;p&gt;Finally, build the app using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flutter build web

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

&lt;/div&gt;



&lt;p&gt;The results of the build will be in the &lt;code&gt;build/web&lt;/code&gt; folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    - name: Deploy to Netlify
      uses: nwtgck/actions-netlify@v1.1
      with:
        publish-dir: './build/web'
        production-branch: master
        github-token: $
        deploy-message: "Deploy from GitHub Actions"
        enable-pull-request-comment: false
        enable-commit-comment: true
        overwrites-pull-request-comment: true
      env:
        NETLIFY_AUTH_TOKEN: $
        NETLIFY_SITE_ID: $
      timeout-minutes: 1

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

&lt;/div&gt;



&lt;p&gt;After a successful build, deploy the files to Netlify manually. Here’s a snippet I used by nwtgck. I changed a few variables to be able to publish Flutter apps, but you can check &lt;a href="https://github.com/marketplace/actions/netlify-actions"&gt;Netlify Actions here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this last workflow, you’ll access the secrets we previously stored on our repository settings. The entire workflow can be copied from this gist below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: CI

on:
  push:
    branches: [master]
  pull_request:
    branches: [master]
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - uses: subosito/flutter-action@v1
      with:
        channel: beta
    - run: flutter config --enable-web
    - run: flutter build web

    - name: Deploy to Netlify
      uses: nwtgck/actions-netlify@v1.1
      with:
        publish-dir: './build/web'
        production-branch: master
        github-token: $
        deploy-message: "Deploy from GitHub Actions"
        enable-pull-request-comment: false
        enable-commit-comment: true
        overwrites-pull-request-comment: true
      env:
        NETLIFY_AUTH_TOKEN: $
        NETLIFY_SITE_ID: $
      timeout-minutes: 1

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

&lt;/div&gt;



&lt;p&gt;Your CI/CD workflow should be finished. Save the workflow inside &lt;code&gt;.github/workflows&lt;/code&gt;, and try running it yourself! You can check the dummy site I deployed &lt;a href="https://miniature-flutter-milkstore.netlify.app/#/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;We’ve successfully created a CI/CD pipeline for Flutter web using Github Actions. To summarize our steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a blank Netlify site.&lt;/li&gt;
&lt;li&gt;Retrieve the personal access token from Netlify and the site ID.&lt;/li&gt;
&lt;li&gt;Retrieve the personal access token from GitHub.&lt;/li&gt;
&lt;li&gt;Set the secrets inside the repository settings.&lt;/li&gt;
&lt;li&gt;Create a GitHub Action YAML file inside &lt;code&gt;.github/workflows&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Voila! We’ve finished our tutorial. Now you have an open playbook to deploy your future Flutter web apps using GitHub Actions.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>linux</category>
      <category>dart</category>
      <category>devops</category>
    </item>
    <item>
      <title>Automate Your Linux Deployment Using Azure DevOps</title>
      <dc:creator>Agustinus Theodorus</dc:creator>
      <pubDate>Thu, 10 Dec 2020 12:49:28 +0000</pubDate>
      <link>https://dev.to/agustinustheo/automate-your-linux-deployment-using-azure-devops-36i3</link>
      <guid>https://dev.to/agustinustheo/automate-your-linux-deployment-using-azure-devops-36i3</guid>
      <description>&lt;p&gt;Feel like you have been logging into your Linux servers too much lately? Good, this might be the right article for you. In teams, either large or small manual deployments can be tedious. But they are also predictable. Deployment steps don’t really change that often unless you have a breaking change or you are implementing a major feature.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AzCSfGwYvrx7hc3DY" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AzCSfGwYvrx7hc3DY"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;So, why don’t you just automate it? You don’t need to do it yourself. Do important things like &lt;strong&gt;writing code&lt;/strong&gt; and let a machine do the deployments for you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If your team is blessed to use Azure DevOps here is a tutorial to finally automate &lt;strong&gt;&lt;em&gt;the hell&lt;/em&gt;&lt;/strong&gt; out of your deployments. You &lt;em&gt;seldom&lt;/em&gt; have to log on to your Linux servers again.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In this tutorial, we will be making an automated pipeline to deploy .NET Core applications to a Centos 8 server. The app will be run as a service and we will serve those services through a reverse proxy using NGINX.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing Azure Agent on Linux
&lt;/h3&gt;

&lt;p&gt;In Azure DevOps, we use an agent to interact with our builds in the pipeline. Installing agents are straightforward, just follow these steps:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Setting Up A Deployment Group in Azure DevOps
&lt;/h4&gt;

&lt;p&gt;Deployment groups are the list of agents already installed on your servers. You would need to make a deployment group for each server.&lt;/p&gt;

&lt;p&gt;First, open your &lt;strong&gt;Azure DevOps&lt;/strong&gt; dashboard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AdiKrTk5BKavbs076x6AqNQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AdiKrTk5BKavbs076x6AqNQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, open your &lt;strong&gt;Pipelines&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2ARQiW01F5omxuvnAV" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2ARQiW01F5omxuvnAV"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go to &lt;strong&gt;Deployment Groups&lt;/strong&gt; , and click &lt;strong&gt;New&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AwFxLJNCYSxD9PhN4" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AwFxLJNCYSxD9PhN4"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give your Linux VM an Alias, and the description. Then click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AdC9GLQyFwPz4sVprOJ4l-g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AdC9GLQyFwPz4sVprOJ4l-g.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You have created a deployment group, now to install this deployment groups agent on your Linux server:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Change the target from Windows to &lt;strong&gt;Linux&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Check the &lt;strong&gt;Use a personal access token&lt;/strong&gt; checkbox.&lt;/li&gt;
&lt;li&gt;Save the script on a notepad for the next step.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  2. Installing the Agent on the Linux Server
&lt;/h4&gt;

&lt;p&gt;To install the agent, run the script copied from the previous step &lt;strong&gt;in the home directory&lt;/strong&gt; , make sure you &lt;strong&gt;run the script with a user that has sudo enabled&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;After installation is finished run go into the &lt;strong&gt;azagent&lt;/strong&gt; directory and check the installation by trying to run the agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd azagent  
./run.sh

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

&lt;/div&gt;



&lt;p&gt;If the agent returns a &lt;strong&gt;&lt;em&gt;Listening for Jobs&lt;/em&gt;&lt;/strong&gt; message, that means the installation was successful. The next step is to make a service that can run the agent in the background.&lt;/p&gt;

&lt;p&gt;To start to install the agent as a service, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo ./svc.sh install

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

&lt;/div&gt;



&lt;p&gt;This will install the service, and then run it in the background. To stop the service run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo ./svc.sh stop

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

&lt;/div&gt;



&lt;p&gt;Otherwise, if we want to start an installed service, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo ./svc.sh start

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

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AvkJRjhEYQVPeemFc" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AvkJRjhEYQVPeemFc"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check if the service is running by opening the Deployment Groups tab in Azure DevOps. If it is &lt;strong&gt;Online&lt;/strong&gt; then your agent installation is successful and it is available for jobs.&lt;/p&gt;

&lt;p&gt;This short installation guide was based on an article by &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/v2-linux?view=azure-devops" rel="noopener noreferrer"&gt;Microsoft&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure your Linux server for automation
&lt;/h3&gt;

&lt;p&gt;Now, this would be the fun part. Microsoft already did all the heavy lifting with the boring installation things. Now it is our turn to automate things.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Make a script to automate NGINX configurations
&lt;/h4&gt;

&lt;p&gt;To add new NGINX configurations we will create a shell script, add this &lt;em&gt;add-nginx-conf.sh&lt;/em&gt; script on the home directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash
conf_path="/etc/nginx/conf.d/$1.conf"

if [-f "$conf_path"]
then
    conf_text=`cat $conf_path`
    if [["$conf_text" == *"$2"*]] || [["$conf_text" == *"localhost:$3"*]]
    then
        echo "Proxy route or localhost port has been used, please manually reconfigure your Nginx configuration."
    else
        word="\n\n\tlocation \/$2\/ {\
\n\t\tproxy_pass http:\/\/localhost:$3\/;\
\n\t}"
        match="# Insert here"
        echo "$conf_text" | sed "s/$match/&amp;amp;$word/g" &amp;gt; "$conf_path"
    fi

    nginx -t
    systemctl reload nginx
else
    conf_text="server {
    listen 80;
    listen [::]:80;
    server_name $1;

    # Load configuration files for the default server block.
    include /etc/nginx/default.d/*.conf;

    # Insert here

    location /$2/ {
        proxy_pass http://localhost:$3/;
    }

    error_page 404 /404.html;
        location = /40x.html {
    }

    error_page 500 502 503 504 /50x.html;
        location = /50x.html {
    }
}"

    echo "$conf_text" &amp;gt; "$conf_path"

    chcon unconfined_u:object_r:httpd_config_t:s0 "$conf_path"
    chown root:root "$conf_path"

    nginx -t
    systemctl reload nginx
fi

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

&lt;/div&gt;



&lt;p&gt;This script will create a search for configuration files named using the associated DNS, it will create a new one if it was not found. Once found, the new configuration routes will be added there. Mind you, the configuration route in this script would be a basic proxy pass, you might want to add more configurations to the script if you want to use it for production.&lt;/p&gt;

&lt;p&gt;The shell script accepts three parameters. The DNS, proxy route, and the port being used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo ~/add-nginx-conf.sh &amp;lt;DNS&amp;gt; &amp;lt;proxy route&amp;gt; &amp;lt;app port&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo ~/add-nginx-conf.sh yourdomain.com enrichment_track 14321

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

&lt;/div&gt;



&lt;p&gt;In this example, the script will add configurations for the yourdomain.com domain, with a reverse proxy to port 14321 in the enrichment_track.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Make a script to automate system service configurations
&lt;/h4&gt;

&lt;p&gt;To add new system service configurations we will create a shell script, add this &lt;em&gt;make-service.sh&lt;/em&gt; script on the home directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash
file_path=`pwd`
service_path="/etc/systemd/system/$1.service"
if [-f "$service_path"]
then
    echo "Service file already exists"
else
    touch "$service_path"
    service_contents="[Unit]
Description=.NET Web API for $1

[Service]
WorkingDirectory=$file_path/_$1/drop/s
ExecStart=/usr/bin/dotnet $file_path/_$1/drop/s/$2.dll
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=dotnet-example
User=&amp;lt;user&amp;gt;
Environment=ASPNETCORE_ENVIRONMENT=&amp;lt;server environment&amp;gt;
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false

[Install]
WantedBy=multi-user.target"
    echo "$service_contents" &amp;gt;&amp;gt; "$service_path"
    systemctl start $1.service
    systemctl enable $1.service
fi

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Before you copy and paste the code, notice the &lt;code&gt;&amp;lt;user&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;server environment&amp;gt;&lt;/code&gt; tags in the script. Please change it to your corresponding user and server environment beforehand. Server environments in this case would be either Development or Production.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The script will generate new systemd service files that would run .NET Core projects. To generate scripts for other types of applications you would want to change the given template.&lt;/p&gt;

&lt;p&gt;The shell script accepts two parameters. The service name, and the project name used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo ~/make-service.sh &amp;lt;service name&amp;gt; &amp;lt;project name&amp;gt;

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

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo ~/make-service.sh CI-Build API-Project

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

&lt;/div&gt;



&lt;p&gt;In this example, the script will add a new system service file &lt;em&gt;CI-Build.service&lt;/em&gt;, that runs a dll file named &lt;em&gt;API-Project.dll&lt;/em&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Setup a user to run systemctl and Nginx commands without password prompts
&lt;/h4&gt;

&lt;p&gt;For automation purposes, the user that you used to install your Azure Agent needs to be able to run systemctl and Nginx commands without a password prompt. To remove the password prompts on sudo run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo visudo

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

&lt;/div&gt;



&lt;p&gt;We need to run all the commands in the script using sudo without having a password being prompted. So, we make exceptions for those commands, and the corresponding scripts we are going to use.&lt;/p&gt;

&lt;p&gt;Then add this on the last line &lt;em&gt;(change the &lt;code&gt;&amp;lt;user&amp;gt;&lt;/code&gt; tag beforehand)&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;user&amp;gt; ALL=(ALL) NOPASSWD:/usr/bin/systemctl, /usr/sbin/nginx, /usr/bin/chcon, /usr/bin/chown, /usr/bin/echo, /usr/bin/touch, /usr/bin/sed, /home/&amp;lt;user&amp;gt;/make-service.sh, /home/&amp;lt;user&amp;gt;/add-nginx-conf.sh

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

&lt;/div&gt;



&lt;p&gt;Exit and save the config file, then try running one of these commands using sudo. You should not be prompted for a password.&lt;/p&gt;

&lt;p&gt;A full explanation on how to run a sudo command without a password can be seen &lt;a href="https://www.cyberciti.biz/faq/linux-unix-running-sudo-command-without-a-password/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prepare the Pipelines
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Prepare the CI Pipeline
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AfRlXDaaNIGDMUXlx8ER1gg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AfRlXDaaNIGDMUXlx8ER1gg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this tutorial, we are going to use a .NET Core app as our example.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, go to the Pipelines tab.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;New Pipeline&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AlwYKW8-orAtqp1xr" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AlwYKW8-orAtqp1xr"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use the classic editor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2Aw9fgiTigSL8dU4Pu" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2Aw9fgiTigSL8dU4Pu"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose a repository and click &lt;strong&gt;Continue&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2Aj8MZijq5kfQ3gFyo" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2Aj8MZijq5kfQ3gFyo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Apply the .NET Core template.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Search for &lt;strong&gt;“.NET Core”&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Then apply the template&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AaJDSwZlIsa-uVRjl" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AaJDSwZlIsa-uVRjl"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because we are deploying a very small example app, I didn’t prepare any tests so:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click the Test task.&lt;/li&gt;
&lt;li&gt;Remove the task.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Otherwise, if you are using tests, then don’t remove this task.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2Ai2vTHkZzgc3RK2Op" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2Ai2vTHkZzgc3RK2Op"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, this is what you are left with. In the next step, we will implement Continuous Development in our solution.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Change the name of your CI pipeline.&lt;/li&gt;
&lt;li&gt;Save the Pipeline.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Prepare the CD Pipeline
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2Aj4Oyuueu6v8jcAa-" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2Aj4Oyuueu6v8jcAa-"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To add a new Continuous Development pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to the &lt;strong&gt;Releases&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;New&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Then click &lt;strong&gt;New release pipeline&lt;/strong&gt; to create a new pipeline.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2APksyAUqhU2tdHkTW" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2APksyAUqhU2tdHkTW"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After clicking the &lt;strong&gt;New release pipeline&lt;/strong&gt; button a pop-up will appear, then select &lt;strong&gt;Empty Job&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AB8Sh7jl3MZJ4qtF1" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AB8Sh7jl3MZJ4qtF1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To connect to a CI pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Add a new artifact&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Choose the project that contains the CI pipeline.&lt;/li&gt;
&lt;li&gt;Choose the CI pipeline.&lt;/li&gt;
&lt;li&gt;Give an alias to your artifact.&lt;/li&gt;
&lt;li&gt;When all is done click &lt;strong&gt;Add&lt;/strong&gt; to finish the configuration.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2A38Fjnw3zUuPhvji9" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2A38Fjnw3zUuPhvji9"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then for the Continuous Deployment pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click the thunderbolt icon.&lt;/li&gt;
&lt;li&gt;Then check the &lt;strong&gt;Enabled&lt;/strong&gt; button.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2A0iqhBSovBPD7xVpL" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2A0iqhBSovBPD7xVpL"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After creating a stage, on &lt;strong&gt;stages&lt;/strong&gt; , double click on tasks to go to the &lt;strong&gt;Tasks&lt;/strong&gt; section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AojZ6-NrtHwo0Aeie" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AojZ6-NrtHwo0Aeie"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the tasks section, make a deployment group job.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click the three dots to show options.&lt;/li&gt;
&lt;li&gt;Add a deployment group job.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AFyUB5L1Iei_pTuQN" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AFyUB5L1Iei_pTuQN"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose the Linux deployment group we made on &lt;a href="https://docs.google.com/document/d/1KauINvdb7BFPz9pdlGhwGw93Jj7unkbnTNWAXrstOeg/edit#heading=h.n6j71fd5yi6b" rel="noopener noreferrer"&gt;this step&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2A3XuKy89xJJyYXec8" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2A3XuKy89xJJyYXec8"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add a task to the deployment job.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;To add a new task click the &lt;strong&gt;+&lt;/strong&gt; sign.&lt;/li&gt;
&lt;li&gt;Then search for &lt;strong&gt;Download build artifacts&lt;/strong&gt;. This task is to download artifacts from the CI pipeline to the Linux VM.&lt;/li&gt;
&lt;li&gt;Finally, &lt;strong&gt;Add&lt;/strong&gt; the task.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2A7r1MUEHrP4G5AbB_" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2A7r1MUEHrP4G5AbB_"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next is to configure your Download Build Artifacts job. Follow these 6 steps.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click the &lt;strong&gt;Download Build Artifacts&lt;/strong&gt; task.&lt;/li&gt;
&lt;li&gt;Choose to download artifacts by &lt;strong&gt;Specific Build&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Define your Azure DevOps project&lt;/li&gt;
&lt;li&gt;Define your CI pipeline.&lt;/li&gt;
&lt;li&gt;Check the &lt;strong&gt;When appropriate download artifacts from the triggering build&lt;/strong&gt; checkbox to trigger a download only after the build is finished.&lt;/li&gt;
&lt;li&gt;As for the download, type choose &lt;strong&gt;Specific files&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AY5iGYaSEcE2O1u1y" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AY5iGYaSEcE2O1u1y"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then search for the &lt;strong&gt;Command line&lt;/strong&gt; task:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new task by clicking the &lt;strong&gt;+&lt;/strong&gt; button.&lt;/li&gt;
&lt;li&gt;Search for &lt;strong&gt;“command”&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Add&lt;/strong&gt; to add a new task to the existing job.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AEWRJZrvelnFdQywZNAAxJA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AEWRJZrvelnFdQywZNAAxJA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then in the command line, paste in the script you will be running:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Copy the &lt;strong&gt;appsettings.json&lt;/strong&gt; file from the home directory to the build folder.&lt;/li&gt;
&lt;li&gt;Generate system service configuration files and start &lt;strong&gt;if not exist&lt;/strong&gt; using the &lt;em&gt;make-service.sh&lt;/em&gt; script.&lt;/li&gt;
&lt;li&gt;Restart the service for the .NET Core project.&lt;/li&gt;
&lt;li&gt;Add NGINX configuration &lt;strong&gt;if not exist&lt;/strong&gt; using the &lt;em&gt;add-nginx-conf.sh&lt;/em&gt; script.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Notice in the command line, there are tags like &lt;strong&gt;$(Build.DefinitionName)&lt;/strong&gt;. This is one of Azure Pipeline’s pre-defined variables you can learn more about it &lt;a href="https://docs.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&amp;amp;tabs=yaml" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AsxB70Pit7xBQICV3" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AsxB70Pit7xBQICV3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you’re done with the configuration, save your Release pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Change the name of the Pipeline&lt;/li&gt;
&lt;li&gt;Save the pipeline.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Testing the pipeline
&lt;/h3&gt;

&lt;p&gt;To test the pipeline, go to the Pipelines section, open the pipeline you just created, and click &lt;strong&gt;Run Pipeline&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AulEJaZGiPYdzOIEoOt8iWw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AulEJaZGiPYdzOIEoOt8iWw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We run it from the CI pipeline because both CI and CD pipelines are already connected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;In this tutorial, you have learned how to automate CI/CD deployments using Azure DevOps and some shell scripts. We tested it out using a .NET Core project. The Linux server used was a Centos 8.&lt;/p&gt;

&lt;p&gt;To recap what we have done:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Installed an Azure Agent on Linux.&lt;/li&gt;
&lt;li&gt;Configured our Linux server for automation.&lt;/li&gt;
&lt;li&gt;Prepared the CI/CD Pipelines.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You now have an open playbook to use when you want to automate deployments. Hope this tutorial was of help and have a nice day!&lt;/p&gt;

</description>
      <category>azure</category>
      <category>devops</category>
      <category>linux</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>How To Choose Your First Techstack</title>
      <dc:creator>Agustinus Theodorus</dc:creator>
      <pubDate>Wed, 18 Nov 2020 13:01:31 +0000</pubDate>
      <link>https://dev.to/agustinustheo/how-to-choose-your-first-techstack-1mhf</link>
      <guid>https://dev.to/agustinustheo/how-to-choose-your-first-techstack-1mhf</guid>
      <description>&lt;p&gt;For all these years in the tech industry. I assure you that I have had my fair share of technology. A multitude of different frameworks aiming to achieve the same thing with their own different takes. Teams that prefer different tech stacks. It doesn’t matter what you learn but how fast can you adapt.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---2iyV15k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2A9RPiaNqFjBvZay_Q" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---2iyV15k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2A9RPiaNqFjBvZay_Q" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, I might not give you &lt;strong&gt;exact&lt;/strong&gt; answers to what you should choose. Because I believe that you should find what is comfortable for yourself. I would just explain what my ideas were when I chose my stack.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Job Stack
&lt;/h3&gt;

&lt;p&gt;When you first started working as a software engineer, you would realize that you can’t decide what tech stack your company would use, initially. You would need a lot more rep and power to be making those decisions.&lt;/p&gt;

&lt;p&gt;So, there you are stuck with a legacy system using &lt;a href="https://winworldpc.com/product/microsoft-visual-bas/60"&gt;VB 6.0&lt;/a&gt;. Probably that shouldn’t be your choice. If you have ever used &lt;a href="https://winworldpc.com/product/microsoft-visual-bas/60"&gt;VB 6.0&lt;/a&gt; damn, how programming has improved over the years. No, this is not an endorsement for &lt;a href="https://winworldpc.com/product/microsoft-visual-bas/60"&gt;VB 6.0&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In my company, we mainly use C# and PHP. I was mentored using C# and &lt;a href="https://dotnet.microsoft.com/apps/aspnet/mvc"&gt;ASP.NET MVC&lt;/a&gt; when I was first starting, then continued to use PHP and CodeIgniter in my second year. So the choices were between these two.&lt;/p&gt;

&lt;p&gt;I chose C#. Why? Well here comes the subjective part. PHP is not a language for me. It is too flexible and there are too many syntaxes that do the same thing. My experience was with PHP5, now it’s with PHP7 things have improved but I have already invested more time on C#.&lt;/p&gt;

&lt;p&gt;The point here is that you can choose to deepen your skill in a modern language used by your current employer. It would be easier and you can suggest implementations of some cool stuff using your employer’s language of choice.&lt;/p&gt;

&lt;p&gt;For example, recently when being tasked with making a multithreaded background service. Using C# and &lt;a href="https://dotnet.microsoft.com/download"&gt;.NET Core&lt;/a&gt; really helped me craft a perfect solution for my employer.&lt;/p&gt;

&lt;p&gt;The best part is not the solution, the best part would be the fact that anyone in your team can maintain your application. Collaboration would be easy because the language used is universally understood by engineers in your company.&lt;/p&gt;

&lt;p&gt;The only downside would be the lack of freedom. You can’t force your will upon your employer, and if you try to master a different language, you end up learning 2 things at the same time. It depends on you personally but I would prefer to avoid that.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Swiss Army Stack
&lt;/h3&gt;

&lt;p&gt;Ooh, swiss army stack! That sounds cool, doesn’t it?&lt;/p&gt;

&lt;p&gt;This particular stack consists of mainly one language with multiple different frameworks for different situations. A good example here would be the Javascript/&lt;a href="https://nodejs.org/en/"&gt;NodeJS&lt;/a&gt; ecosystem.&lt;/p&gt;

&lt;h4&gt;
  
  
  Javascript
&lt;/h4&gt;

&lt;p&gt;Who here doesn’t know NodeJS? Look it up.&lt;/p&gt;

&lt;p&gt;Using a front-end framework like &lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt;, &lt;a href="https://vuejs.org/"&gt;Vue&lt;/a&gt;, or &lt;a href="https://angularjs.org/"&gt;Angular&lt;/a&gt; has been the norm. They all use Javascript/&lt;a href="https://www.typescriptlang.org/"&gt;Typescript&lt;/a&gt;. So why bother learning a different language other than Javascript? Just use &lt;a href="https://expressjs.com/"&gt;Express&lt;/a&gt; for the backend and your all set. Fullstack Javascript here we go.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hey, do you know Javascript can do AI too? It can, there is a library called &lt;a href="https://www.tensorflow.org/js"&gt;Tensorflow.js&lt;/a&gt;. Now don’t tell me that isn’t amazing?!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To be clear, I am not advocating for Javascript. It is just one of those languages that have a lot of functionality. Another example would be Python, and probably &lt;a href="https://dart.dev/"&gt;Dart&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Python
&lt;/h4&gt;

&lt;p&gt;I don’t know about you, but Python is still looking hot nowadays. It still hasn’t lost it’s easy to use appeal. You can make a ton of things with Python, web applications, APIs, AI applications, background services, etc.&lt;/p&gt;

&lt;p&gt;As far as I know, the Javascript ecosystem’s AI libraries aren’t as mature as Python. Python is the main go-to language for AI. Youtube AI programming tutorials usually are done using Python. Some exceptions are using Javascript but my argument still stands.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;But Python does suck at frontend programming. Javascript beat Python in GUI building by a longshot.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Dart
&lt;/h4&gt;

&lt;p&gt;Honestly, this should be an honorable mention. But because the environment is quite interesting and has some potential, I thought I would bring it to light.&lt;/p&gt;

&lt;p&gt;So, the main powerhouse behind &lt;a href="https://dart.dev/"&gt;Dart&lt;/a&gt; is Google’s &lt;a href="https://flutter.dev/"&gt;Flutter&lt;/a&gt;. The prospect of a multiplatform frontend framework for Desktop, Mobile, and Web is very promising, to say the least.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Sure, Javascript has a multiplatform framework. There’s &lt;a href="https://reactnative.dev/"&gt;React Native&lt;/a&gt;. But it’s only for &lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt;. So, mobile and web. How about &lt;a href="https://www.electronjs.org/"&gt;Electron.js&lt;/a&gt;? Sure it would work for Desktop. But &lt;a href="https://flutter.dev/"&gt;Flutter&lt;/a&gt; alone compasses all three.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Backend though. It isn’t as promising. The only backend framework I know that uses Dart is probably &lt;a href="https://aqueduct.io/"&gt;Aqueduct&lt;/a&gt;. Though to be honest, I haven’t had time to research that. So I don’t know if it is already production-ready.&lt;/p&gt;

&lt;p&gt;Out of the three languages, I would say Dart is the least mature tech stack. An immature tech stack can bring opportunities for new developers to contribute to the open-source ecosystem, but the downside would be very unstable ecosystem wise.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Mature Stack
&lt;/h3&gt;

&lt;p&gt;Mature by what definition? These tech stacks have been around for a while. Has been battle-tested and many applications are using them.&lt;/p&gt;

&lt;p&gt;For example, in the case of web frameworks, a mature framework would be C#’s ASP.NET, Java’s Spring, Python’s Django, PHP’s CodeIgniter, Symfony, and Ruby on Rails. These are some of the oldest tech stacks, developed between 2002–2006. Many corporate applications use these frameworks.&lt;/p&gt;

&lt;p&gt;Being knowledgeable about these tech stacks are only good if you want to join large corporations. New startups have a very different tech stack, not because these frameworks are bad. But because there exist more production-ready options today.&lt;/p&gt;

&lt;p&gt;I personally have tried 3 of the previously mentioned frameworks. ASP.NET, Django, and Ruby on Rails. &lt;strong&gt;My favorite was Ruby on Rails&lt;/strong&gt;. Django was always too complicated for me, I prefer to use Flask for Python web development. It’s hard to host ASP.NET applications on Linux so I also passed on that.&lt;/p&gt;

&lt;h3&gt;
  
  
  So, which should I choose?
&lt;/h3&gt;

&lt;p&gt;Now, this is where it gets opinionated.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Take this with a grain of salt, try it out yourself. There are many more technologies available than what I have written here.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you dislike your job stack, well you can use it for professional purposes only, and try to find another job with a tech stack you like. Nothing you can do about it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;My simple guide would be to master one object-oriented language and one scripting language, and if you’re lucky both of them would be multiplatform.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I on the other hand love C# and .NET Core, so it has not been a problem for me. I prefer it over Java because C# libraries are helpful and are already all too familiar to me. .NET Core is also multiplatform, and unlike previous ASP.NET releases, it runs seamlessly on Linux.&lt;/p&gt;

&lt;p&gt;My scripting language of choice would be Python. Writing in Python has been so wonderfully easy. I am very comfortable with the amount of flexibility the language gives me. The libraries are also mature and because I have an obsession with AI, implementing an AI model in a web application is seamless.&lt;/p&gt;

&lt;p&gt;Seeing my choices you might be wondering. “Hmm, so C# and Python. Aren’t both of them backend languages?”, and you are right. Well, apart from C# Blazor. But I don’t use Blazor that much so I’ll turn a blind eye to that.&lt;/p&gt;

&lt;p&gt;For front-end purposes, I use Javascript frameworks. This limits my capabilities to pure web applications because Javascript frameworks are mostly well known for its front-end web frameworks. But another benefit of learning Javascript is that it is an in-demand skill. Javascript can have production-ready environments for both front-end and back-end most companies take advantage of that.&lt;/p&gt;

&lt;p&gt;Furthermore, Javascript has another benefit of being &lt;strong&gt;a free tech stack&lt;/strong&gt;. Here’s what I mean. There is a service called &lt;a href="https://www.netlify.com/"&gt;Netlify&lt;/a&gt;. Netlify hosts JAM Stack applications, and if you have reasonably small traffic, Netlify covers the costs for free. JAM stands for Javascript, APIs, Markup. Add to that Netlify also has a service called &lt;a href="https://www.netlify.com/products/functions/"&gt;Netlify Functions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dwfj7rvl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2ASjwe6yN2B25zJI91MAqMmA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dwfj7rvl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2ASjwe6yN2B25zJI91MAqMmA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Netlify Functions utilize serverless technologies to make simple APIs using Javascript using &lt;a href="https://aws.amazon.com/lambda/"&gt;AWS Lambda&lt;/a&gt; as their base. You are only charged after 125k~ requests or so.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--51zkM6AH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2Awl90hwJrFDI7-UW1jHQfjQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--51zkM6AH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2Awl90hwJrFDI7-UW1jHQfjQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My next statement might sound controversial, but in my opinion, adding Javascript to your knowledge repository can help you get a job. It is very popular and very flexible. Being multiplatform it is cost-effective and the choice of many modern startups. Some corporations are also planning to migrate to Javascript environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;So? Found your calling yet? Don’t rush. It’s fine. Do what you think is right. If you want to learn them all, be my guest. I am already at a stage where I want to master concepts rather than frameworks so I can say I understand how it feels. Be slow but sure, you won’t master it all overnight.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“The master has failed more times than the beginner has even tried.” — &lt;a href="https://www.goodreads.com/quotes/1252243-the-master-has-failed-more-times-than-the-beginner-has"&gt;Stephen McCranie&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Don’t be afraid to try. Failure is only a step. Thank you and have a nice day!&lt;/p&gt;

</description>
      <category>software</category>
      <category>productivity</category>
      <category>webdev</category>
      <category>techstack</category>
    </item>
    <item>
      <title>How To Host Flutter Web In Linux Using Nginx</title>
      <dc:creator>Agustinus Theodorus</dc:creator>
      <pubDate>Sun, 08 Nov 2020 22:02:42 +0000</pubDate>
      <link>https://dev.to/agustinustheo/how-to-host-flutter-web-in-linux-using-nginx-4a93</link>
      <guid>https://dev.to/agustinustheo/how-to-host-flutter-web-in-linux-using-nginx-4a93</guid>
      <description>&lt;p&gt;Thinking of making a web app? I recommend you try Flutter. Flutter’s web capabilities are still in beta but it’s quite promising, to say the least. I have experienced first hand how quick it is to build UIs using Flutter and I think it could soon be a competitive alternative to the Javascript ecosystem such as React, Vue, and Angular.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RR3cD5zc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2A4HwhJBcQU5Fcjv2U" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RR3cD5zc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2A4HwhJBcQU5Fcjv2U" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So to help out the future Flutter community members, a tutorial on how to host your Flutter web app on a DIY private server would help. As a healthy alternative to Firebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  What would you need?
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Umm, first of all, a private server.
&lt;/h4&gt;

&lt;p&gt;With serverless capabilities nowadays it is no wonder that people prefer Firebase, it’s free and it’s painless. Obvious choice.&lt;/p&gt;

&lt;p&gt;But what if we want to go independent? Away from the norms? Well, you have to learn it all yourself. Because we are using Nginx, then the server must be a Linux server, not a Windows server.&lt;/p&gt;

&lt;p&gt;Assuming you use a Debian/Ubuntu-based Linux distro. Here’s a starter script to help you get started.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt update  
sudo apt install nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There, I just saved you some googling time. If you want an in-depth guide on Nginx, I suggest you read &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-18-04"&gt;this post by Digital Ocean&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Do we need to install the Flutter SDK on our server?
&lt;/h4&gt;

&lt;p&gt;Umm, yes, and no.&lt;/p&gt;

&lt;p&gt;Let me elaborate. It is possible to install the SDK, but why do you need exactly? Installing the SDK helps you to test quick changes to the code on the server to try to fix a few production-related bugs like a cowboy!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vu7TKN6o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/600/0%2AchBNVmBfQ2j2KpyA.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vu7TKN6o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/600/0%2AchBNVmBfQ2j2KpyA.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I won’t do it though because SDKs consumes a lot of memory and requires a lot of RAM to be compiled. Your private server might not have enough RAM to process it. Believe me, I’ve tried. My VPS only had around 400MB of RAM enough to run a small app but not enough to compile the SDK. &lt;strong&gt;So I didn’t install it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So this just leaves one option either you use CI/CD to deploy your Flutter app to your VPS or just use plain old git. By using Git I mean by pushing your builds to the repository. This might not be a best practice for some teams as the entire software world almost unilaterally agree on using CI/CD, but hey — a cowboy’s gotta do what a cowboy’s gotta do.&lt;/p&gt;

&lt;p&gt;I am not going into how much of a best practice this tutorial is going to be rather how simple and understandable it is. So let me just leave this choice to you.&lt;/p&gt;

&lt;h4&gt;
  
  
  Do I need a domain?
&lt;/h4&gt;

&lt;p&gt;Do you need a domain? No. It is not required because we are learning &lt;strong&gt;how to host a Flutter web app using Nginx&lt;/strong&gt; using a domain or not is not of this tutorial’s concern.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build your app
&lt;/h3&gt;

&lt;p&gt;After your app has been tested, run the Flutter build command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flutter build web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That should generate a build folder within your project structure. Within the build folder, there is another folder named &lt;strong&gt;web&lt;/strong&gt; which contains the essential files to be used for hosting.&lt;/p&gt;

&lt;p&gt;The web directory should contain a file named &lt;strong&gt;index.html&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure Nginx
&lt;/h3&gt;

&lt;p&gt;Here come’s the fun part. Now copy that web directory to your VPS in any fashion you would want. Then make sure you move the build files to /var/www/html.&lt;/p&gt;

&lt;p&gt;Let’s say your application name is &lt;strong&gt;todos&lt;/strong&gt; so a good folder naming convention would be /var/www/html/todos. Inside the todos directory is the build files, &lt;strong&gt;index.html,&lt;/strong&gt; etc. If you’re not familiar with Linux commands this should help, assuming that your build files are in your home directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mv web /var/www/html/todos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, you need to go to the Nginx directory on your server more precisely /etc/nginx/sites-enabled. There should be a file named &lt;strong&gt;default&lt;/strong&gt;. Open it using a vim/nano text editor of your choice and change the root directory on the configuration file to /var/www/html/todos.&lt;/p&gt;

&lt;h4&gt;
  
  
  No Domain Setup
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Default server configuration
server {
       listen 80 default_server;
       listen [::]:80 default_server;

       root /var/www/html/todos;
       index index.html index.htm;

       server_name _;

       location / {
              try_files $uri $uri/ =404;
       }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is an example. The original file should be filled with comments, but I left those comments out in the gist. After changing your config files, check your Nginx config using this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nginx -t
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If all is well, then restart the Nginx service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should restart your Nginx server and get the updated config file. When all is done open up your VPS IP Address from the browser. Your Flutter app should already be up.&lt;/p&gt;

&lt;p&gt;I prefer people access my app by domain so I’ll include how to set up the app using a domain here too.&lt;/p&gt;

&lt;h4&gt;
  
  
  Domain Setup
&lt;/h4&gt;

&lt;p&gt;When you don’t want to use a domain, changing the &lt;strong&gt;default&lt;/strong&gt; file should be fine (even though some people prefer to leave the default as-is and create a new one).&lt;/p&gt;

&lt;p&gt;But when you want to use a domain, make sure you make a new configuration file. The file should have a .conf extension.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Default server configuration
server {
       listen 80;
       root /var/www/html/yourdomain.com;
       index index.html index.htm;

       server_name yourdomain.com www.yourdomain.com;

       location / {
              try_files $uri $uri/ =404;
       }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I have attached the corresponding gist. The setup should be similar to the previous one with a difference in the server_name. Then before you open your app from the browser, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo nginx -t
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If configuration health checks pass, reload the Nginx service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl reload nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After restarting Nginx, try to open your domain from your browser. It should be done by then.&lt;/p&gt;

&lt;h3&gt;
  
  
  Further Note
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Don’t forget to update domain nameservers
&lt;/h4&gt;

&lt;p&gt;When you want to use a domain, please make sure you point your domain nameservers to your VPS. You are required to do this before any further configuration is to be done.&lt;/p&gt;

&lt;h4&gt;
  
  
  Install an SSL certificate using Certbot
&lt;/h4&gt;

&lt;p&gt;There’s a technology called Let’s Encrypt. It gives you free SSL certificates to be used for your apps, securing your app, and adding HTTPS to your domain. Install Certbot for Nginx using this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt install python-certbot-nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, install SSL certificates on your domains:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo certbot --nginx -d your\_domain -d www.your\_domain
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;In this tutorial, you have learned how to serve a Flutter application using Nginx. You now have an open playbook to use when you want to deploy Flutter web applications using Nginx on your own server. Hope this tutorial was of help and have a nice day!&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>linux</category>
      <category>dart</category>
      <category>devops</category>
    </item>
    <item>
      <title>How To Make Scalable APIs Using Flask and FaunaDB</title>
      <dc:creator>Agustinus Theodorus</dc:creator>
      <pubDate>Tue, 27 Oct 2020 23:50:13 +0000</pubDate>
      <link>https://dev.to/agustinustheo/how-to-make-scalable-apis-using-flask-and-faunadb-1onp</link>
      <guid>https://dev.to/agustinustheo/how-to-make-scalable-apis-using-flask-and-faunadb-1onp</guid>
      <description>&lt;p&gt;With the rise of serverless technology, making web services only gets easier. Serverless apps change the old monolithic architecture of apps and promote more of a microservice solution to technical problems.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eEi42SqV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2ADuZ_NXbhwmAfiMPM" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eEi42SqV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2ADuZ_NXbhwmAfiMPM" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the advantage of autoscaling, and multi-region deployments it is no wonder that serverless apps are making a quick rise in recent years. The cost of serverless has also redefined how we make software as it is now on a per request basis rather than a time-based service.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Even better, serverless also enables small services to be free altogether. Only being needed to be paid after a million requests or so. &lt;a href="https://azure.microsoft.com/en-us/pricing/details/functions/#:~:text=Azure%20Functions%20consumption%20plan%20is,function%20apps%20in%20that%20subscription."&gt;An example would be Azure Function’s consumption plan&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  What does Serverless have to do with this tutorial?
&lt;/h3&gt;

&lt;p&gt;The main reason serverless is being mentioned here is because &lt;a href="https://fauna.com/features"&gt;FaunaDB&lt;/a&gt; is a NoSQL database that is made for serverless in mind. The pricing on this database is request based, precisely what serverless apps need.&lt;/p&gt;

&lt;p&gt;Using a service like FaunaDB can help cut costs so much that the hosting capabilities of the app would be virtually free. Excluding the development costs of course. Thus, using a monthly billed database for serverless apps kind of kills the point.&lt;/p&gt;

&lt;p&gt;A free stack example would be a combination of Netlify, Netlify Functions, and FaunaDB. Though it would only be ‘free’ for a certain amount of requests. Unless you are making an app that gets thousands of users on day zero of deployment I don’t think it would be much of a problem.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In my opinion, using a monthly billed database for serverless apps kind of kills the point&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Flask on the other hand is a microframework written in Python. It is a minimalistic framework with no database abstraction layers, form validation, or any other particular functions provided by other frameworks.&lt;/p&gt;

&lt;p&gt;Flask is by large serverless compatible. You can make a serverless Flask app using AWS Lambda. &lt;a href="https://www.serverless.com/flask"&gt;Here is an official guide to Flask serverless from serverless.com&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Started
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Setting up Python and Pip
&lt;/h4&gt;

&lt;p&gt;First of all, install Python and Pip. I’m not going to list all the possible ways of installing it, for Windows users you can get the installer &lt;a href="https://www.python.org/downloads/windows/"&gt;here&lt;/a&gt;. As for Linux users if you are using a Debian/Ubuntu-based distro open your command prompt and install python and pip like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt update  
sudo apt install python3 python3-pip

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

&lt;/div&gt;



&lt;p&gt;To check if the installation is correct try executing these commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python --version  
pip --version

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

&lt;/div&gt;



&lt;p&gt;The version numbers would then show for the corresponding commands.&lt;/p&gt;

&lt;h4&gt;
  
  
  Installing dependencies
&lt;/h4&gt;

&lt;p&gt;After the environment setup is complete, the next step would be to install Flask itself. The installation process is simple just enter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install Flask

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

&lt;/div&gt;



&lt;p&gt;Then, install the python driver for FaunaDB:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install faunadb

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

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Voila!&lt;/em&gt; You’re all set!&lt;/p&gt;

&lt;h3&gt;
  
  
  Making a To-Do List App
&lt;/h3&gt;

&lt;p&gt;Now we are going to make an example app with the &lt;strong&gt;mother&lt;/strong&gt; of all app ideas, the to-do list app.&lt;/p&gt;

&lt;h4&gt;
  
  
  To-Do List Template
&lt;/h4&gt;

&lt;p&gt;For this example, because we will be focusing mainly on how to make the API we will be using the &lt;a href="https://www.w3schools.com/howto/howto_js_todolist.asp"&gt;W3School template&lt;/a&gt; for the to-do list app frontend.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sj3RLfEz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2Avd-pu5pZaaHq0pSjp39meQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sj3RLfEz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2Avd-pu5pZaaHq0pSjp39meQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Basic Project Structure
&lt;/h4&gt;

&lt;p&gt;Our project would be an implementation of a helper pattern. A simple outline of our project would be like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\-
 |--app.py   
 |  
 |--services  
    |--todo_service.py  
 |--helpers  
    |--todo_helper.py  
 |--entities  
    |--faunadb_entity.py

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  FaunaDB Indexes
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Wait, what are indexes?
&lt;/h4&gt;

&lt;p&gt;Indexes are how you make ‘where’ statements in FaunaDB. It allows you to get specific documents based on the field values.&lt;/p&gt;

&lt;p&gt;To create a new Index, just go to the Indexes section on your database and click &lt;strong&gt;New Index&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yraVzMGP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2Ao7EBsxeVx6QtvRmq4s0fLA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yraVzMGP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2Ao7EBsxeVx6QtvRmq4s0fLA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When creating an Index, choose the collection you would want to interact with. Then define the field name you want to search by. Lastly, define your index name make sure it is unique and readable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4LuZ7-VR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2ALoR_MqlQX_is-ZtnAvDxCw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4LuZ7-VR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2ALoR_MqlQX_is-ZtnAvDxCw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example, let’s make an index where we can get all the data in an existing collection.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pUCZJWIv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AnOsbTxZXiyhH11zB-0qH_g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pUCZJWIv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AnOsbTxZXiyhH11zB-0qH_g.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Oh, what about an index to get todos by the user’s email? Easy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--trKwZgqW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AyWe7e6e0TlskA2NUrGI3GQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--trKwZgqW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AyWe7e6e0TlskA2NUrGI3GQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to make the terms unique, check the Unique checkbox to add a constraint.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WMOXTnLO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2ADCaHNlv3bdj8WDIpb7IYcw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WMOXTnLO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2ADCaHNlv3bdj8WDIpb7IYcw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To add constraints to a certain collection you need to create indexes with terms that contain unique fields.&lt;/p&gt;

&lt;p&gt;To help you understand better, &lt;a href="https://docs.fauna.com/fauna/current/tutorials/indexes/index.html"&gt;here is an official article from Fauna to help you understand indexes.&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Let’s Make The API
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Make the Flask startup file
&lt;/h4&gt;

&lt;p&gt;First, write a python file that would run Flask.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from flask import Flask

app = Flask( __name__ )

if __name__ == " __main__":
    app.run(host='0.0.0.0')

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  Write the FaunaDB entity script
&lt;/h4&gt;

&lt;p&gt;Next, before we start writing our services and helpers we must first define an entity file to connect to FaunaDB.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os
from faunadb import query as q
from faunadb.objects import Ref
from faunadb.client import FaunaClient

def get(index, data):
    try:
        serverClient = FaunaClient(secret=os.environ.get("FAUNA_SERVER_SECRET"))
        res = serverClient.query(q.get(q.match(q.index(index), data)))
        res["data"]["ref_id"] = res["ref"].id()
        return res["data"]
    except Exception as ex:
        raise ex

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

&lt;/div&gt;



&lt;p&gt;This is used to get a FaunaDB document by Index. The get function does not return multiple documents and is only able to return a single document at a time.&lt;/p&gt;

&lt;p&gt;To get multiple documents we need to use a map function to return multiple data by a certain index.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def get_multiple(index, data=None):
    try:
        serverClient = FaunaClient(secret=os.environ.get("FAUNA_SERVER_SECRET"))
        res_arr = []
        if data is None:
            res = serverClient.query(   
                q.map_(
                    q.lambda_("data", q.get(q.var("data"))), 
                    q.paginate(q.match(q.index(index)))
                )
            )
            res_arr.extend(res["data"])
        elif isinstance(data, list):
            for x in data:
                res = serverClient.query(   
                    q.map_(
                        q.lambda_("data", q.get(q.var("data"))), 
                        q.paginate(q.match(q.index(index), q.casefold(x)))
                    )
                )
                res_arr.extend(res["data"])
        else:
            res = serverClient.query(   
                q.map_(
                    q.lambda_("data", q.get(q.var("data"))), 
                    q.paginate(q.match(q.index(index), q.casefold(data)))
                )
            )
            res_arr.extend(res["data"])

        arr = []
        for x in res_arr:
            x["data"]["ref_id"] = x["ref"].id()
            arr.append(x["data"])
        return arr
    except Exception as ex:
        raise ex

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

&lt;/div&gt;



&lt;p&gt;The lambda function will pass the data needed in the Index while paginate will search for the specific documents in the collection, then the map function will return all matching documents as a list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def get_by_ref_id(collection, id):
    try:
        serverClient = FaunaClient(secret=os.environ.get("FAUNA_SERVER_SECRET"))
        res = serverClient.query(q.get(q.ref(q.collection(collection), id)))
        res["data"]["ref_id"] = res["ref"].id()
        return res["data"]
    except Exception as ex:
        raise ex

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

&lt;/div&gt;



&lt;p&gt;Get document by reference Id is the only function that does not use an Index rather would utilize the document’s reference Id.&lt;/p&gt;

&lt;p&gt;The code for creating, updating, and deleting documents would be similar. Because FaunaDB is a NoSQL database the data structure doesn’t matter as long as it is passed as a dictionary. Updating and deleting documents would also need an extra reference Id parameter, similar to the Get document by reference Id function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def create(collection, data):
    try:
        serverClient = FaunaClient(secret=os.environ.get("FAUNA_SERVER_SECRET"))
        res = serverClient.query(q.create(q.collection(collection), {"data": data}))
        res["data"]["ref_id"] = res["ref"].id()
        return res["data"]
    except Exception as ex:
        raise ex

def update(collection, id, data):
    try:
        serverClient = FaunaClient(secret=os.environ.get("FAUNA_SERVER_SECRET"))
        res = serverClient.query(q.update(q.ref(q.collection(collection), id), {"data": data}))
        res["data"]["ref_id"] = res["ref"].id()
        return res["data"]
    except Exception as ex:
        raise ex

def delete(collection, id):
    try:
        serverClient = FaunaClient(secret=os.environ.get("FAUNA_SERVER_SECRET"))
        serverClient.query(q.delete(q.ref(q.collection(collection), id)))
        return True
    except Exception as ex:
        raise ex

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  Make the To-Do helper
&lt;/h4&gt;

&lt;p&gt;After writing the FaunaDB entity script, write the helper functions for the collection. The helper functions need to be small precise functions that do exactly one thing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from entities.faunadb_entity import get, get_multiple, get_by_ref_id, create, update, delete

def get_all_todos():
    try:
        return get_multiple('all_todos')
    except Exception as ex:
        raise ex

def get_todo_by_ref_id(id):
    try:
        return get_by_ref_id('todo', id)
    except Exception as ex:
        raise ex

def create_todo(data):
    try:
        return create('todo', data)
    except Exception as ex:
        raise ex

def update_todo(id, data):
    try:
        return update('todo', id, data)
    except Exception as ex:
        raise ex

def delete_todo(id):
    try:
        return delete('todo', id)
    except Exception as ex:
        raise ex

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  Make the To-Do service
&lt;/h4&gt;

&lt;p&gt;When all the helpers are ready, write the service file to be used as endpoints. All the requests are parsed at the service level, thus the helper level will only receive processed data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from flask import request, jsonify
from helpers import todo_helper

def get_all_todos():
    try:
        print(todo_helper.get_all_todos())
        return jsonify(todo_helper.get_all_todos())
    except Exception as ex:
        raise ex

def get_todo_by_ref_id(id):
    try:
        return jsonify(todo_helper.get_todo_by_ref_id(id))
    except Exception as ex:
        raise ex

def create_todo():
    try:
        req_data = request.get_json()
        return jsonify(todo_helper.create_todo(req_data))
    except Exception as ex:
        raise ex

def update_todo(id):
    try:
        req_data = request.get_json()
        return jsonify(todo_helper.update_todo(id, req_data["data"]))
    except Exception as ex:
        raise ex

def delete_todo(id):
    try:
        return jsonify(todo_helper.delete_todo(id))
    except Exception as ex:
        raise ex

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

&lt;/div&gt;



&lt;h4&gt;
  
  
  Attach the routes to the service endpoints
&lt;/h4&gt;

&lt;p&gt;Finally, when the endpoints are set, add the endpoints to the app.py&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from services.todo_service import get_all_todos, get_todo_by_ref_id, create_todo, update_todo, delete_todo
from flask import Flask

app = Flask( __name__ )
app.add_url_rule('/api/todos', methods=['GET'], view_func=get_all_todos)
app.add_url_rule('/api/todos', methods=['POST'], view_func=create_todo)
app.add_url_rule('/api/todos/&amp;lt;string:id&amp;gt;', methods=['GET'], view_func=get_todo_by_ref_id)
app.add_url_rule('/api/todos/&amp;lt;string:id&amp;gt;', methods=['PUT'], view_func=update_todo)
app.add_url_rule('/api/todos/&amp;lt;string:id&amp;gt;', methods=['DELETE'], view_func=delete_todo)

if __name__ == " __main__":
    app.run(host='0.0.0.0')

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

&lt;/div&gt;



&lt;p&gt;You’re done! Don’t forget to test the APIs with Postman before deployment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; You can check out my Github repository for the project and try to run it yourself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/agustinustheo/flask-faunadb"&gt;&lt;strong&gt;Boilerplate code for Flask and FaunaDB project&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this tutorial, you have learned to make an API using Flask and FaunaDB.&lt;/p&gt;

&lt;p&gt;To recap we have made:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API endpoints using Flask.&lt;/li&gt;
&lt;li&gt;Indexes in FaunaDB.&lt;/li&gt;
&lt;li&gt;A simple entity helper for FaunaDB.&lt;/li&gt;
&lt;li&gt;A readable boilerplate for future API projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You now have a quick boilerplate setup to use when you want to make a quick app in a matter of hours. Future plans include adding a Swagger implementation to the existing boilerplate.&lt;/p&gt;

&lt;p&gt;Hope this is a great start for you, have a nice day!&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>python</category>
      <category>serverless</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How To Deploy Your .NET Core App on an IIS Server</title>
      <dc:creator>Agustinus Theodorus</dc:creator>
      <pubDate>Tue, 20 Oct 2020 13:51:54 +0000</pubDate>
      <link>https://dev.to/agustinustheo/how-to-deploy-your-net-core-app-on-an-iis-server-5ade</link>
      <guid>https://dev.to/agustinustheo/how-to-deploy-your-net-core-app-on-an-iis-server-5ade</guid>
      <description>&lt;p&gt;When you work in an enterprise environment you can’t choose where you would want to publish your application, especially if you enter a very established company. There would be times that you have to publish in a Linux environment, but in this case publishing in a Windows environment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AQkuSb8wVpC5wY7kj" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AQkuSb8wVpC5wY7kj"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure your .NET Core project
&lt;/h3&gt;

&lt;p&gt;When trying to deploy on an IIS Server, make sure you already configure your Startup.cs and Program.cs accordingly. On the &lt;strong&gt;Startup.cs&lt;/strong&gt; you should add this config:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AWH3WzOX03-rPBePK" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AWH3WzOX03-rPBePK"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the &lt;strong&gt;Program.cs&lt;/strong&gt; add this config:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2A7ndyVaQEnF108l4V" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2A7ndyVaQEnF108l4V"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure your IIS Server
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Downloading the required packages
&lt;/h4&gt;

&lt;p&gt;Install the required packages before configuration.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.microsoft.com/download/details.aspx?id=52685" rel="noopener noreferrer"&gt;Microsoft Visual C++ 2015 Redistributable Update 3.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://support.microsoft.com/help/2533623/microsoft-security-advisory-insecure-library-loading-could-allow-remot" rel="noopener noreferrer"&gt;Windows Server Patch KB2533623.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Downloading the dotnet SDK
&lt;/h4&gt;

&lt;p&gt;Deployments only need runtime, but if you want to have a more flexible environment that allows you to build and publish &lt;strong&gt;dll&lt;/strong&gt; files rather than only running it you would want to install the latest dotnet SDK, &lt;a href="https://dotnet.microsoft.com/download/dotnet-core" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Install the Azure Artifacts Credential Provider
&lt;/h4&gt;

&lt;p&gt;Next, install the Azure Artifacts Credential Provider, full instructions can be seen &lt;a href="https://github.com/Microsoft/artifacts-credprovider" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Azure Artifacts Credential Provider Manual Installation Guide
&lt;/h4&gt;

&lt;p&gt;Find the latest release &lt;a href="https://github.com/Microsoft/artifacts-credprovider/releases" rel="noopener noreferrer"&gt;here&lt;/a&gt;, and download the .zip package.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AtlJiw8J58KyBZk1D" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AtlJiw8J58KyBZk1D"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After downloading the zip archive, copy the plugins folder to &lt;strong&gt;%USERPROFILE%/.nuget&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2ADNrZNycYxJ7EmmAK" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2ADNrZNycYxJ7EmmAK"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Set your environment variables, open &lt;strong&gt;User Variables&lt;/strong&gt; and create a new entry.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AjPaoP30GSXaE-mvK" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AjPaoP30GSXaE-mvK"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Set the variable name to &lt;strong&gt;NUGET_PLUGIN_PATHS&lt;/strong&gt; , and because in this case, we are going to be using the dotnet credential provider, so set the value to&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;%USERPROFILE%.nuget\plugins\netcore\CredentialProvider.Microsoft\CredentialProvider.Microsoft.dll&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2A1IbSM3kmog2-9kWl" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2A1IbSM3kmog2-9kWl"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then finish the setup by clicking &lt;strong&gt;OK&lt;/strong&gt; on the &lt;strong&gt;Environment Variables&lt;/strong&gt; dialog.&lt;/p&gt;

&lt;h3&gt;
  
  
  Publish your .NET Core application
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Pull the project from DevOps
&lt;/h4&gt;

&lt;p&gt;Get into the directory where you want to put the application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AJdLjczILQMnVA9QutYSYog.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AJdLjczILQMnVA9QutYSYog.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Get inside the newly formed folder and run the dotnet publish command. Further info regarding the commands can be seen &lt;a href="https://docs.google.com/document/d/14YRTCJ8XO7yumjwmwyN67ZrEpc4LDrbg6UXlGC4noI0/edit#heading=h.eyphkxwv1b7" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AbVpZ052xiPvEIl34UfVtfg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2AbVpZ052xiPvEIl34UfVtfg.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If an authorization prompt to &lt;a href="https://microsoft.com/devicelogin" rel="noopener noreferrer"&gt;https://microsoft.com/devicelogin&lt;/a&gt; pops up, login using the &lt;a href="https://azure.microsoft.com/en-us/services/devops/" rel="noopener noreferrer"&gt;Azure DevOps&lt;/a&gt; account and enter the code shown in the window.&lt;/p&gt;

&lt;p&gt;Otherwise, it should show a successful build like so:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2A9x3fssWVV25Ks0JUIHOaWw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2A9x3fssWVV25Ks0JUIHOaWw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this case, &lt;strong&gt;D:\deploy\api.test\bin\Release\netcoreapp3.1\publish&lt;/strong&gt; is the &lt;strong&gt;&lt;em&gt;physical path&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This will be the path used when configuring your app on an IIS application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run your .NET Core on IIS
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Add the application pool
&lt;/h4&gt;

&lt;p&gt;Right-click on the &lt;strong&gt;Application Pools&lt;/strong&gt; option.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2ANtuy9f755WVik0zY" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2ANtuy9f755WVik0zY"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose the &lt;strong&gt;Add Application Pool&lt;/strong&gt; option&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AKW3cmVX3rTQ7Lwjs" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AKW3cmVX3rTQ7Lwjs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Name your application pool and set the .NET CLR version to &lt;strong&gt;No Managed Code.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AyZqj4kWhU7wpVDp1" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AyZqj4kWhU7wpVDp1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then click &lt;strong&gt;OK&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Add the IIS website (Optional)
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;This configuration is optional as you can use a pre-existing site.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Right-click on the &lt;strong&gt;Site&lt;/strong&gt; option&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AfOXUHP0QgMyt-NXO" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AfOXUHP0QgMyt-NXO"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Add Website&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AZFzoqMNSIj7Mmwb5" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AZFzoqMNSIj7Mmwb5"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Set the &lt;strong&gt;Site name&lt;/strong&gt; and the physical path to the .NET Core build.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AIHxAaO_VohU2op1x" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AIHxAaO_VohU2op1x"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click the &lt;strong&gt;Connect as…&lt;/strong&gt; button, to connect as a specific user. Set your user credentials and click &lt;strong&gt;OK&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AhqYDTod9W9vsmTgM" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AhqYDTod9W9vsmTgM"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Test Settings&lt;/strong&gt; and it should show a pop up like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2A6zwI7X_4N98nhBPn" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2A6zwI7X_4N98nhBPn"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then on the &lt;strong&gt;Add Website&lt;/strong&gt; dialog click &lt;strong&gt;OK&lt;/strong&gt; to finish the setup.&lt;/p&gt;

&lt;h4&gt;
  
  
  Add the Application on the IIS website
&lt;/h4&gt;

&lt;p&gt;On the site’s homepage, click on the &lt;strong&gt;View Applications&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AxZT4AhnRwDe3-EjL" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AxZT4AhnRwDe3-EjL"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the &lt;strong&gt;Add Application&lt;/strong&gt; action&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AdInCu25X3VsVexlZ" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AdInCu25X3VsVexlZ"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Set your alias, this will be the path on the Url. Then, set the physical path to the .NET Core build.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2An0yJiu4l94muBAXB" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2An0yJiu4l94muBAXB"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, select the application pool you previously made, then click &lt;strong&gt;OK&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2ARWYhIfs7zUhkEePs" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2ARWYhIfs7zUhkEePs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click the &lt;strong&gt;Connect as…&lt;/strong&gt; button. Set your user credentials and click &lt;strong&gt;OK&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2A60abQOP6lDndEYGS" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2A60abQOP6lDndEYGS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Test Settings&lt;/strong&gt; and it should show a pop up like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AyDHFWEiPupCSrfsL" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F0%2AyDHFWEiPupCSrfsL"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then on the &lt;strong&gt;Add Application&lt;/strong&gt; dialog click &lt;strong&gt;OK&lt;/strong&gt; to finish the setup.&lt;/p&gt;

&lt;p&gt;When all steps are done, your application should be running. Test this by opening a browser and put &lt;strong&gt;localhost/*your application alias*&lt;/strong&gt; in the search bar.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;In this tutorial, you have learned how to serve a .NET Core application using IIS.&lt;/p&gt;

&lt;p&gt;To recap what we have done:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We have configured our .NET Core web app before deploying it on IIS.&lt;/li&gt;
&lt;li&gt;We have installed the prerequisites for the IIS server.&lt;/li&gt;
&lt;li&gt;We installed the required dotnet SDKs and the corresponding Azure authentication providers.&lt;/li&gt;
&lt;li&gt;We have configured IIS to deploy our .NET Core app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You now have an open playbook to use when you want to deploy dotnet applications on IIS. Hope this tutorial was of help and have a nice day!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>tutorial</category>
      <category>devops</category>
    </item>
    <item>
      <title>4 Key Habits I Learned as a Software Engineer</title>
      <dc:creator>Agustinus Theodorus</dc:creator>
      <pubDate>Mon, 12 Oct 2020 16:15:31 +0000</pubDate>
      <link>https://dev.to/agustinustheo/4-key-habits-i-learned-as-a-software-engineer-30po</link>
      <guid>https://dev.to/agustinustheo/4-key-habits-i-learned-as-a-software-engineer-30po</guid>
      <description>&lt;p&gt;I am almost 3 years into software engineering. Honestly, I don’t think I am &lt;strong&gt;that&lt;/strong&gt; good at it yet (I don’t know if I’ll ever be). But there are times when I wished that I knew somethings sooner than later. I thought it would be fun for me to reflect on those subjects and try to convey them to you as best as I can in this article. So here are the 4 key habits I learned as a software engineer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2Au18ToVTMMZ8AN1M4fur0xw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F800%2F1%2Au18ToVTMMZ8AN1M4fur0xw.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Write Clean Code (Obviously!)
&lt;/h3&gt;

&lt;p&gt;Bear with me here.&lt;/p&gt;

&lt;p&gt;So I haven’t always been the cleanest coder in the team. Through my struggles, I always find it annoying that people don’t understand what I wrote. Heck, I am annoyed that I can’t understand what I wrote a month ago.&lt;/p&gt;

&lt;p&gt;I thought, “Hey, why don’t I try to write &lt;em&gt;cleaner&lt;/em&gt;?”. Well, sometimes cleaner code doesn’t always mean someone else will understand what the code means at first glance. Because there are other factors at play like the business process, etc. But it helps — &lt;em&gt;I guess.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Don’t Repeat Yourself (DRY)
&lt;/h4&gt;

&lt;p&gt;Let me tell you, no one annoys me more than &lt;em&gt;myself.&lt;/em&gt; I honestly can’t explain how frustrated I am when I read old code that has multiple copies.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Trying to understand multiple copies of the same lines of code at different points in the documentation is &lt;strong&gt;really confusing&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So ever since I realized that I tried to write functions for code that I would be reusing often. &lt;em&gt;Boy did that save a lot of headaches&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If you don’t do that you might have to change multiple documents that literally have the same line of code just to let’s say — add a new condition to an if-else statement. Take it from me, sometimes you can forget and bugs will happen. So please, write code you going to reuse in a function.&lt;/p&gt;

&lt;p&gt;Speaking of functions…&lt;/p&gt;

&lt;h4&gt;
  
  
  Code Purposeful Functions
&lt;/h4&gt;

&lt;p&gt;What I meant by &lt;strong&gt;purposeful&lt;/strong&gt; is that you have to write functions that have one exact purpose. For example, I want to hash passwords so I would obviously write a function specifically to hash passwords.&lt;/p&gt;

&lt;p&gt;This will add even more readability to your code and it will save you a lot of headaches when you need to say — change the hashing algorithms &lt;em&gt;or whatever&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;But don’t go too overboard, if you feel that you don’t need to write a function for that &lt;strong&gt;.ToString()&lt;/strong&gt; method in C# than don’t. It’s already readable. Don’t overdo it.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Learn Design Patterns
&lt;/h3&gt;

&lt;p&gt;Like writing clean code wasn’t enough! Well, to be frank, it isn’t. I have tried to maintain and develop a lot of software in the 3 years I have been a software engineer, and sometimes I would say the default design pattern doesn’t do me any good.&lt;/p&gt;

&lt;p&gt;That’s why sometimes micro web frameworks like Flask are my favorites. I can go full creative in how I want my project to be, either by using repository patterns or otherwise.&lt;/p&gt;

&lt;p&gt;Find the best fit for you, try to catch up using materials &lt;a href="https://refactoring.guru/design-patterns" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Automate Tasks
&lt;/h3&gt;

&lt;p&gt;If possible, you should automate everything. Automation might be the best thing I have ever done in my entire career. One time I wrote an application to write APIs for me, so I wouldn’t have to write code anymore.&lt;/p&gt;

&lt;p&gt;Well to be fair, it was templated so I still have to code if the app isn’t a simple CRUD application, but it was a good start. This “code generator” coincides with the second point of learning design patterns. I would not have been able to make it if I didn’t implement a design pattern that was comfortable for me.&lt;/p&gt;

&lt;p&gt;Another idea would be if your office has a ticketing system of some kind automating those to be added to your Agile boards might be a good idea. Well, it depends, but it is possible.&lt;/p&gt;

&lt;p&gt;Other things you might want to automate probably would be menial tasks such as server monitoring and app deployments.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Be as Passionate About Writing as Coding
&lt;/h3&gt;

&lt;p&gt;Let me explain, probably your job as a software engineer does not always involve code. Sometimes it will involve writing.&lt;/p&gt;

&lt;p&gt;Maybe some companies have KPIs for writing on their engineering blog on Medium. But usually, the writing you would be doing involves documentation.&lt;/p&gt;

&lt;p&gt;It is kind of related to coding but rather than writing code, you are writing &lt;strong&gt;about&lt;/strong&gt; your code. In my personal experience, I would try to write the best documentation I can in the limited amount of time I would give myself. It helped tremendously when I had to handover projects to other teams.&lt;/p&gt;

&lt;p&gt;For me, I write good documentation for myself, because I don’t want to be bothered by other people.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Good documentation means fewer people asking for your help to understand your code. Which means more time for you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Keep that in mind the next time your boss asks you to document your code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; Write clean code, try to implement the Don’t Repeat Yourself (DRY) mindset to your code. Write purposeful functions that are easy to read. Learn design patterns, find a pattern that you personally like. Also if possible try to automate your tasks. Finally, never be a lazy documentation writer. It can save you more time than you think.&lt;/p&gt;

&lt;p&gt;In the end, we all have our own variety of lessons learned. These 4 are just mine. I am writing this not to persuade you rather share with you my personal opinions. Anyway, I hope you have a nice day!&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>career</category>
      <category>productivity</category>
      <category>performance</category>
    </item>
    <item>
      <title>4 Things I Learned About The Software Engineering Culture</title>
      <dc:creator>Agustinus Theodorus</dc:creator>
      <pubDate>Fri, 11 Sep 2020 11:20:37 +0000</pubDate>
      <link>https://dev.to/agustinustheo/4-things-i-learned-about-the-software-engineering-culture-530h</link>
      <guid>https://dev.to/agustinustheo/4-things-i-learned-about-the-software-engineering-culture-530h</guid>
      <description>&lt;p&gt;When I started my first job as a software engineer I would have never realized how narrow my world view regarding tech was. In my mind, the world of software is as large a pool when it is an ocean.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SHIrdiTL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2AhqcdsOSzhIQ3LQXk" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SHIrdiTL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2AhqcdsOSzhIQ3LQXk" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Everyone Starts Confused
&lt;/h3&gt;

&lt;p&gt;It is commonly said that most software engineers don’t know what exactly their profession would be in the tech world. It becomes more complicated today as more branches of software engineering emerge. The fast emergence of AI has opened many branches of software engineering roles such as Data Scientist, Machine Learning Engineer, and Deep Learning Engineer. Each role is different and needs exceptional skills in their own right.&lt;/p&gt;

&lt;p&gt;This coincides with previously available roles like Database Administrators, System Administrators, Networking Engineer. Heck, even Software Engineers have sub-roles like Frontend Engineer and Backend Engineers now because of how complicated software is nowadays. I don’t think I have even touched on the security roles yet.&lt;/p&gt;

&lt;p&gt;I honestly entered the tech world thinking I would end up as a Frontend Engineer. Today I am mainly focusing on backend services, system administration, and machine learning. If you’ve ever &lt;em&gt;touched&lt;/em&gt; any one of these skills you would understand how different these 4 roles are.&lt;/p&gt;

&lt;p&gt;I ended up learning everything I can. Though I am currently focusing more on machine learning than any other field. I find making computers do menial and repetitive jobs amusing.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Your Not In A Pool — Your In An Ocean
&lt;/h3&gt;

&lt;p&gt;As you might have already noticed, there are many flavors to software engineering. Some roles might be more enticing than others. But it doesn’t make those other roles less important.&lt;/p&gt;

&lt;p&gt;Every role in the software department needs to work together. Either you’re the networking engineer to the backend engineer. As you progress forward you would respect your colleagues for their contribution. Because in the end, they know things that you may not know, as well as you knowing things they do not know. Respect should be mutual.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Mentorship should not always be a relation between seniors to juniors, rather peers from different backgrounds.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In my opinion, you should always take every opportunity for a sharing session with your peers. You would never know what you would get out of it.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Software Engineering Is A Sharing Culture
&lt;/h3&gt;

&lt;p&gt;Ever heard of the term open-source? Open-source software is software projects that allow for contributions from anyone. Contributions to an open-source project come in many forms. If you are a highly skilled engineer that has an interest in the project, you may contribute your time to help develop the project altogether. Otherwise, you can usually support the project maintainers by donating money to them directly.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In this culture sharing is the norm. We contribute to the field and everyone in it while being open and transparent about it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even though software engineering has an open culture it doesn’t mean plagiarism would be left unchecked, don’t ever steal someone else’s source code and claim it as your own.&lt;/p&gt;

&lt;p&gt;Originality is always appreciated!&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Mentorship Is Essential
&lt;/h3&gt;

&lt;p&gt;My first years as a software engineer began with mentorship. I entered a trainee program to make apps that solve real-world problems while learning.&lt;/p&gt;

&lt;p&gt;It was one of the most formative years of my life. I have always wondered how my life would be like after my trainee years have passed. It has been 2 years since then, I can say it helped me through a lot.&lt;/p&gt;

&lt;p&gt;Just as in any field, mentorship gives you a boost in learning. It helps you skim through the less important skills and gives you an insight into what skills you need to improve to reach your end goal.&lt;/p&gt;

&lt;p&gt;It is completely forgivable if you don’t know what role you would be focusing on specifically. Precisely why every new software engineer should go through some sort of mentorship with more senior software engineers, to help them go learn faster.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For example, a backend engineer does not necessarily need to learn artificial intelligence. Though it might be a useful skill, there are more important things at hand.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  5. Sharing Helps You Learn Too
&lt;/h3&gt;

&lt;p&gt;Some people might not know this, but sharing helps you learn. When you are sharing what you know with other people, you get the chance to review your knowledge and probably patch holes in your knowledge that previously was unbeknownst to you.&lt;/p&gt;

&lt;p&gt;Sharing also gives you the opportunity of being questioned by inquiring minds. As the saying goes, &lt;em&gt;“Two heads are better than one”&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you encounter a question that you have never thought about, you gain a plus there. A new insight.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When given the responsibility of sharing your knowledge, of course, you want to perform your best. You should be aware of the big responsibility of teaching. You wouldn’t want to disappoint. Given, it would improve your sense of responsibility to your own words.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;So you think you are ready for the tech world? Don’t ever be afraid to ask for help. It is completely normal to not know about somethings in this field. You don’t have to be the know-it-all.&lt;/p&gt;

&lt;p&gt;Be humble! It may be one of the most important traits you would ever need. If you know something your desk neighbor doesn’t it wouldn’t hurt to share a bit. Being a mentor can get you further than you would ever expect.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>productivity</category>
      <category>performance</category>
      <category>career</category>
    </item>
    <item>
      <title>Thoughts About Being A Software Project Manager</title>
      <dc:creator>Agustinus Theodorus</dc:creator>
      <pubDate>Fri, 26 Jun 2020 20:48:29 +0000</pubDate>
      <link>https://dev.to/agustinustheo/thoughts-about-being-a-software-project-manager-bp7</link>
      <guid>https://dev.to/agustinustheo/thoughts-about-being-a-software-project-manager-bp7</guid>
      <description>&lt;p&gt;A few months ago I had an initiative that I have been wanting to realize. In the company that I have been working in, there seems to be a lack of documentation for teaching and no media for knowledge sharing between teams. I thought that there has to be one, for the better of us all.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pFrQys28--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2AhDkrdgngAzgKZn0T" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pFrQys28--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/0%2AhDkrdgngAzgKZn0T" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Background
&lt;/h3&gt;

&lt;h4&gt;
  
  
  The Initiative
&lt;/h4&gt;

&lt;p&gt;So I approached HR and proposed this project. To help people learn. Since I work on a university campus, I thought it might be a good idea to have the learning management system (or &lt;em&gt;LMS&lt;/em&gt; for short) be available to the students there as well.&lt;/p&gt;

&lt;p&gt;Well, that was the initial plan. As all software engineer knows, when it came up to requirement gathering the requirements were not really exactly what I wanted. It was less of an LMS and more of an HR information system.&lt;/p&gt;

&lt;p&gt;Well, I didn’t mind. The LMS part of the system is still there, and I think that’s good enough as a start.&lt;/p&gt;

&lt;p&gt;So a month in, the requirements were accepted by the user. Resources have also been allocated for my project.&lt;/p&gt;

&lt;p&gt;Initially, I had a team of 3 people. It was me and two other guys. They bailed after knowing the project was going to use a new tech-stack they have never used before.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;”Well…”&lt;/em&gt;, I thought, &lt;em&gt;“It’s back to square one”&lt;/em&gt;. Luckily for me a year prior I was one of the interviewers for some of the new trainees.&lt;/p&gt;

&lt;h4&gt;
  
  
  Gathering the crew
&lt;/h4&gt;

&lt;p&gt;It was surely a stroke of luck that my relationship with the trainees was on good terms.&lt;/p&gt;

&lt;p&gt;I met one of them a year ago when I was active as an activist at my Uni, and I interviewed the other one. So, I figured they would like to have an opportunity.&lt;/p&gt;

&lt;p&gt;When it came the time to ask. I breathed a sigh of relief after they said that they were interested.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A third person joined after he heard about the project from his friend, interestingly enough.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I orchestrated the first meeting between the four of us. At the beginning of the meeting, I said that it will be an opportunity for them to learn new skills. Since I was going for a relatively modern tech-stack (for the year 2020). A Vue frontend and a .NET Core backend.&lt;/p&gt;

&lt;p&gt;Just like that — &lt;em&gt;the project was on&lt;/em&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Happily ever after — sort of…
&lt;/h4&gt;

&lt;p&gt;The three trainees’ main responsibilities would be code, my responsibilities were more — &lt;em&gt;many more&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Sure I tried to do project management by the book. I used a virtual board on Azure DevOps to list all the requirements, and I also arranged weekly meetings to calculate the project’s velocity.&lt;/p&gt;

&lt;p&gt;I thought that would be enough — &lt;em&gt;boy was I wrong&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;First of all, I may have relied on the trainees a little bit too much and I needed to back them up more than I thought. &lt;em&gt;I am not blaming them, it was my fault for not considering their skills thoroughly.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Second, I think my requirement gathering skills have a &lt;em&gt;lot&lt;/em&gt; of room to improve. I analyzed a few features wrong and came up with very conflicting results — &lt;em&gt;I had to clean this up in the end, it was my fault after all&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So here I am being a project manager, guiding the trainees, fixing all my requirements, talking to the &lt;em&gt;techies&lt;/em&gt; in my company making sure everything was safe, secure, and best practice. Boy… that was an experience.&lt;/p&gt;

&lt;p&gt;I honestly felt bad for the people I led because they might be more confused than I am. Though I always try my best to help them solve their problems. I did promise them that they would learn something and I really meant it.&lt;/p&gt;

&lt;h3&gt;
  
  
  What I’ve learned
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Mistakes made
&lt;/h4&gt;

&lt;p&gt;I have been a programmer for 3 years now and I think it’s about time I led my own team. I won’t lie that it was neither easy or relaxing. It was a stressful experience with many mistakes made along the way.&lt;/p&gt;

&lt;p&gt;I was lucky that my team was made out of trainees eager to learn, thus they still continued on through my less than average project management skills.&lt;/p&gt;

&lt;p&gt;It was a learner though.&lt;/p&gt;

&lt;p&gt;After being a project manager I now can grasp what needs to be done by a project lead, or team lead. This is why those roles have less programming and require more time to &lt;em&gt;literally&lt;/em&gt; manage the ongoing project.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Good project management can be done if the person in charge is focused on doing so.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I was a little to stretched thin at that moment. I needed to help trainees solve problems that they couldn’t while considering the project and safety of the entire codebase.&lt;/p&gt;

&lt;p&gt;It was a real hassle.&lt;/p&gt;

&lt;p&gt;I don’t want to say that I was busy, rather that I could not focus on what I should have done, managing the project.&lt;/p&gt;

&lt;p&gt;System analyzing wise, I can confidently say that — I suck at it, still a long way to go.&lt;/p&gt;

&lt;p&gt;I didn’t have a good design doc to look up, only a few notes on how it would be made. So I have to &lt;em&gt;read&lt;/em&gt; what I wanted to do, probably a user diagram would be helpful or an application flow diagram.&lt;/p&gt;

&lt;p&gt;I know that this is software project 101 but I am honestly saying that I missed that. &lt;strong&gt;I really blew it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ItqY5X6n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/500/0%2AYNrrfiMSoLTXJprW.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ItqY5X6n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/500/0%2AYNrrfiMSoLTXJprW.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now look at this diagram, can you imagine the number of roles needed when we want to create this application? It is written on the diagram and it is as clear as day.&lt;/p&gt;

&lt;p&gt;Now imagine having no diagram and trying to understand this system by writing. Better yet, try to translate this diagram into a paragraph. Good luck! I didn’t make this and it made me forget what I wanted to do indefinitely. A big lesson learned.&lt;/p&gt;

&lt;p&gt;Feature-wise there should be a clear application flow to explain how the system works, how the users register, and so on.&lt;/p&gt;

&lt;p&gt;Sadly I also didn’t make it. It contributed to the disarray of the trainees under my wing. It showed how a project with good intentions became a complicated one at best. &lt;em&gt;“If only”&lt;/em&gt;, I said to my self, &lt;em&gt;“I have done this”&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--s7xFGv00--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/600/0%2AFYeIWVNRO6-pQtHW.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--s7xFGv00--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/600/0%2AFYeIWVNRO6-pQtHW.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I used waterfall as the software development lifecycle because the requirements were constant and the user wasn’t much of a hassle.&lt;/p&gt;

&lt;p&gt;This further amplified my mistakes because — &lt;em&gt;waterfall absolutely needs these kinds of diagrams.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The requirements were constant and might as well made diagrams from the beginning to help understand the system beforehand.&lt;/p&gt;

&lt;p&gt;If I were to use agile however my huge mishap might be forgiven &lt;em&gt;a little bit&lt;/em&gt;. Because if you were to use agile even though an initial design doc is &lt;em&gt;very important&lt;/em&gt;, the requirements are fluid thus you might have no time to keep making a design doc and must continue on programming to finish the project before a deadline.&lt;/p&gt;

&lt;p&gt;I am not saying that a design doc is not important, not by a long shot. I am just trying to imply that the requirements are fluid and you might be forgiven for making a design doc that is slightly different from the end product.&lt;/p&gt;

&lt;h4&gt;
  
  
  A Realization
&lt;/h4&gt;

&lt;p&gt;I realized why it is important that project management roles shouldn’t be too caught up in programming. There are a lot of things that need to be arranged by a project manager, like making a design doc and managing the team’s workload.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Deep respect to all project managers out there doing it well.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Of course, in the end, it is not all about the project rather the interactions with the people in the team are very important.&lt;/p&gt;

&lt;p&gt;In regard to this aspect, I feel that I have done a good job. My relationship with the trainees I led has nothing but improved. We communicate more, we are able to joke together as friends. I am able to teach them and communicate my thoughts with them clearly.&lt;/p&gt;

&lt;p&gt;In my opinion, I think socially I am already viable enough. Communication with higher-ups and other teams were also great.&lt;/p&gt;

&lt;p&gt;In the end, the project is planned to have its phase 2 of development. I have other projects so I will not be continuing my role. Thus, the role of the project manager will fall to someone else.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In conclusion, I really enjoyed the opportunity to lead my own project. It really helped me understand the flaws I have in leadership and gave me a path to further improve myself.&lt;/p&gt;

&lt;p&gt;The company received the project well since they plan on having a phase 2 to further develop it, making it into something better.&lt;/p&gt;

&lt;p&gt;Being the initiator is truly a dream come true. To all the people who believed. Thank you. Mistakes were made, but from them, we learn new things. On that note, here is a good quote to end it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The master has failed more times than the beginner has tried&lt;/strong&gt; - Stephen McCranie&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>watercooler</category>
      <category>discuss</category>
      <category>career</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
