<?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>Forem: Sakir Temel</title>
    <description>The latest articles on Forem by Sakir Temel (@sakirtemel).</description>
    <link>https://forem.com/sakirtemel</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%2F989092%2F289bead6-9a79-470a-996e-b50b9a76298e.png</url>
      <title>Forem: Sakir Temel</title>
      <link>https://forem.com/sakirtemel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sakirtemel"/>
    <language>en</language>
    <item>
      <title>How to Communicate Your Process Visually using BPMN as Code</title>
      <dc:creator>Sakir Temel</dc:creator>
      <pubDate>Mon, 23 Jan 2023 17:50:41 +0000</pubDate>
      <link>https://forem.com/kelebeklabs/how-to-communicate-your-process-visually-using-bpmn-as-code-4377</link>
      <guid>https://forem.com/kelebeklabs/how-to-communicate-your-process-visually-using-bpmn-as-code-4377</guid>
      <description>&lt;p&gt;&lt;em&gt;When you have multiple participants in a process, and we often do, you realize that you're dealing with a lot of miscommunication / misalignment issues. It's so hard to remember who was doing what and when, furthermore it's even harder to make some optimization in the process itself as you lose the control over it.  Besides you'll need to group all the participants together for them tell their opinions.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Processes are long and complex, but they're there even if you don't formalize them. So, why don't we find a way to approach it in an easy way? First thing each of us would do in such a situation is drawing some boxes and lines, a.k.a. diagrams. Today, we're going to talk about ways of drawing some diagrams, in a comprehensive yet simple way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Business Process Model and Notation (BPMN)
&lt;/h2&gt;

&lt;p&gt;BPMN diagram is like &lt;a href="https://en.wikipedia.org/wiki/Flowchart"&gt;Flowchart&lt;/a&gt;, but the tasks (activities) are grouped by the participants. It can be drawn / read by both business or technical people as the main purpose is to &lt;strong&gt;communicate a process in a simple yet complete way&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---zTMJNDf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bqidzymuw6tjs88k0ozk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---zTMJNDf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bqidzymuw6tjs88k0ozk.png" alt="Simple BPMN diagram for pizza ordering" width="880" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;BPMN is actually a &lt;a href="https://www.bpmn.org/"&gt;set of standards&lt;/a&gt; has been used for years for complex enterprise processes, and nowadays it's becoming more accessible thanks to the development of the new techniques. Web based tooling (like &lt;a href="https://camunda.com/"&gt;Camunda&lt;/a&gt;, &lt;a href="http://bpmn.io/"&gt;BPMN.io&lt;/a&gt;), more &lt;a href="https://github.blog/2022-02-14-include-diagrams-markdown-files-mermaid/"&gt;platforms supporting integrating diagrams into the flows&lt;/a&gt;, and remote work culture all helps us to use BPMN easier. Besides all of that, we drive/lead more and more initiatives together and we're keep looking for the efficiency and improvement.&lt;/p&gt;

&lt;p&gt;I started to see more and more teams are formalizing their development / pull request flows. Many of them are going with a very long, not up-to-date flowchart diagrams just to keep the things "simple" and not require learning any better suited specifications like BPMN. It's a fair tradeoff, but at the end, it makes these diagrams not serving to their purposes. We should rather prefer solutions that makes BPMN diagrams more friendly, and super easy to learn/draw.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diagram as Code
&lt;/h2&gt;

&lt;p&gt;Diagram as Code is a trending concept that automatically generates diagrams from a simple text/code. Some of the pioneers are &lt;a href="https://plantuml.com/"&gt;PlantUML&lt;/a&gt;, &lt;a href="https://mermaid.js.org/"&gt;Mermaid&lt;/a&gt; and &lt;a href="https://kroki.io/"&gt;Kroki&lt;/a&gt;. It has several great benefits like having your architecture diagrams close to your code and your development flow. If you want to learn more about it, there's a &lt;a href="https://www.slideshare.net/sakirtemel/diagrams-as-code"&gt;presentation&lt;/a&gt; that covers main benefits in action.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Xx7vutnR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vcjpmqjnrvgkdu8ron3k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Xx7vutnR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vcjpmqjnrvgkdu8ron3k.png" alt="Visualization of Diagram as Code with PlantUML" width="880" height="651"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  BPMN as Code with BPMN Sketch Miner
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.bpmn-sketch-miner.ai/"&gt;BPMN Sketch Miner&lt;/a&gt; is a rapid sketching tool for BPMN process models, you just write it as you're telling a story. They also have a great BPMN tutorial to make understanding of BPMN easier.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--78zCJz9K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8xd9cb1hnr37crwm06b4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--78zCJz9K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8xd9cb1hnr37crwm06b4.png" alt="Simple BPMN diagram for pizza ordering with using BPMN Sketch Miner" width="880" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Waiter, Chef, Customer are the &lt;strong&gt;roles&lt;/strong&gt; defined as &lt;a href="https://www.bpmn-sketch-miner.ai/doc/02-pools.html#pool-task-annotation"&gt;Lanes&lt;/a&gt;, the yellow rectangles are &lt;a href="https://www.bpmn-sketch-miner.ai/doc/01-tasks.html"&gt;Tasks&lt;/a&gt;, the circles are &lt;a href="https://www.bpmn-sketch-miner.ai/doc/04-events.html#start-and-end-events"&gt;Events&lt;/a&gt;, the arrows are the &lt;a href="https://www.bpmn-sketch-miner.ai/doc/05-message-flow.html"&gt;Flows&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Since we learnt the basics, we can &lt;strong&gt;just start&lt;/strong&gt; drawing of one of our processes &lt;strong&gt;!&lt;/strong&gt; Sounds a bit strange, right? BPMN as a set of standards seems complex to learn because it has &lt;a href="https://www.bpmn.org/"&gt;hundreds of elements&lt;/a&gt; that allows us to map almost any situation in the real world, but do we need all of them to start? To me, it's very similar to when we learn programming languages, you don't need to know / apply the best of the bests to be able to create an application, you know that you can continuously improve your codebase later on. Since now we're &lt;strong&gt;storing our diagrams as code in our codebases&lt;/strong&gt;, the same rule applies! Just start mapping a process that you believe it can be helpful for your team to have it visualized.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using more features of BPMN
&lt;/h3&gt;

&lt;p&gt;Here you can see how you can evolve the diagram above by using a few more elements of BPMN.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4QSBYeFO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kt83uoqghhvbekdmyuzb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4QSBYeFO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kt83uoqghhvbekdmyuzb.png" alt="Evolved BPMN diagram for pizza ordering with using BPMN Sketch Miner" width="880" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://www.bpmn-sketch-miner.ai/doc/04-events.html#start-and-end-events"&gt;Start and End events&lt;/a&gt; are &lt;strong&gt;labeled&lt;/strong&gt;, used &lt;a href="https://www.bpmn-sketch-miner.ai/doc/04-events.html#timer"&gt;Timer event&lt;/a&gt; to represent delay, &lt;a href="https://www.bpmn-sketch-miner.ai/doc/03-gateways.html#exclusive-gateways"&gt;Exclusive Gateway&lt;/a&gt; is used to &lt;strong&gt;branch&lt;/strong&gt; for &lt;strong&gt;alternative paths&lt;/strong&gt;, Loop is used for repeated actions.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Another great thing I use in BPMN is the &lt;a href="https://www.bpmn-sketch-miner.ai/doc/06-data.html#data-flow"&gt;Data and Message Flow&lt;/a&gt;, it clearly describes who needs what and when, and where it's generated at. This is one of the biggest ambiguity in the processes and often it's missed because of the assumptions. BPMN helps us to explicitly talk about that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9pznLdkp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e3bv3fx7wmp8hglr0kha.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9pznLdkp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e3bv3fx7wmp8hglr0kha.png" alt="BPMN diagram for job application process using BPMN Sketch Miner" width="880" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://www.bpmn-sketch-miner.ai/doc/04-events.html#message"&gt;Message Events&lt;/a&gt; are used to represent what's &lt;strong&gt;received or sent&lt;/strong&gt; with the tasks, &lt;a href="https://www.bpmn-sketch-miner.ai/doc/06-data.html"&gt;Data objects&lt;/a&gt; used to show inputs and outputs of the tasks. &lt;a href="https://www.bpmn-sketch-miner.ai/doc/06-data.html#data-flow"&gt;Data Flow&lt;/a&gt; is used to describe how the data is processed throughout the process.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Mapping our processes
&lt;/h3&gt;

&lt;p&gt;Imagine you'd like to describe what's &lt;a href="https://www.bpmn-sketch-miner.ai/examples/demos-10-16-appstore.html"&gt;the journey of your feature&lt;/a&gt; from being developed to customers using that. You may want this to cooperate with marketing department for them to understand better which steps are there and they can align, you can use it for your new team members to onboard them faster, or you can use it for a brainstorming session with different experts to see if there's a way to optimize the process. Either way, just start drafting something and live-edit it during your meeting.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Kc63EUVf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/thp75640c4te4qyr5ntu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Kc63EUVf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/thp75640c4te4qyr5ntu.png" alt="BPMN diagram for application publishing process with using BPMN Sketch Miner" width="880" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  BPMN Sketch Miner VSCode Extension
&lt;/h3&gt;

&lt;p&gt;There's a &lt;a href="https://marketplace.visualstudio.com/items?itemName=s-v-o.bpmn-sketch-miner"&gt;VSCode Extension&lt;/a&gt; to integrate BPMN Sketch Miner to your development flow easily. I often store them under &lt;em&gt;docs/diagrams/source/process_name.sketchminer&lt;/em&gt; and the png versions at &lt;em&gt;docs/diagrams/out/process_name.png&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZbLO_WWh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bnv7b6a46lcgty2lde7q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZbLO_WWh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bnv7b6a46lcgty2lde7q.png" alt="BPMN Sketch Miner VSCode Extension" width="880" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Further thoughts
&lt;/h2&gt;

&lt;p&gt;Visually expressing our thoughts or new processes engages people more and allows going more efficient in our discussions. &lt;a href="https://www.bpmn.org/"&gt;BPMN&lt;/a&gt; is the language of the processes and it's good to speak this language, and even daily basis. This article covered how to start doing that, of course there'll be a lot of development opportunities on the go, a few of them are; how to use it in our git flow, using BPMN files as an outcome to auto generate forms etc, allowing teams to describe their internal or external facing processes in an efficient manner. Note that the diagrams help with having shorter and interesting meetings, async work, less regression of the established practices, and less resistance of a change. Feel free to &lt;a href="https://www.kelebeklabs.com/contact"&gt;contact us&lt;/a&gt; if you encounter any of the opportunities, always happy to share our practices.&lt;/p&gt;

</description>
      <category>diagram</category>
      <category>team</category>
      <category>productivity</category>
      <category>engineering</category>
    </item>
    <item>
      <title>Linode, Firewall, Cloudflare Full (Strict) with Terraform Cloud</title>
      <dc:creator>Sakir Temel</dc:creator>
      <pubDate>Wed, 21 Dec 2022 20:38:19 +0000</pubDate>
      <link>https://forem.com/kelebeklabs/linode-firewall-cloudflare-full-strict-with-terraform-cloud-2h6m</link>
      <guid>https://forem.com/kelebeklabs/linode-firewall-cloudflare-full-strict-with-terraform-cloud-2h6m</guid>
      <description>&lt;p&gt;&lt;em&gt;You built your application and now looking for a way to deploy it with a managed security? You'd like to have a simple yet powerful enough solution that can extend later on? We have an example web server setup in this article that provides you that. At KelebekLabs, whenever we choose to go with a basic server setup, not PaaS or Kubernetes, we follow these principles.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.cloudflare.com/en-gb/application-security/"&gt;Cloudflare Application Security&lt;/a&gt; gives us a lot of services &lt;strong&gt;for free&lt;/strong&gt;, such as DDoS protection, managing bad bots, rate limiting, free SSL certificate and many others. What we need to do is to make sure all the connections to our servers are going &lt;strong&gt;through Cloudflare and only.&lt;/strong&gt; We're going to configure a firewall at our server provider side to make sure we &lt;strong&gt;only allow connection from Cloudflare&lt;/strong&gt; so that the people who knows our IP address won't be able to bypass our security. You can think this as almost hiding your servers from the internet as &lt;strong&gt;Cloudflare will be the only door&lt;/strong&gt; to your servers. In our example, we use &lt;a href="https://www.linode.com/pricing/#compute-shared"&gt;Linode&lt;/a&gt;, a developer friendly, low cost cloud provider.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--olhc8c5S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j7olzehgd45xo00mro52.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--olhc8c5S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j7olzehgd45xo00mro52.png" alt="Linode cloudflare full strict ssl diagram" width="880" height="204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead of setting up the things manually at Linode, we're using Terraform, and to manage that we're using &lt;a href="https://cloud.hashicorp.com/products/terraform"&gt;Terraform Cloud&lt;/a&gt;. In this article, you'll learn to set it up easily.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TTRKk2_k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hytuncan0c9sai45iloa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TTRKk2_k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hytuncan0c9sai45iloa.png" alt="Terraform cloud basics" width="880" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing for Infrastructure as Code
&lt;/h2&gt;

&lt;p&gt;We need a place where we're going to define our infrastructure, how many servers we have, what are their sizes, their connections in between etc. You can just create a new private repository on Github, or you can create a folder in your existing project. I prefer the second option as I like the monorepo more, so just create a readme file under &lt;strong&gt;terraform&lt;/strong&gt; directory in your codebase.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zSFae5qA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ns0v4lb157gcxkcjsv1c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zSFae5qA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ns0v4lb157gcxkcjsv1c.png" alt="Terraform folder structure" width="880" height="94"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Terraform Cloud
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://cloud.hashicorp.com/products/terraform"&gt;Terraform Cloud&lt;/a&gt; is an amazing service by HashiCorp with a free pricing option that helps you to ease your Terraform journey. It automatically connects to your repository, keeps the terraform state(the last state of your infrastructure, how many serves were created etc) for you, helps you to have your environment variables for you in their UI. Just &lt;a href="https://app.terraform.io/signup/account"&gt;create an account&lt;/a&gt; (you can use login via GitHub if you click on Continue via HCP) and then create a workspace, which is basically your system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--J4r-p2qi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o78mi681m1dnfu8pd8m0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--J4r-p2qi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o78mi681m1dnfu8pd8m0.png" alt="Terraform cloud new workspace" width="880" height="562"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4As9GZFu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i4r776flg4n6jbcjvu4i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4As9GZFu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i4r776flg4n6jbcjvu4i.png" alt="Terraform cloud choose subdirectory" width="880" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember the option we talked about earlier, creating a folder in a repo, you can specify it while you're creating a workspace. Congratulations, you now have an automation, doing any changes under terraform directory will generate a new terraform plan.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generating a Linode Token for Terraform Cloud
&lt;/h3&gt;

&lt;p&gt;We need to give permission to Terraform Cloud to create servers for us on Linode. We're going to do that via personal API tokens.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;WARNING: Terraform will create servers, make sure that you're aware of what's created and how much does it cost for you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can create an API token by going to &lt;a href="https://cloud.linode.com/profile/tokens"&gt;API tokens page&lt;/a&gt; under My Profile.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xpw0LRem--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4hrqnh8ghkbnek4jepyb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xpw0LRem--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4hrqnh8ghkbnek4jepyb.png" alt="Linode api tokens page" width="880" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RObe9dDH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j3t5f8xwxd47mjxm79w1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RObe9dDH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j3t5f8xwxd47mjxm79w1.png" alt="Linode create an api token page" width="880" height="283"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you get the token, add this as an environment variable in our Workspace at Terraform Cloud. Great, now Terraform Cloud can do operations on Linode.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cloudflare SSL
&lt;/h2&gt;

&lt;p&gt;As mentioned at the beginning, Cloudflare protects our system from various problems. We're now going to focus on the connection between &lt;strong&gt;Cloudflare -- Linode.&lt;/strong&gt; Cloudflare generates an SSL certificate that is called Origin Server (Linode is our Origin Server in this case) certificates that ensures the connection between Cloudflare and Linode is fully secure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_SM30zzT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pgxovgoeaizywdhcd9cd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_SM30zzT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pgxovgoeaizywdhcd9cd.png" alt="Cloudflare SSL full strict" width="880" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Assuming that your &lt;a href="https://developers.cloudflare.com/dns/zone-setups/full-setup/setup/"&gt;DNS is already managed by Cloudflare&lt;/a&gt;, we can begin to make our configuration there. Create an Origin Server certificates by providing your domain name. The generated certificate will only be used between Cloudflare to Linode, real users won't be aware of it at all.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eLAXWk4---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gcrkuiq2ao14v23dcqa0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eLAXWk4---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gcrkuiq2ao14v23dcqa0.png" alt="Cloudflare create an origin certificate" width="880" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After creating the certificates, copy them as terraform variables in your Workspace variables pages at Terraform Cloud. Copy Private Key as &lt;strong&gt;SSL_CERTIFICATE_KEY&lt;/strong&gt; and the other as &lt;strong&gt;SSL_CERTIFICATE.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_hudNbOy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qive81uand5454itpq3a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_hudNbOy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qive81uand5454itpq3a.png" alt="Cloudflare SSL key" width="880" height="548"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4nPwGuhG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/imlf1ect2nvxs9vkvhp5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4nPwGuhG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/imlf1ect2nvxs9vkvhp5.png" alt="Cloudflare SSL in Terraform Cloud" width="880" height="124"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you have all the necessary configuration ready, you'll be able to access these keys in your server and use them in your web server configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Provision with Terraform
&lt;/h2&gt;

&lt;p&gt;It's time for coding our infrastructure, you should put these IaC (Infrastruce as Code) files in your terraform folder. Once you commit them to your repository, you'll see a plan in your Terraform Cloud waiting for your approval. Once you approve your plan, Terraform is going to create an Ubuntu server for you with a simple init script, configure the firewall to only allow connections through Cloudflare and injects the SSL certificate keys as files.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Deploy your application
&lt;/h3&gt;

&lt;p&gt;Now you have your server up and running, go to Linode console to access to your server via &lt;a href="https://www.linode.com/docs/guides/lish/"&gt;Lish Console&lt;/a&gt;, it's a secure way to access to your server. Clone your application server and configure your nginx. There's an example nginx configuration attached as nginx.conf. This part is left out on purpose as the deployment can be different for everyone.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure your DNS with your server's IP address
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;This part is a bit hacky for my case, if I find a better option, I'll update the article.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So, since we have our Linode server up and running, get its IP Address and add this as an A record with Proxy on option on Cloudflare. Now you should be able to send a request to your server in a secure way.&lt;/p&gt;

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

&lt;p&gt;We learnt how to programmatically provision our infrastructure with a basis of production grade security in a high level perspective. This gives us a peace of mind as we know we're protected from most of the basic attacks. Now we can learn more how to configure our Cloudflare better, how to improve our Application level security, go through &lt;a href="https://owasp.org/www-project-top-ten/"&gt;OWASP Top 10&lt;/a&gt;,  organizational security principles etc. Building Secure applications is key for Reliability, Reliable applications boosts customers' and the developers' happiness. We'd like to be a part of this message by sharing our knowledge, so please reach out to us if you find any difficultly or anything wrong in this article.&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>security</category>
      <category>webdev</category>
      <category>api</category>
    </item>
    <item>
      <title>Load Testing with Ruby-JMeter</title>
      <dc:creator>Sakir Temel</dc:creator>
      <pubDate>Wed, 21 Dec 2022 19:01:12 +0000</pubDate>
      <link>https://forem.com/kelebeklabs/load-testing-with-ruby-jmeter-1h3i</link>
      <guid>https://forem.com/kelebeklabs/load-testing-with-ruby-jmeter-1h3i</guid>
      <description>&lt;p&gt;&lt;em&gt;You're ready for your product's launch, you'd like to show your customers finally there's a solution for their pain. You expect 1000 people using your service per hour, you made all the calculations and somehow you're confident. But, are you? Load Testing is here to simulate the traffic, 1000 people using your service per hour, and increase your confidence on launch day(and after).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The story for FolderCode, a temporary file uploading service, was exactly like above, and just to show how it was addressed in its backlog, see the picture below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q16kQCwm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/746actgv50bvchsgbkwg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q16kQCwm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/746actgv50bvchsgbkwg.png" alt="Product backlog item" width="880" height="301"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Designing your JMeter Test Plan
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://jmeter.apache.org/"&gt;JMeter&lt;/a&gt; is a well-known tool for load or stress testing, it basically sends requests to your application within the given time, according to the behaviour plan you provided. The plans are designed to be detailedly configurable and focused on load-testing jargon. That makes the JMeter a comprehensive solution, however makes it a bit hard to understand &amp;amp; focus on the well written tests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NFPtbFow--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z882dnilluutzm99r2i2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NFPtbFow--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z882dnilluutzm99r2i2.png" alt="JMeter plan example" width="219" height="171"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here comes the &lt;a href="https://github.com/flood-io/ruby-jmeter"&gt;ruby-jmeter&lt;/a&gt;! An easy to use tool that helps you to write readable test plans, which leads to focusing on your simulator scenarios to become closer to real customer behaviours. Under the hood, it uses JMeter. The code below simulates 10 customers keep visiting Google while its being run.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iHPkaFu1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w6ar9jfkqvefa5ddbwn5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iHPkaFu1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w6ar9jfkqvefa5ddbwn5.png" alt="Ruby-JMeter example" width="880" height="193"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing our Dashboards to observe our Product's behaviour
&lt;/h2&gt;

&lt;p&gt;Before we start sending some traffic to simulate the launch day, do you already monitor your system? If not, you should! Some basic things like traffic, CPU, memory, and also some functional metrics, for example our case was how many files are being uploaded. Create a dashboard where you can easily watch the vital signs of your system.&lt;/p&gt;

&lt;p&gt;You'll find so many things that weren't ready in your dashboard as you were focusing on the developing particular features not overall system's behaviour. This is actually a great benefit of preparing for a load testing.&lt;/p&gt;

&lt;p&gt;We used &lt;a href="https://newrelic.com/resources/datasheets/new-relic-one"&gt;New Relic One&lt;/a&gt; and &lt;a href="https://docs.newrelic.com/docs/apm/agents/manage-apm-agents/agent-data/collect-custom-metrics/"&gt;custom metrics&lt;/a&gt;, it has a free plan, complete feature-set and easy to use interface.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eBh9V79S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a2vpoy2s1x0ivgoka1tk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eBh9V79S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a2vpoy2s1x0ivgoka1tk.png" alt="NewRelic One app metrics" width="880" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3LauybRC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d4ipqe6cdoptp7pepszo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3LauybRC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d4ipqe6cdoptp7pepszo.png" alt="NewRelic One infra metrics" width="880" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You should design some alerts for non-desired values such as storage usage should never reach to 70%.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Let's send some traffic!!
&lt;/h2&gt;

&lt;p&gt;That's the most fun part, sending the traffic with using JMeter and watching the vitals of our system. It's as exciting as the product launch, if not more. While the script is being run, for 2 minutes as configured, you can watch the metrics are changing on your dashboard.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  Analyzing the results
&lt;/h2&gt;

&lt;p&gt;Did you have receive any errors during the simulation?&lt;br&gt;
Customers' latency was increasing? Increased latency gives worse customer experience.&lt;br&gt;
Did any request fail?&lt;br&gt;
Did you find any additional vital sign that should be monitored?&lt;br&gt;
Do you need to make some infrastructure modifications?&lt;br&gt;
Are you now confident that your system can handle the pre-calculated load without any increased latency?&lt;/p&gt;

&lt;p&gt;Show your team your results! I was so happy to see that uploading ~1000 files in 2 minutes caused no issue to our system. Now you should have a validated confidence over your system. Make sure that you save your JMeter code in you repositories for reuse and improving the test plan!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5Q99YCI0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/knk7xotvignnfbtmm5nn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5Q99YCI0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/knk7xotvignnfbtmm5nn.png" alt="NewRelic One dashboard for load testing results" width="880" height="456"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can run the load tests periodically to stay confident over your system especially for the critical parts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Reference links
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.blazemeter.com/blog/jmeter-performance-testing"&gt;https://www.blazemeter.com/blog/jmeter-performance-testing&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.blazemeter.com/blog/performance-testing-vs-load-testing-vs-stress-testing"&gt;https://www.blazemeter.com/blog/performance-testing-vs-load-testing-vs-stress-testing&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>performance</category>
      <category>api</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Using Notion as a Content Management System (CMS) for your applications</title>
      <dc:creator>Sakir Temel</dc:creator>
      <pubDate>Wed, 21 Dec 2022 18:50:39 +0000</pubDate>
      <link>https://forem.com/kelebeklabs/using-notion-as-a-content-management-system-cms-for-your-applications-4ald</link>
      <guid>https://forem.com/kelebeklabs/using-notion-as-a-content-management-system-cms-for-your-applications-4ald</guid>
      <description>&lt;p&gt;&lt;em&gt;Recently while developing GarajApp, a car magazine app, we had a need to use a CMS to add content such as News, Campaigns and static pages like Guides. We considered several options like Strapi, Contentful or even implementing a simple enough markdown editor with WYSIWYG editor.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing the right CMS
&lt;/h2&gt;

&lt;p&gt;Founder of GarajApp tried using Strapi earlier and it ended up a maintenance burden with updates, errors, and not-so-easy development flow. We needed something simple enough, yet production ready. We just needed to serve some content from our database to the mobile app, how hard it could be?&lt;/p&gt;

&lt;p&gt;We were leaning towards implementing a very simple page with a good WYSIWYG editor, perhaps with markdown support, that simply retrieves a page record and updates when we click save. It really looked easy but we had some concerns like adding a login, uploading the photos, managing the pages etc. Ok, so it wasn't so easy, then should we go with a full-scale content management system that supports a looot of things?&lt;/p&gt;

&lt;p&gt;During a weekly brainstorming session, we threw the idea of using Notion! Notion has a great user experience when you edit or organize content, it has great permissions and login capabilities, and uploading images is so easy on that. We immediately started doing an end-to-end proof of concept, editing a page in Notion should be reflected in our mobile app within 10 minutes with using GraphQL(with Hasura engine).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_inEBn-G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zlwxzj4pe1so35p6xvlo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_inEBn-G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zlwxzj4pe1so35p6xvlo.png" alt="Using Notion as CMS architecture" width="504" height="249"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Proof of Concept
&lt;/h2&gt;

&lt;p&gt;We first created a page in Notion for News and an example item in it with adding a few columns.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Wsb3Wf7o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/meu8fkpaqfpbmieh1j4f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Wsb3Wf7o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/meu8fkpaqfpbmieh1j4f.png" alt="Notion as CMS page structure" width="880" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--i_5al0MW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ljp78tws9iltfss87nz5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i_5al0MW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ljp78tws9iltfss87nz5.png" alt="Notion as CMS page content" width="880" height="801"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notion has an API that gives the list of pages and the page content. &lt;a href="https://www.npmjs.com/package/@notionhq/client"&gt;We used Notion client for JavaScript&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now we need to run this script and call the API every 10 minutes with cron, can be more frequent if needed, and update the records in the database. Simply upserting the objects in fetchedNews to our news table in our database would be enough. We used Hasura as a backend in this project, so we just &lt;a href="https://hasura.io/docs/latest/mutations/postgres/upsert/"&gt;called the API with an upsert request&lt;/a&gt; with conflict on id field.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sII4RmOo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fssvhde65sagbps93lg5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sII4RmOo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fssvhde65sagbps93lg5.png" alt="Notion as CMS block example" width="880" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Making a GraphQL call to our Hasura engine, and we return the data! Now you can implement a code for transforming this Notion blocks to be displayable elements. You can implement a simple markdown generator or can just directly use the blocks in your code. We moved with implementing a module in iOS that converts these blocks into a display.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling the Images
&lt;/h2&gt;

&lt;p&gt;Here's the tricky part, image blocks are returning us URLs that expires. So, if we copy the blocks from Notion directly into our database, our users won't be able to see the images after 60 minutes. To solve this issue, we simply cloned the images to &lt;a href="https://www.npmjs.com/package/cloudinary"&gt;Cloudinary&lt;/a&gt; during importing our Notion pages and saving the Cloudinary URL into our database. This gave also a power over the images for us, so that we could implement different versions of the same images easily.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AG1Zwy0e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wot0x7wxza40rlnsh53j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AG1Zwy0e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wot0x7wxza40rlnsh53j.png" alt="Notion as CMS image block" width="880" height="255"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Production ready implementation
&lt;/h2&gt;

&lt;p&gt;To make this implementation production ready, we created 2 main pages like GarajDataStaging and GarajDataProduction. GarajDataProduction's data structure(columns and so on) is changed less frequently and controlled while doing any modification not to have any surprises. We also added Sentry to our script to make sure that our code is not failing. We haven't implemented any monitoring system for the code as the scope was too small, but feel free to include that, too.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6-E65GIs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/po4ppvo456xpzsg27omm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6-E65GIs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/po4ppvo456xpzsg27omm.png" alt="Notion as CMS production" width="880" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;It has been a great experience to use Notion as CMS, it's free and it has a great user experience. Simplifying the content management enabled us to develop the application smoothly, we were able to get real data during the development thanks to ease of using Notion. Not to forget to mention, Notion's blocks system gives a powerful yet organizable content with a great UI for modifying the content, which makes it a default choice over using HTML, markdown or a custom implementation.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>ios</category>
      <category>tutorial</category>
      <category>api</category>
    </item>
    <item>
      <title>Finding spikes in your plans</title>
      <dc:creator>Sakir Temel</dc:creator>
      <pubDate>Wed, 21 Dec 2022 18:39:07 +0000</pubDate>
      <link>https://forem.com/kelebeklabs/finding-spikes-in-your-plans-1lof</link>
      <guid>https://forem.com/kelebeklabs/finding-spikes-in-your-plans-1lof</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Spikes are for research, design, investigation, &lt;strong&gt;exploration&lt;/strong&gt;. The purpose is to gain necessary knowledge to better understand a task and to work on that.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Word definition
&lt;/h2&gt;

&lt;p&gt;The word spike comes from rock climbing activities. While climbing, we might stop to force a spike into the rock face, which is not actual climbing but by doing this we are making sure that future climbing will be smooth and easy.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Spikes as the Solution
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Problem: We have a lot of uncertainties in our plans&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It's demotivating when we're doing our &lt;strong&gt;tasks&lt;/strong&gt; and we don't even understand why we're demotivated before doing it&lt;/li&gt;
&lt;li&gt;We can't see the risks earlier, we can't say how long something will take&lt;/li&gt;
&lt;li&gt;We don't know if we should spend time on something, what happens if we won't need it at the end?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Solution: Let's use Spikes!&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We do the initial research early and our expectation is actually to "Learn" and "Understand" before we "Do" something&lt;/li&gt;
&lt;li&gt;Spikes allow us to focus on analyzing the risks, do exploration. The purpose of a spike is not "Doing" but &lt;strong&gt;Enabling&lt;/strong&gt; doing&lt;/li&gt;
&lt;li&gt;Work for researching is never lost, outcome of a research is knowledge 🧠. After the research we can say that we shouldn't do the task now, and we're still staying with knowledge.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Let's say there's a &lt;strong&gt;task&lt;/strong&gt; &lt;em&gt;Make a slideshow with taking 10 photos&lt;/em&gt;, how you can plan this? How long this will take? You can say taking photos will take ~2 hours, making slideshow ~5 / ~10 / ~15 hours? If you don't know which tool to use, if you know the tool but you never used it, how you can plan working with that tool? In these cases, we create a Spike and we call this as an &lt;strong&gt;Enabler&lt;/strong&gt;. You first do your Spike: "Research and make a slideshow with a few photos to decide which tool to use" and you &lt;strong&gt;timebox&lt;/strong&gt; it for 2 hours. After 2 hours, you have the enough knowledge of slideshow tools and enough understanding of your task. After your spike, it's better to refine your task once again as you know more now.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;KelebekLabs is doing R&amp;amp;D, it's likely to happen that we'll have a lot of Spikes.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If we knew what we were doing, it wouldn’t be called research. — Albert Einstein&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Best practices of a Spike&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spike to represent uncertainty&lt;/li&gt;
&lt;li&gt;Planning for both the spike and the resulting stories in the same iteration is sometimes risky&lt;/li&gt;
&lt;li&gt;Better to plan the spike first and then take the decisions on actual story&lt;/li&gt;
&lt;li&gt;Treat spike as a problem to be fixed, ideally shouldn't stay in the backlog for long&lt;/li&gt;
&lt;li&gt;Spikes are only used with research(or exploration and other activities above) and documentation of it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Spikes can be technical or functional;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Functional spikes&lt;/strong&gt; – They are used to analyze overall solution behavior and determine:&lt;/p&gt;

&lt;p&gt;How to break it down&lt;br&gt;
How to organize the work&lt;br&gt;
Where risk and complexity exist&lt;br&gt;
How to use insights to influence implementation decisions&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technical spikes&lt;/strong&gt; – They are used to research various approaches in the solution domain. For example:&lt;/p&gt;

&lt;p&gt;Determine a build-versus-buy decision&lt;br&gt;
Evaluate the potential performance or load impact of a new user story&lt;br&gt;
Evaluate specific technical implementation approaches&lt;br&gt;
Develop confidence about the desired solution path&lt;/p&gt;

&lt;h2&gt;
  
  
  Reference links
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.slideshare.net/GoAtlassian/spiking-your-way-to-improved-agile-development-anatoli-kazatchkov" rel="noopener noreferrer"&gt;https://www.slideshare.net/GoAtlassian/spiking-your-way-to-improved-agile-development-anatoli-kazatchkov&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.scaledagileframework.com/spikes/" rel="noopener noreferrer"&gt;https://www.scaledagileframework.com/spikes/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.c-sharpcorner.com/article/what-is-spike-in-agile-software-development2/" rel="noopener noreferrer"&gt;https://www.c-sharpcorner.com/article/what-is-spike-in-agile-software-development2/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Spike_(software_development)" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Spike_(software_development)&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.leadingagile.com/2014/04/dont-estimate-spikes/" rel="noopener noreferrer"&gt;https://www.leadingagile.com/2014/04/dont-estimate-spikes/&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://t2informatik.de/en/smartpedia/spike-story/" rel="noopener noreferrer"&gt;https://t2informatik.de/en/smartpedia/spike-story/&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://youtu.be/zOIQjluFQZ4?t=203" rel="noopener noreferrer"&gt;https://youtu.be/zOIQjluFQZ4?t=203&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blogs.starcio.com/2019/11/spikes-agile-poc.html" rel="noopener noreferrer"&gt;https://blogs.starcio.com/2019/11/spikes-agile-poc.html&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://rgalen.com/agile-training-news/2018/12/7/12-considerations-for-user-story-spikes" rel="noopener noreferrer"&gt;https://rgalen.com/agile-training-news/2018/12/7/12-considerations-for-user-story-spikes&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://spin.atomicobject.com/2017/05/23/spikes-for-problem-solving/" rel="noopener noreferrer"&gt;https://spin.atomicobject.com/2017/05/23/spikes-for-problem-solving/&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://community.atlassian.com/t5/Jira-questions/How-do-you-use-Spikes-in-Jira/qaq-p/492960" rel="noopener noreferrer"&gt;https://community.atlassian.com/t5/Jira-questions/How-do-you-use-Spikes-in-Jira/qaq-p/492960&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.leadingagile.com/2016/09/whats-a-spike-who-should-enter-it-how-to-word-it/" rel="noopener noreferrer"&gt;https://www.leadingagile.com/2016/09/whats-a-spike-who-should-enter-it-how-to-word-it/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>indonesia</category>
    </item>
    <item>
      <title>Auth0, Hasura, Social Media Login</title>
      <dc:creator>Sakir Temel</dc:creator>
      <pubDate>Tue, 20 Dec 2022 02:18:14 +0000</pubDate>
      <link>https://forem.com/kelebeklabs/auth0-hasura-social-media-login-o3n</link>
      <guid>https://forem.com/kelebeklabs/auth0-hasura-social-media-login-o3n</guid>
      <description>&lt;p&gt;We all want a super simple login and sign up system, so that our customers can become our members in a second and keep logging in without any hassle. Today we're going to talk about how to do it in the projects when we're using &lt;a href="https://hasura.io/"&gt;Hasura&lt;/a&gt; and &lt;a href="https://auth0.com/"&gt;Auth0&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up a Table in Hasura
&lt;/h2&gt;

&lt;p&gt;First we need to have a users table in our Hasura, our unique key on email helps our users to login with different providers to the same account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1nEwv49o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/51lk8yfaszj0pnk326mm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1nEwv49o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/51lk8yfaszj0pnk326mm.png" alt="Users table" width="880" height="794"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--M9RyLBDz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6y89iafyyra5b5sjwav4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--M9RyLBDz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6y89iafyyra5b5sjwav4.png" alt="Users table unique keys" width="842" height="738"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Auth0 Configuration
&lt;/h2&gt;

&lt;p&gt;There's not much to add except following any &lt;a href="https://auth0.com/docs/quickstarts"&gt;Quickstart&lt;/a&gt;, I prefer disabling email&amp;amp;password login and only allowing login via Google and Apple (because for our case it was an iOS project). It gives a really simple experience to our customers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auth0 Rule for Syncing Users to Hasura
&lt;/h2&gt;

&lt;p&gt;This is the most important part, it should be added as a Rule under Auth Pipeline. Whenever a successful login happens at Auth0 end, this code below runs. This code communicates with our Hasura via API and injects the just logged in user to our table that we created. It also retrieves back a &lt;strong&gt;token&lt;/strong&gt; from Hasura and returns to our Auth0 client(library that you're using on mobile/web) as &lt;strong&gt;idToken&lt;/strong&gt;. Now you can use Hasura with "Authorization: Bearer &lt;strong&gt;token&lt;/strong&gt;" header.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: don't forget to add HASURA_GRAPHQL_JWT_SECRET environment variable to Hasura with the value generated &lt;a href="https://hasura.io/jwt-config/"&gt;here&lt;/a&gt;. This is necessary for Hasura to recognize our Auth0 as a provider, so that Hasura can generate a user token.&lt;/em&gt;&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


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

&lt;p&gt;We just went through an end-to-end login/sign-up + Authentication experience with using Auth0 and Hasura. This became our default choice at KelebekLabs whenever we develop a new application. It gives a peace of mind both for the team and the customers.&lt;/p&gt;

</description>
      <category>hasura</category>
      <category>auth0</category>
      <category>reactnative</category>
      <category>ios</category>
    </item>
  </channel>
</rss>
