<?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: The Agile Monkeys</title>
    <description>The latest articles on DEV Community by The Agile Monkeys (@theagilemonkeys).</description>
    <link>https://dev.to/theagilemonkeys</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%2Forganization%2Fprofile_image%2F645%2F69ecc7e6-e64b-4230-928e-564df2008cea.png</url>
      <title>DEV Community: The Agile Monkeys</title>
      <link>https://dev.to/theagilemonkeys</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/theagilemonkeys"/>
    <language>en</language>
    <item>
      <title>Navigating the Double-Edged Sword of AI as a Software Developer</title>
      <dc:creator>Abraham Romero</dc:creator>
      <pubDate>Sun, 13 Oct 2024 22:44:23 +0000</pubDate>
      <link>https://dev.to/theagilemonkeys/navigating-the-double-edged-sword-of-ai-as-a-software-developer-4h35</link>
      <guid>https://dev.to/theagilemonkeys/navigating-the-double-edged-sword-of-ai-as-a-software-developer-4h35</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;Years ago, saving time in software development meant creating macros to avoid code repetition.. We needed to read books to understand how to program in a given language or for a specific machine.&lt;/p&gt;

&lt;p&gt;We then turned to the internet for information, with YouTube videos, Udemy courses, and StackOverflow replacing traditional books.&lt;/p&gt;

&lt;p&gt;Over time, we began using better IDEs like IntelliJ, which offers autocompletion and refactoring features that save us time.&lt;/p&gt;

&lt;p&gt;Now, we have made a leap that is multiple magnitudes larger than ever before in terms of increasing development velocity. With the rise of LLMs, we now have a wide variety of tools that we, as developers, can use in our daily jobs. But, as Uncle Ben said, with great power comes great responsibility. Let's explore these tools together, let me tell you what I do, and what I think is coming.&lt;/p&gt;

&lt;h3&gt;
  
  
  Great Power...
&lt;/h3&gt;

&lt;p&gt;You should already know all these names: ChatGPT, Gemini, Claude, GitHub Copilot, etc. You can find LLMs specialized for doing nearly everything you want to do nowadays.&lt;/p&gt;

&lt;p&gt;The clearest advantage of these tools is increased velocity, such as rapid prototyping (AI can automate repetitive tasks, allowing developers to focus on higher-level design and problem-solving), faster debugging (AI tools can quickly identify bugs and suggest fixes, significantly reducing time spent in the debugging phase), or unit test development will be immediately noticeable.&lt;/p&gt;

&lt;p&gt;But that's not all; you'll have access to a broader range of technologies. Using AI will reduce the learning curve by providing instant insights and resources on unfamiliar technologies. This allows you to quickly tackle projects outside your expertise with AI support.&lt;/p&gt;

&lt;p&gt;LLMs like GPT-4 specialize in text generation, allowing you to write better messages, improve your emails, or generate documentation for your projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Great Responsibilities
&lt;/h3&gt;

&lt;p&gt;As we just saw, using AI can help you do your job better. But it doesn't come for free; there are some risks.&lt;/p&gt;

&lt;p&gt;You can't blindly trust AI. Over-reliance on AI can lead to complacency and reduced critical thinking. Additionally, AI-generated code may not always adhere to best practices or organizational standards, requiring vigilant oversight.&lt;/p&gt;

&lt;p&gt;Relying on AI can stunt learning and hinder problem-solving skills, making it harder for developers to tackle challenges independently. Furthermore, if developers lean on AI tools instead of mastering foundational concepts, they may miss out on essential skills.&lt;/p&gt;

&lt;p&gt;Security risks are another significant concern. AI-generated code may inadvertently introduce vulnerabilities, especially if not properly reviewed or tested. Cybercriminals can exploit these tools to automate attacks or create sophisticated phishing schemes.&lt;/p&gt;

&lt;h3&gt;
  
  
  How I Use AI in My Daily Job
&lt;/h3&gt;

&lt;p&gt;In my daily workflow, I utilize several AI tools like ChatGPT, GitHub Copilot, or Perplexity AI. However, I approach their outputs with healthy skepticism. While AI can provide valuable suggestions and speed up certain processes, I always verify the results to ensure they align with best practices and meet my project’s specific requirements.&lt;/p&gt;

&lt;p&gt;For example, I never copy and paste code from ChatGPT; I always try to understand the response and apply it to my code, test it, and check if it truly works. On the other hand, with GitHub Copilot, I accept many code suggestions, and that code is inserted directly into my code, but I always review it and modify it if needed.&lt;/p&gt;

&lt;p&gt;This critical mindset allows me to leverage AI effectively without compromising the quality of my work. I also make it a point to stay engaged with the underlying concepts, ensuring that I continue to enhance my skills and understanding of the technologies I’m using.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Coming and How to Maximize the Advantages
&lt;/h3&gt;

&lt;p&gt;Use AI tools, learn how to use them, keep learning, and focus on the personal aspects of your job, such as capturing requirements and team collaboration.&lt;/p&gt;

&lt;p&gt;The future of AI in software development is bright, with advancements expected to make these tools even more powerful and intuitive. To maximize the advantages of AI, you should actively use these tools while also dedicating time to learn how to integrate them into your workflows effectively. Continuous learning is key; you should stay informed about the latest AI developments and explore new tools that can aid your tasks.&lt;/p&gt;

&lt;p&gt;Importantly, it’s crucial to focus on the human aspects of software development that AI cannot replace. This includes capturing requirements accurately, engaging in effective team collaboration, and fostering open communication among team members. By maintaining a balance between leveraging AI and enhancing interpersonal skills, you can ensure you are not only effective in your technical role but also a valuable contributor to your team.&lt;/p&gt;

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

&lt;p&gt;The integration of AI into software development presents a compelling mix of opportunities and challenges. While it can enhance productivity and expand skill sets, you must remain vigilant and engaged in your learning. Finding the right balance between using AI and mastering core software development practices is essential for long-term success.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opinion</category>
      <category>discuss</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>Baby's First Contribution - A GitHub Flow for non-devs</title>
      <dc:creator>Nick Tchayka</dc:creator>
      <pubDate>Tue, 25 Jul 2023 16:37:27 +0000</pubDate>
      <link>https://dev.to/theagilemonkeys/babys-first-contribution-a-github-flow-for-non-devs-2ebg</link>
      <guid>https://dev.to/theagilemonkeys/babys-first-contribution-a-github-flow-for-non-devs-2ebg</guid>
      <description>&lt;p&gt;I'm sure that there was at least a single time where you wanted to change a word, a color, a font, a link, or something in a repo.&lt;/p&gt;

&lt;p&gt;I'm sure that you are not afraid of doing the change, &lt;strong&gt;but of the process that it involves.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using a text editor&lt;/li&gt;
&lt;li&gt;changing code *&lt;em&gt;&lt;strong&gt;gasp&lt;/strong&gt;&lt;/em&gt;*&lt;/li&gt;
&lt;li&gt;and… *&lt;em&gt;&lt;strong&gt;dramatic orchestra sound&lt;/strong&gt;&lt;/em&gt;* &lt;strong&gt;creating a pull request&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I know, this sounds scary af, but stay with me, I've streamlined the process for you so you can be doing the changes super easily.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get to meet Git - Time Machine for code
&lt;/h2&gt;

&lt;p&gt;If you use MacOS you probably know the Time Machine feature, which allows you to go back in time to retrieve a previous version of a file from the past. If you don't, well, apparently computers allow you to travel back in time 🤷 (at least digitally)&lt;/p&gt;

&lt;p&gt;Git was one of the first software to popularize this concept, allowing to retrieve previous versions of any text file on a computer, saving all the changes that have been done to that file in what's called a &lt;strong&gt;log&lt;/strong&gt; (like the log of an accountant, or the diary of someone).&lt;/p&gt;

&lt;p&gt;The cool part of this, is that you can share this &lt;strong&gt;log&lt;/strong&gt; with other people, so they can check the previous versions that you have done to your files. &lt;strong&gt;You can literally email them this log&lt;/strong&gt;. (Remember all of this was in the early internet era).&lt;/p&gt;

&lt;p&gt;What happens if two persons want to do changes to the same files? Git allows you to work in parallel, each timeline of changes is called a &lt;strong&gt;branch&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Branches get out of the log, get it? Apparently programmers like bad jokes, but we keep denying it&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They usually look like this:&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%2Fblog.seibert-media.net%2Fwp-content%2Fuploads%2F2015%2F07%2FGit-Branches-1.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%2Fblog.seibert-media.net%2Fwp-content%2Fuploads%2F2015%2F07%2FGit-Branches-1.png" alt="git branch diagram" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each circle is a change that someone has done, and the different colors represent the branches.&lt;/p&gt;

&lt;p&gt;What if now we want to merge the changes from one branch into the main one? Let's keep reading.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub - A Google Drive for Git logs
&lt;/h2&gt;

&lt;p&gt;You could've been thinking already that emailing the Git log to everyone is a nightmare. Indeed it is, and teams have been doing so in the past.&lt;/p&gt;

&lt;p&gt;Thankfully, nowadays we have GitHub, which makes everything super easy.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 &lt;strong&gt;Hub&lt;/strong&gt; = place to share stuff, therefore &lt;strong&gt;GitHub&lt;/strong&gt; = Place to share Git things.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;GitHub is a platform that allows you to store the Git log of a project in a centralized place, and then it gives you tools so the team can discuss whether a change should be integrated into the main project or not (this is called a &lt;strong&gt;Pull Request&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;If you don't have one, you should begin by creating an account in GitHub, and sharing the name with one of the team members so they can add you to the company team.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;✏️ &lt;strong&gt;Note&lt;/strong&gt;: In GitHub, open source projects are completely public, so if the project you want to contribute to is open source, you can skip the wait of getting added to the team.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;GitHub is a very big tool that can have it's own article for an explanation. So we will talk only about making the change that you want.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making the change
&lt;/h2&gt;

&lt;p&gt;Let's suppose that you want to change a typo on the Docusaurus website of a project.&lt;/p&gt;

&lt;p&gt;Open your web browser, and get into the GitHub repository that you want to make the change to.&lt;/p&gt;

&lt;p&gt;Once you're here, press the  &lt;code&gt;.&lt;/code&gt;  key in your keyboard. You should go from here:&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%2Fqfi1saz9x11tidtar36n.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%2Fqfi1saz9x11tidtar36n.png" alt="Image description" width="800" height="573"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To here&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%2Fnj9s78qx4xvukj36xdcb.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%2Fnj9s78qx4xvukj36xdcb.png" alt="Image description" width="800" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This new view is called &lt;strong&gt;Visual Studio Code&lt;/strong&gt;. It is a text editor that devs use to code (and edit documentation).&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a branch
&lt;/h3&gt;

&lt;p&gt;In order to be able to make a change properly, you need to create a branch. &lt;/p&gt;

&lt;p&gt;First, think of a name for the branch (usually it is something like &lt;code&gt;GITHUB-ISSUE-NUMBER/task-title&lt;/code&gt; for example &lt;code&gt;999/create-something-cool&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Now click on the branches button, which is the one saying &lt;code&gt;main&lt;/code&gt; on the bottom left of Visual Studio Code:&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%2Fn1j263e5cbvilz3tmhzt.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%2Fn1j263e5cbvilz3tmhzt.png" alt="Image description" width="800" height="670"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on &lt;code&gt;Create New Branch&lt;/code&gt;.&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%2Fx6vheq192losysd1niwp.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%2Fx6vheq192losysd1niwp.png" alt="Image description" width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Type the branch name that you thought of, and press &lt;strong&gt;ENTER&lt;/strong&gt; (if you minimize the window the text box will probably disappear and you will have to open this menu again)&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%2Ff5limrz5s6wlmkk9mkv9.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%2Ff5limrz5s6wlmkk9mkv9.png" alt="Image description" width="779" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It could be possible that it will ask you something about commits and stuff now, just click on &lt;strong&gt;Switch To Branch&lt;/strong&gt;&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%2Fowefnk7ycpdikcnp3jhu.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%2Fowefnk7ycpdikcnp3jhu.png" alt="Image description" width="679" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Doing the actual changes
&lt;/h3&gt;

&lt;p&gt;On the left side bar, you will see lots of folders and files. Locate the one that you want to change.&lt;/p&gt;

&lt;p&gt;For our example, where we want to change something from Docusaurus, we will look into the &lt;code&gt;website&lt;/code&gt; folder, which is where the documentation related files are usually located.&lt;/p&gt;

&lt;p&gt;Let's say we saw a typo in the Getting Started guide and we want to fix it. We would have to navigate to &lt;code&gt;website/docs/getting_started.md&lt;/code&gt; and open the file by clicking on it:&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%2Fj47zmr956bjutrux183l.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%2Fj47zmr956bjutrux183l.png" alt="Image description" width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm going to change the first sentence of the section name &lt;code&gt;Step 0&lt;/code&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Usually technical documentation follows a format called &lt;strong&gt;Markdown&lt;/strong&gt;. This is a way of formatting text in a super nerdy way, but it is a standard that most web tools understand. For example, when you format messages in Slack, you're using (something that is very close to) Markdown. &lt;a href="https://www.markdownguide.org/cheat-sheet" rel="noopener noreferrer"&gt;Here you have a cheatsheet&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once you save the file using &lt;code&gt;Cmd + S&lt;/code&gt;. If you did it well, you should have a line marker where you did the changes:&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%2Ftgkm9oyrrcjmmc5g561o.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%2Ftgkm9oyrrcjmmc5g561o.png" alt="Image description" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now to ensure that the changes are uploaded to GitHub, you have to &lt;strong&gt;commit&lt;/strong&gt; them.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡 Commiting means signing your changes with your name and a description. It is a way of marking who did what in a project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;On the top-left of Visual Studio Code, click on the thing that looks the USB logo, this is called the &lt;code&gt;Source Control View&lt;/code&gt;:&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%2Fmsm2t9tw4u5uca7emz10.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%2Fmsm2t9tw4u5uca7emz10.png" alt="Image description" width="800" height="644"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, describe briefly the changes that you've made in the text box that says message. And click &lt;code&gt;Commit &amp;amp; Push&lt;/code&gt;:&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%2Fp5ph19lmw5krbq2w99k8.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%2Fp5ph19lmw5krbq2w99k8.png" alt="Image description" width="399" height="272"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the button went dark, and the message box got cleared, this means that the changes you made were uploaded to GitHub.&lt;/p&gt;

&lt;p&gt;Now the last step!&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a Pull Request
&lt;/h3&gt;

&lt;p&gt;If you put the mouse near where you see the text &lt;code&gt;Source Control&lt;/code&gt;, some icons will appear. Click on the second one, the one that looks like a diagram with a plus sign. This will begin the Pull Request creation process.&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%2F513x0cw5jyr4tnuww2lx.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%2F513x0cw5jyr4tnuww2lx.png" alt="Image description" width="426" height="185"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This new panel should appear. Don't get into the details, you just have to do 3 things here:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ensure that your branch is correctly selected.&lt;/li&gt;
&lt;li&gt;Ensure that the &lt;code&gt;into&lt;/code&gt; branch is &lt;code&gt;main&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Improve the title, and add some lengthy description.&lt;/li&gt;
&lt;/ol&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%2Fiy18hmmw2rdr86vkv7jq.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%2Fiy18hmmw2rdr86vkv7jq.png" alt="Image description" width="313" height="591"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If everything is correct, click on &lt;code&gt;Create&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Something like this will appear, click on &lt;code&gt;Copy Link&lt;/code&gt; to copy the link to this Pull Request.&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%2Fakp0u1wui45blhg80jjk.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%2Fakp0u1wui45blhg80jjk.png" alt="Image description" width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, just share the link with the team in a passive-agressive message, and let them review and merge the things that you did. Be proud of yourself!&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%2F41yyn8axfa3h638sqom1.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%2F41yyn8axfa3h638sqom1.png" alt="Image description" width="800" height="162"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Congratulations, you're officially a &lt;del&gt;nerd&lt;/del&gt; programmer now!
&lt;/h2&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%2Fuq2ylidak8xf7yrzluo0.gif" 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%2Fuq2ylidak8xf7yrzluo0.gif" alt="nerds dancing" width="314" height="206"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>github</category>
      <category>opensource</category>
      <category>vscode</category>
    </item>
    <item>
      <title>Railway Event Processor: Safe integrations in Event Sourcing</title>
      <dc:creator>Yeray Cabello</dc:creator>
      <pubDate>Mon, 15 May 2023 08:27:44 +0000</pubDate>
      <link>https://dev.to/theagilemonkeys/railway-event-processor-272l</link>
      <guid>https://dev.to/theagilemonkeys/railway-event-processor-272l</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;An integral default approach for the design and implementation of third party integrations in event-sourced systems.&lt;/p&gt;

&lt;p&gt;⚠️The abstractions proposed in this paper will be soon implemented in &lt;a href="https://github.com/boostercloud/booster" rel="noopener noreferrer"&gt;booster&lt;/a&gt;, the algorithms proposed are proven correct &lt;a href="https://github.com/boostercloud/workflows-framework" rel="noopener noreferrer"&gt;in this repository&lt;/a&gt;. A solution to a real world problem with these abstractions will be soon shared.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Railway Event Processor
&lt;/h1&gt;

&lt;h2&gt;
  
  
  When in doubt, treat your system as distributed
&lt;/h2&gt;

&lt;p&gt;The need to integrate with third-party services is prevalent in the software industry. Many cross-cutting problems present massive and unique challenges that require specialized focus to solve; some of them would be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Making sure that transactional emails are sent to consumers without being filtered as spam requires such a degree of commitment that there are companies that do exclusively that.&lt;/li&gt;
&lt;li&gt;Receiving payments online, interacting with the myriad of platforms available, and with the banks reaches a point of complexity that many payment providers become banks themselves to make the service more reliable.&lt;/li&gt;
&lt;li&gt;Keeping track of interactions with customers has enough nuance to create an entire industry of Customer Relationship Management.&lt;/li&gt;
&lt;li&gt;Logistics and chain of supply.&lt;/li&gt;
&lt;li&gt;Providing customer support.&lt;/li&gt;
&lt;li&gt;Authentication and authorization.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The issue with this is that, no matter how simple you think your application is, having any of those increasingly necessary integrations, effectively turn any system into a distributed one, and in the words of Leslie Lamport:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A distributed system is one in which the failure of a computer you didn't even know existed can render your own computer unusable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Any integration with these systems, services in your own company, or actually anything that happens outside the memory assigned on your program, like a database, presents four major challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Orchestration.&lt;/li&gt;
&lt;li&gt;
Fault tolerance.&lt;/li&gt;
&lt;li&gt;
Concurrency handling.&lt;/li&gt;
&lt;li&gt;Communication.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ This research looks to address Fault Tolerance and Concurrency Handling, but since they can’t be addressed without taking into account the other two, orchestration will be handled using the &lt;a href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/ProcessManager.html" rel="noopener noreferrer"&gt;Process Manager Pattern&lt;/a&gt;, with some lessons learned from the Saga Pattern, and Communication will be solved via event streams and read models. It might catch the attention of the reader that, given the spotlight that message streaming platforms have in enterprise environments, to the point that seminal books as &lt;a href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/Messaging.html" rel="noopener noreferrer"&gt;enterprise integration patterns deal almost exclusively with messaging&lt;/a&gt;, messaging is not used. As a matter of fact, the read models that will be used for scheduling can, and often should, be stored via message queues, but that extra step will be omitted for simplicity.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The language described in this paper has the aspiration to be a framework used as a bridge between engineering and business teams, so the degree of complexity of any given integration is visible and understandable by everybody involved.&lt;/p&gt;

&lt;p&gt;First, the problem will be laid out in terms of the nature of integrations and why they are a frequent source of errors and technical challenges. Then the core concepts will be introduced, the &lt;code&gt;Task&lt;/code&gt;, the &lt;code&gt;Compromise&lt;/code&gt;, and the &lt;code&gt;Transition&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;All of these will be put together with an example in the &lt;code&gt;Workflow&lt;/code&gt; definition.&lt;/p&gt;

&lt;p&gt;Finally, a design will be provided for the abstraction of every kind of &lt;code&gt;Task&lt;/code&gt;, with a formal proof of correctness for each. Together with the solutions, there will be proof of the unsolvable nature of the opaque integrations.&lt;/p&gt;

&lt;p&gt;The solution design is built around the assumption of an event-sourced, or at least event-driven system, and it should be possible to apply these principles to such systems without any modification. A non event-oriented system can implement this pattern with relative ease as long as it follows the &lt;code&gt;Command Query Responsibility Segregation&lt;/code&gt; principle. Beyond that, major concessions might be needed, forfeiting the correctness provided out of the box by this framework.&lt;/p&gt;

&lt;p&gt;The end goal is to provide a safe structure to connect every step of these processes, so they can be built and maintained as a deterministic state machine.&lt;/p&gt;

&lt;h1&gt;
  
  
  Modelling systems as a workflow of tasks
&lt;/h1&gt;

&lt;p&gt;Before delving into the concept of a task as the key component of our solution, it is essential to provide a brief introduction to the concept of a workflow as a means of orchestration. Details regarding this concept and the communication between tasks will be discussed later. At this point, it suffices to understand that any system orchestration situation can be modeled as a combination of tasks that run sequentially.&lt;/p&gt;

&lt;p&gt;For instance, consider a series of tasks, labeled A to D, where task B is an action to be performed with information obtained from the result of A. Task A has the responsibility to start B. Then, when B completes, it will decide whether to continue with C, because customer support has to make a review, or D, which is a straightforward automatic process. Finally, either of them will emit an event with the outcome of the workflow.&lt;/p&gt;

&lt;p&gt;The aforementioned configuration can be represented using a diagram as follows:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa6v5mewffspcfoqiihs5.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa6v5mewffspcfoqiihs5.png" alt="Example workflow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This example serves merely as an illustration of a possible task orchestration scenario. The crucial idea to grasp at this stage is that tasks will run in sequence, and that they are unlikely to show unexpected behavior, forming execution graphs of arbitrary complexity. These execution graphs provide a mental map of the system's orchestration, enabling efficient and adaptable process modeling.&lt;/p&gt;

&lt;p&gt;More importantly, &lt;strong&gt;there is no hidden complexity in these diagrams&lt;/strong&gt;, every possible outcome is represented in the graph.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Task
&lt;/h1&gt;

&lt;p&gt;An abstraction over a single step in a workflow, it is modeled after a state of a state machine, and all its possible results, including those of failure, will point out to a different task.&lt;/p&gt;

&lt;h3&gt;
  
  
  To-Do Item
&lt;/h3&gt;

&lt;p&gt;They require one external action to happen: a user interaction, receiving a message from a queue, a webhook from a payment provider, or other similar interactions. Once that is received, a decision will be made to move to the next step.&lt;/p&gt;

&lt;h3&gt;
  
  
  State
&lt;/h3&gt;

&lt;p&gt;A step in the workflow that will perform an action synchronously and, using the result of such action, will decide on the next step.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Notice that neither of them are concerned with fault, the goal of the abstraction is exclusively to make a decision.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  The transition
&lt;/h1&gt;

&lt;p&gt;One key element of the Railway Event Processor is that there is no concept of a failed task. Even for technical faults, the inability to attempt the task has to be translated into a business outcome.&lt;/p&gt;

&lt;p&gt;That is, a payment might be successful or fail because of a lack of funds, this means that the payment itself can be rejected, but the task is not concerned whether the result was desirable or not, but about that, there was one of two possible results, and that each of them will lead to a different task in the flow.&lt;/p&gt;

&lt;p&gt;In this example, a successful payment will lead to the fulfillment of the order, and a failed one will lead to a new request for payment to the user, possibly with a retry counter, which will eventually lead to the order being canceled.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa83a6tgh9f7gquxc79p5.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa83a6tgh9f7gquxc79p5.png" alt="Transition"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ A task that “fails” for business reasons it’s not considered a failure in this framework, as business failures (such as a payment rejected or not having permissions to perform an action) are abstracted as just one of several possible outcomes.&lt;/p&gt;

&lt;p&gt;e.g. Performing a fraud check can determine whether the user is trustworthy or not. Both cases are just possible outcomes of the check: A result of potential fraud is not a failure but a successful verification that returned useful information.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The transition is represented as one of the following options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A domain event that ends the workflow, this would be the outcome of the workflow.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;State&lt;/code&gt; that follows the decision.&lt;/li&gt;
&lt;li&gt; The &lt;code&gt;To Do Item&lt;/code&gt; that follows the decision.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ The domain event that ends the workflow can be used to chain parts of a more complex workflow.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Technical categories of tasks
&lt;/h1&gt;

&lt;h2&gt;
  
  
  External action required
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Task&lt;/code&gt; is waiting for the third party to continue the execution.&lt;/p&gt;

&lt;p&gt;e.g. A webhook from a payment provider or a response sent by a human.&lt;/p&gt;

&lt;h2&gt;
  
  
  Idempotency enabled
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Task&lt;/code&gt; is executed against a service that provides a mechanism to uniquely identify an action. Said mechanism allows us to try to perform the action knowing that it will only impact the system once even if we have attempted it on the past or there is a duplicated process attempting the same action. This removes concerns for concurrency and fault tolerance, as it is possible to just attempt the action until we get an acceptance or rejection result and succeed in directing the workflow toward the desired next &lt;code&gt;Task&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;e.g. Many payment providers accept an &lt;code&gt;Idempotency Key&lt;/code&gt; in their requests, so if we attempt a refund, and we generate a unique key per refund, we know we will never refund more than once.&lt;/p&gt;

&lt;p&gt;Simply add the &lt;code&gt;Idempotency Key&lt;/code&gt; to the request, any parallel executions, or retries due to failure to register the outcome will be ignored by the third party.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimistic lock enabled
&lt;/h2&gt;

&lt;p&gt;This is a&lt;code&gt;Task&lt;/code&gt; with the following characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Either the API of the third party offers:

&lt;ul&gt;
&lt;li&gt;A way to attach a unique identifier to the action we want to perform.&lt;/li&gt;
&lt;li&gt;A query mechanism that allows filtering via the aforementioned unique identifier.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Or:

&lt;ul&gt;
&lt;li&gt;The nature of the task makes it so that the action can be identified deterministically without an additional identifier.&lt;/li&gt;
&lt;li&gt;And the API offers a query mechanism that allows querying for that.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;A multistep process that can be canceled at any time before it is completed.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This way, we can, before we even start processing it, detect whether there is another process trying to perform the same action or whether there was a previous attempt that faulted. This allows us to attempt the action and verify between steps again for faulty concurrent access. Finally, it is possible to run a cleanup after one process has been successful. That is, we virtually allow multiple processes to race concurrently, allowing only the first of them to write the result and canceling the others.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pessimistic lock enabled
&lt;/h2&gt;

&lt;p&gt;This is a &lt;code&gt;Task&lt;/code&gt; with the following characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Either the API offers:

&lt;ul&gt;
&lt;li&gt;A way to attach a unique identifier to the action we want to perform.&lt;/li&gt;
&lt;li&gt;A query mechanism that allows filtering via the aforementioned unique identifier.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Or:

&lt;ul&gt;
&lt;li&gt;The nature of the task makes it so that the action can be identified deterministically without an additional identifier.&lt;/li&gt;
&lt;li&gt;And the API offers a query mechanism that allows to query for that.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Without a multistep process that can be canceled at any time, we must rely on a central place to lock any other processes out of attempting the operation.&lt;/p&gt;

&lt;p&gt;That is, we won’t allow a second attempt to run if there’s an ongoing process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Black boxed
&lt;/h2&gt;

&lt;p&gt;This &lt;code&gt;Task&lt;/code&gt; provides no ability to reliably determine if the operation is being performed by another process, or whether we are attempting it again from a previous failure.&lt;/p&gt;

&lt;p&gt;For these processes, the beginning of an attempt is stored, so is the result, any attempt that starts, will check if there was a previous beginning recorded without a matching result, if that’s the case, a possible failure is detected, as it is impossible to know if the action was performed and its outcome. &lt;/p&gt;

&lt;p&gt;This case would require compromising in case of failure. A decision needs to be made if it’s detected that there was a previous attempt that did not finish:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have a human review it.&lt;/li&gt;
&lt;li&gt;Ignore it and move on.&lt;/li&gt;
&lt;li&gt;Retry it up to a certain amount of times.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Common language definitions
&lt;/h1&gt;

&lt;p&gt;All these definitions, for the sake of simplicity, will be condensed from the perspective of the common language into these three terms, so when discussing the design of workflows that integrate third parties, they will get referred to in the following three categories.&lt;/p&gt;

&lt;h2&gt;
  
  
  To Do
&lt;/h2&gt;

&lt;p&gt;This is the &lt;code&gt;External Action Required&lt;/code&gt; type. An external service needs to reach to continue the workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trivial
&lt;/h2&gt;

&lt;p&gt;Services that have an explicit idempotency mechanism, rare, but always preferable.&lt;/p&gt;

&lt;p&gt;Integrating with this category poses no challenge both in terms of correctness and performance. &lt;/p&gt;

&lt;p&gt;We can count on any action performed towards this service as that they will eventually complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deterministic
&lt;/h2&gt;

&lt;p&gt;This includes optimistic and pessimistic lock enabled third parties.&lt;/p&gt;

&lt;p&gt;Integrating with this category poses a challenge in terms of correctness. The simplest approach is to consider all of them pessimistic and switch to the optimistic ones if there's a performance problem.&lt;/p&gt;

&lt;p&gt;We can count on any action performed towards this service as that they will eventually complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  Opaque
&lt;/h2&gt;

&lt;p&gt;Black boxed.&lt;/p&gt;

&lt;p&gt;These present an unsolvable challenge in terms of correctness, as we can neither guarantee a single execution nor failure (in the case of having a record of the attempt starting but not of the attempt outcome).&lt;/p&gt;

&lt;p&gt;A business decision needs to be made in terms of what to do when failure is suspected.&lt;/p&gt;

&lt;h1&gt;
  
  
  Business concerns of a Black Boxed Task
&lt;/h1&gt;

&lt;p&gt;This includes all the factors we need to take into account when making compromises over black-boxed tasks. This part of the framework is not formal, it aims to provide a checklist of factors to consider when making a decision, the decision itself is formal, as it will have an abstraction on top of it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Visibility
&lt;/h1&gt;

&lt;p&gt;How likely is the non-execution or failure of the task to be perceived.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Self-evident.&lt;/strong&gt; By its own nature, the failure will be noticed.
e.g. If a refund is never sent, the user will eventually complain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traceable.&lt;/strong&gt; It’s possible to add reliable tracking mechanisms to follow up on the action being performed.
e.g. The deduction of the loyalty points from a user that purchased a product using them fails. We would need to set an alert for it and have someone verify what happened.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Invisible.&lt;/strong&gt; We can’t guarantee to know the outcome of a task.
e.g. We cannot determine whether an email has been opened or not. Mechanisms like tracking pixels might be blocked by the email service, so it’s possible that an email that was read shows as unread.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Necessity
&lt;/h1&gt;

&lt;p&gt;How critical is the step to the workflow&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Must happen.&lt;/strong&gt; The workflow can’t continue without this step.
e.g. The payment must be confirmed before we start handling an order.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Should happen.&lt;/strong&gt; The workflow can continue, but there’s a consequence if it fails.
e.g. Bank account number validations are known to put back customers when they make a typo, so it’s desirable to allow them to continue and then reach out to them about a failed payment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nice to have.&lt;/strong&gt; It’s not needed, but it is presumed that it adds some value to the product.
e.g. Sending a satisfaction survey.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Concern
&lt;/h1&gt;

&lt;p&gt;Who gets directly hurt if the task fails:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Own.&lt;/strong&gt;
e.g. There’s a failure when registering an order as sent, and it gets sent twice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Third party.&lt;/strong&gt;
e.g. The delivery data for an order to a logistics company gets corrupted, and the provider needs to reach out to fix the issue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Customer.&lt;/strong&gt;
e.g. A refund is not sent when it’s due.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Risk
&lt;/h1&gt;

&lt;p&gt;The kind of consequences suffered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reputation.&lt;/strong&gt;
e.g. A customer gets charged twice for a product. Event after returning the amount, the customer might not come back.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Legal.&lt;/strong&gt;
e.g. A Service Level Agreement is not met, a customer loses business because of that, and sues us for the losses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data breach.&lt;/strong&gt;
e.g. There is an email with an invoice from customer "A" sent to customer "B", leaking GDPR protected information.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Economic loss.&lt;/strong&gt;
e.g. An expensive product was bought, but an error caused two of them to be sent.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Compromise Decision of Black Boxed Tasks
&lt;/h1&gt;

&lt;p&gt;Once taken the concerns into account, a decision has to be made about handling possible failure for the task:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ This is about &lt;code&gt;possible failure&lt;/code&gt; it is often possible to guarantee that a task has failed, if that’s the case, that failure will be treated as it would in a deterministic &lt;code&gt;task&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  At least once
&lt;/h2&gt;

&lt;p&gt;If there’s a suspicion that the task has failed, it will be retried indefinitely, assuming the risk that it might happen more than once. It is important to understand that this means to attempt it until its success &lt;code&gt;is registered&lt;/code&gt;, or it expires, meaning that it might even succeed indefinitely.&lt;/p&gt;

&lt;p&gt;e.g. Blocking a user that has been deemed hostile should be attempted until success is registered.&lt;/p&gt;

&lt;h2&gt;
  
  
  Up to &lt;code&gt;n&lt;/code&gt; times
&lt;/h2&gt;

&lt;p&gt;If there’s a suspicion that the task has failed, it will be retried a certain amount of times, assuming the risk that it might happen more than once.&lt;/p&gt;

&lt;p&gt;e.g. Sending a verification code as an SMS, it’s desirable to guarantee that it gets sent, but the costs could pile up rather quickly if the retries happen indefinitely for every user.&lt;/p&gt;

&lt;h2&gt;
  
  
  At most once
&lt;/h2&gt;

&lt;p&gt;If there’s a suspicion that the task has failed, it’s given up silently.&lt;/p&gt;

&lt;p&gt;e.g. Sending a welcome email.&lt;/p&gt;

&lt;h2&gt;
  
  
  Important: Human intervention required
&lt;/h2&gt;

&lt;p&gt;If there’s a suspicion that the task has failed, there will be a step where a human has to make a decision. This is not a special kind of compromise, as there’s already a kind of task for this, the &lt;code&gt;External Action Required&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;e.g. A user requested the deletion of their private data, but the confirmation email could not be sent, it is desirable to reach out to the user to avoid legal risks.&lt;/p&gt;

&lt;h1&gt;
  
  
  The conclusion
&lt;/h1&gt;

&lt;p&gt;The outcome of a task that has been deemed &lt;code&gt;possibly failed&lt;/code&gt; needs to be mapped to a business outcome, that is, a &lt;code&gt;transition&lt;/code&gt;. All the other conclusions are mapped just like the deterministic ones.&lt;/p&gt;

&lt;h1&gt;
  
  
  Algorithms for each kind of Task
&lt;/h1&gt;

&lt;h1&gt;
  
  
  Every task requires:
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Task identifier
&lt;/h2&gt;

&lt;p&gt;A unique, human-readable identifier that is unique for the action that is being attempted and that &lt;strong&gt;has to be consistently and deterministically generated only with the information contained in the event that triggered it&lt;/strong&gt;. It will be referred to as the &lt;code&gt;Task identifier&lt;/code&gt;. Optionally, they can be part of the signature of the events that trigger a task. Some examples would be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;refund-eaf1c4d0-3cfd-4fb4-bae0-864a6142446d&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;partial-payment-invoice-6ddcfdc3-8769-4f53-9cb8-66f6d6aa9b69-part-0&lt;/code&gt; In this case, the event needs to carry the part, number and the aggregate responsible for it needs to keep track of which partial payment it is emitting the event for.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;payment-initiated-6ddcfdc3-8769-4f53-9cb8-66f6d6aa9b69&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Expiration functions
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;A function that receives the event that triggered the task, its &lt;code&gt;Task identifier&lt;/code&gt;, and determines whether it still needs to be performed.&lt;/li&gt;
&lt;li&gt;A function that maps the expiration to one of the possible transitions of the task.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  To-Do Item
&lt;/h1&gt;

&lt;p&gt;Tasks that expose an endpoint that a third party must complete, this might even be a human actor. The abstraction requires the following definitions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A read model definition.&lt;/li&gt;
&lt;li&gt;An endpoint definition:

&lt;ol&gt;
&lt;li&gt;Access control.&lt;/li&gt;
&lt;li&gt;A data contract.&lt;/li&gt;
&lt;li&gt;Type.

&lt;ol&gt;
&lt;li&gt;Message queue.&lt;/li&gt;
&lt;li&gt;Synchronous API route segment (web API, GraphQL…)&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;A function that queries the read model based on the information in the data received.&lt;/li&gt;

&lt;li&gt;A function that makes a decision based on both the read model and the data received, and &lt;strong&gt;nothing else.&lt;/strong&gt;
&lt;/li&gt;

&lt;/ol&gt;

&lt;/li&gt;

&lt;li&gt;A function that receives the event that leads to this task and generates a read model.&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The algorithm:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6stfmnj89c7mptoze9mr.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6stfmnj89c7mptoze9mr.png" alt="To-Do Item example"&gt;&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcumsnml79afwonlm8o49.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcumsnml79afwonlm8o49.png" alt="Legend"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  State
&lt;/h1&gt;

&lt;p&gt;Tasks that receive an event, attempt an action and, once successful, make a decision and emit a new event.&lt;/p&gt;

&lt;h3&gt;
  
  
  Retriability
&lt;/h3&gt;

&lt;p&gt;All state tasks can define retry logic, this is done through a back off function that receives how many times the function has been attempted, the event, the &lt;code&gt;Task identifier&lt;/code&gt;and an optional error type (an exception in most languages), and returns either an amount of time to wait until the next attempt or a decision to not try again.&lt;/p&gt;

&lt;p&gt;To implement this function, it is important to take into account the “retriability” of a task based on the risk assessment made in the business concern section.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;At least once&lt;/li&gt;
&lt;li&gt;Up to &lt;code&gt;n&lt;/code&gt; times&lt;/li&gt;
&lt;li&gt;At most once&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In general, tasks falling into the first category can be retried until the timeout function stops the cycle. If that is the case, no retry back-off function is needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fault tolerance
&lt;/h3&gt;

&lt;p&gt;All state tasks need to define a function that takes an error type, represented as &lt;code&gt;exceptions&lt;/code&gt; in most languages, the event, and the &lt;code&gt;Task identifier&lt;/code&gt;, and returns a business decision. This function will be called if the retriability function decides not to retry again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Idempotency enabled
&lt;/h2&gt;

&lt;p&gt;This task is an integration with a third party that provides a mechanism to uniquely identify an action, often with an idempotency header, so the action can be attempted many times without producing the effect several times. The definition requires:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A function that receives the event and the &lt;code&gt;Task identifier&lt;/code&gt;, attempts the action and with the result of it, makes a decision.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The algorithm:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3zidr13g2goezruksgjb.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3zidr13g2goezruksgjb.png" alt="Idempotency enabled algorithm"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimistic lock enabled
&lt;/h2&gt;

&lt;p&gt;This task is an integration with a third party that allows to perform an action in two steps, and determine whether the first step of the task is already underway by another process by querying for the first step based on some form of metadata that includes the &lt;code&gt;Task identifier&lt;/code&gt;. The definition consists on:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A function that receives the event and the &lt;code&gt;Task identifier&lt;/code&gt;, and attempts the first step of the task.&lt;/li&gt;
&lt;li&gt;A function that receives the event and the &lt;code&gt;Task identifier&lt;/code&gt;, and determines whether the action has already started.&lt;/li&gt;
&lt;li&gt;A function that receives the event and the &lt;code&gt;Task identifier&lt;/code&gt;, attempts the second step, and based &lt;/li&gt;
&lt;li&gt;An optional function that receives the event and the &lt;code&gt;Task identifier&lt;/code&gt;, and undoes any incomplete attempt of the task.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Task will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Attempt the first step.&lt;/li&gt;
&lt;li&gt;Verify that the first step just made is the oldest one not expired for this identifier.

&lt;ol&gt;
&lt;li&gt;If it isn't, it tries to delete the step and exits without an outcome.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Verify that there isn't a completed second step for this identifier.

&lt;ol&gt;
&lt;li&gt;If there is, it tries to delete the step and exits without an outcome.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Attempt the second step.&lt;/li&gt;

&lt;li&gt;Generate an outcome with the result of the second step.&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The algorithm:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F754vf5nv1wlehho0n22d.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F754vf5nv1wlehho0n22d.png" alt="Optimistic lock enabled algorithm"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pessimistic lock enabled
&lt;/h2&gt;

&lt;p&gt;This task is an integration with a third party that allows to query if an attempt on the action has been performed before based on some form of metadata that includes the &lt;code&gt;Task identifier&lt;/code&gt;. If it has, it has to be possible to get the outcome of that previous attempt. The definition consists on:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A function that receives the event and the &lt;code&gt;Task identifier&lt;/code&gt;, attempts the task, and uses its outcome to make a decision.&lt;/li&gt;
&lt;li&gt;A function that receives the event and the &lt;code&gt;Task identifier&lt;/code&gt;, and determines whether the action has been tried before. If it has, reads the outcome of the task and makes a decision.&lt;/li&gt;
&lt;li&gt;A property that delimits how long can the task take in an attempt, cancelling it after that time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Task will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write a lock for the &lt;code&gt;Task identifier&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Verify that the lock just made is the oldest one not expired for this identifier.

&lt;ol&gt;
&lt;li&gt;If it isn't, aborts without an outcome.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Verify that there isn't a completed action in the service for this identifier.

&lt;ol&gt;
&lt;li&gt;If there is, it is guaranteed that the original process has expired, so emit an outcome with the result available.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Attempt the action.&lt;/li&gt;

&lt;li&gt;Generate an outcome with the result.&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The algorithm:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0x54l8r19v0cgxputlfl.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0x54l8r19v0cgxputlfl.png" alt="Pessimistic lock algorithm"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Black boxed
&lt;/h2&gt;

&lt;p&gt;This task in an integration with a third party that offers no way to determine whether an action or an attempt has been performed before. While it is possible to determine whether an attempt has started, it is not possible to determine if the third party actually received a request from the system unless the third party replied and the system was successful in storing the outcome.&lt;/p&gt;

&lt;p&gt;Since the task is attempted via a pessimistic lock, it is possible this means that if an expired lock exists and no decision has been recorded, the state of &lt;code&gt;possible failure&lt;/code&gt; is reached.&lt;/p&gt;

&lt;p&gt;The definition of this task consists on:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A function that receives the event and the &lt;code&gt;Task identifier&lt;/code&gt;, attempts the task, and uses its outcome to make a decision.&lt;/li&gt;
&lt;li&gt;A function that receives the event, the &lt;code&gt;Task identifier&lt;/code&gt;, and the time the previous attempt started and makes a decision.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Task will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write a lock for the &lt;code&gt;Task identifier&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Verify that the lock just made is the oldest one.

&lt;ol&gt;
&lt;li&gt;If it isn't, verify that every previous lock is past expiration, and with a registered fault.

&lt;ol&gt;
&lt;li&gt;If they all meet both conditions, continue.&lt;/li&gt;
&lt;li&gt;If there is at least one expired without a fault, emit an uncertainty outcome.&lt;/li&gt;
&lt;li&gt;If there is at least one that is neither expired nor faulted, register a fault for this attempt and abort without an outcome.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;/li&gt;

&lt;li&gt;Attempt the action.

&lt;ol&gt;
&lt;li&gt;If there's a fault, register the fault.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Generate an outcome with the result.&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The algorithm:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffun1z2t40yh4r89bvs1n.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffun1z2t40yh4r89bvs1n.png" alt="Black boxed algorithm"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  The Workflow
&lt;/h1&gt;

&lt;h1&gt;
  
  
  The core tenets of the framework
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Rejection is not failure
&lt;/h2&gt;

&lt;p&gt;The concept of a &lt;code&gt;Task&lt;/code&gt; is, when it comes to its outcome not concerned about which outcome means a success business wise, but about whether the action could be executed and a decision was made out of the outcome. This means that any possible result just represents the next possible state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Undo "A" is just do "B" when "A" has been done
&lt;/h2&gt;

&lt;p&gt;While the &lt;code&gt;Task&lt;/code&gt; is not concerned about business failure, the &lt;code&gt;Workflow&lt;/code&gt; itself is, there are actions that might need to be undone if subsequent &lt;code&gt;Tasks&lt;/code&gt; fail, this is not considered a special action in this framework, but just an action to perform after a certain precondition has been met. &lt;/p&gt;

&lt;h2&gt;
  
  
  All parties are third parties
&lt;/h2&gt;

&lt;p&gt;Even when the services integrated are developed, maintained and owned by the same company, even by the same team, treating any external service as a third party that can fail to respond leads to predictable software. While it might seem extreme, bear in mind that this treatment is done only once, as part of the framework, so the pressure of having to consider every outcome is released once designing the state machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Yes, even people are third party services
&lt;/h2&gt;

&lt;p&gt;In a &lt;code&gt;To Do Item&lt;/code&gt;, an external action is awaited, this might come from an employee of the company owning the system, a confirmation from a user, or even a user from the third party needing to click on a link. The expiration scenario, that is, when the action never happens, must be a clearly visible part of the design, as it is not a matter of “if”, but of “when” will it happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Insist, desist or react
&lt;/h2&gt;

&lt;p&gt;As complex as the decisions for faults in a &lt;code&gt;Task&lt;/code&gt; might seem, there are only three possible outcomes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retry the action, this is part of the retriability definition of the &lt;code&gt;Task&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Desist in the attempt, that is, deciding not to retry, and in the fault mapping function, continue the workflow towards a different &lt;code&gt;State&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;React to the fault, that is, deciding not to retry, and in the fault mapping function, continue the workflow towards a &lt;code&gt;To Do Item&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Optimism through deterministic pessimism
&lt;/h2&gt;

&lt;p&gt;Unless there's a performance &lt;strong&gt;problem actually happening&lt;/strong&gt;, treat both optimistic and pessimistic integrations as a pessimistic one.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Since an optimistic integration needs to happen in two steps, simply define every step as a different integration.&lt;/p&gt;

&lt;p&gt;⚠️ Remember that a performance &lt;strong&gt;concern&lt;/strong&gt; is not a performance &lt;strong&gt;problem actually happening&lt;/strong&gt;, the robustness of pessimistic locked actions allow for an aggressive distribution of the tasks amongst workers, reducing the time required to execute thousands of tasks to the longest execution time of a single one.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  The framework, by example
&lt;/h1&gt;

&lt;p&gt;The following example is the creation of an order. So simplify the model, any fault and expiration result that maps to a default exit, &lt;code&gt;Order cancelled&lt;/code&gt; in this case, can be left as an implicit mapping.&lt;/p&gt;

&lt;h3&gt;
  
  
  Legend
&lt;/h3&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj63bamzixgeujh6c0dnw.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj63bamzixgeujh6c0dnw.png" alt="Legend"&gt;&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftgeg1ggrcup2sr1nav34.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftgeg1ggrcup2sr1nav34.png" alt="Example of a real workflow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Glossary
&lt;/h1&gt;

&lt;h4&gt;
  
  
  Code safety:
&lt;/h4&gt;

&lt;p&gt;Property of code that handles every possible state it can go through. A safe function has constraints in its input, so every possible value that is allowed by the compiler is valid, never throws exceptions for any valid value of its input, and always returns a valid value, specified by its return type.&lt;/p&gt;

&lt;h4&gt;
  
  
  Completed task:
&lt;/h4&gt;

&lt;p&gt;A task that has executed without fault. This definition is not concerned whether the action was accepted or rejected.&lt;/p&gt;

&lt;p&gt;e.g. A fraud check that returns a result, regardless of the user being deemed trustworthy or not, has completed.&lt;/p&gt;

&lt;h4&gt;
  
  
  Concurrency handling:
&lt;/h4&gt;

&lt;p&gt;Capacity of a system to behave predictably when interacting with a resource that can be accessed by another process, be it a third party, another instance of the current system or another process that is part of the same system.&lt;/p&gt;

&lt;h4&gt;
  
  
  Failed task:
&lt;/h4&gt;

&lt;p&gt;A task that could not be completed after all the fault tolerance mechanisms have exhausted any option to recover, or the task can’t be performed for other reasons.&lt;/p&gt;

&lt;p&gt;e.g. An email provider throttled a request, a circuit breaker acts in to give the service some time to recover, after the request successfully goes through, it returns a Bad Request response because the content had some invalid characters.&lt;/p&gt;

&lt;p&gt;e.g. A SMS provider rejects an attempt to send a message because the associated account does not have enough credits.&lt;/p&gt;

&lt;h4&gt;
  
  
  Fault tolerance:
&lt;/h4&gt;

&lt;p&gt;Capacity of a system to continue functioning predictably after an external action fails to execute as expected, it is assumed that the fault is transient, that is, that the external system will be able to eventually respond.&lt;/p&gt;

&lt;h4&gt;
  
  
  Optimistic lock enabled action:
&lt;/h4&gt;

&lt;p&gt;An integration that can be done in two steps, provides a deterministic mechanism to identify the process as unique, and allows for the process to be cancelled.&lt;/p&gt;

&lt;h4&gt;
  
  
  Pessimistic lock enabled action:
&lt;/h4&gt;

&lt;p&gt;An integration that provides a deterministic mechanism to identify the process as unique, but lacks the other two characteristics of the optimistic lock enabled&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>eventdriven</category>
      <category>distributedsystems</category>
      <category>eventsourcing</category>
    </item>
    <item>
      <title>Coaches don’t play</title>
      <dc:creator>Rubén Domínguez Falcón</dc:creator>
      <pubDate>Wed, 02 Nov 2022 09:27:11 +0000</pubDate>
      <link>https://dev.to/theagilemonkeys/coaches-dont-play-3i03</link>
      <guid>https://dev.to/theagilemonkeys/coaches-dont-play-3i03</guid>
      <description>&lt;p&gt;I remember the first time I was promoted to a leadership position. I was thrilled, looking forward to all the new challenges this new position would bring. But I also remember the week after, how I found myself trying to complete the same tasks as before, but now also juggling additional meetings and management tasks.&lt;/p&gt;

&lt;p&gt;Clearly, something was wrong; becoming a leader shouldn't be "doing the same work but having more meetings".&lt;/p&gt;

&lt;p&gt;And it’s definitely not. I was seeing it from the wrong angle. I was about to learn that being a leader means you are not a player anymore.&lt;/p&gt;

&lt;h2&gt;
  
  
  You are not a player anymore.
&lt;/h2&gt;

&lt;p&gt;Imagine for a second that you are a soccer player and you're promoted to be the team's coach. Can you imagine yourself on the pitch, trying to score during the match?&lt;/p&gt;

&lt;p&gt;Yeah, it sounds ridiculous! Coaches are not supposed to play the match, but to guide the team. The same applies to any leader. &lt;strong&gt;Your goal is to guide your team to achieve the best results, not to do their job.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As a leader, you should focus on defining the strategy, clarifying goals, setting the right expectations, providing your team with the tools to succeed, and then letting them play the match.&lt;/p&gt;

&lt;p&gt;You should interiorize this concept because you'll find a lot of challenges that will test your leadership skills, like the delivery trap.&lt;/p&gt;

&lt;h2&gt;
  
  
  The delivery trap
&lt;/h2&gt;

&lt;p&gt;All projects have milestones and deadlines; the closer the deadline, the more conscious you become about the performance gaps in your team. In these situations, you might feel tempted to jump in and start doing their work.&lt;/p&gt;

&lt;p&gt;You'll find a lot of good reasons to jump in, "I want to lead by example", "It will be faster if I do it myself", "I want to support my team"...&lt;/p&gt;

&lt;p&gt;They are all excellent reasons, but it’s also the wrong decision. &lt;strong&gt;Everybody loses if you jump in and start working on your team's tasks.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By jumping in, you are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Removing the opportunity for your team to face the challenge and learn from it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Losing the opportunity to improve your leadership skills, because you’ll only be polishing the skills you already had from your old position.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;You should focus on improving your leadership skills to help your team.&lt;/strong&gt;&lt;br&gt;
With the pressure of a deadline, you should focus on redefining the plan, ensuring the expectations are clear, figuring out what's blocking your team, and helping them to perform at their very best.&lt;/p&gt;

&lt;p&gt;That way, iteration by iteration, your team will become better. Your ultimate goal should be to make your team grow to the point that they don't need you. The goal is to make yourself redundant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make yourself redundant
&lt;/h2&gt;

&lt;p&gt;One of the many good things about being in a leadership position is that it allows you to help people grow and develop their potential. If you do it well, after some time, your team will reach a point where they will be able to do their job without needing you; that's the ideal scenario.&lt;/p&gt;

&lt;p&gt;Once your team doesn't need you, you'll have the opportunity to join a different team and continue helping there. That is one of your key goals as a leader, to help people grow, and in doing so, help the company grow.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Swiss Army knives or Allen keys?</title>
      <dc:creator>Sebastián Pérez Pérez</dc:creator>
      <pubDate>Tue, 27 Sep 2022 09:58:07 +0000</pubDate>
      <link>https://dev.to/theagilemonkeys/swiss-army-knives-or-allen-keys-3933</link>
      <guid>https://dev.to/theagilemonkeys/swiss-army-knives-or-allen-keys-3933</guid>
      <description>&lt;p&gt;When you have to choose a tool to perform a task, you always have two options. You can go to the shop and buy a super versatile Swiss Army knife that will provide you with a lot of options for many different tasks, or you can go and buy a specific tool for a specific task. It will work perfectly for what you need it for, but you won’t be able to use it for anything else, like an Allen key.&lt;/p&gt;

&lt;p&gt;With the Swiss Army knife, you’ll be able to tighten certain screws, cut a piece of string, break a branch, build a spear, etc. On the other hand, with the Allen keys, you will be able to tighten hex screws only. So, it looks like an easy decision, doesn’t it? Go and buy the Swiss Army knife and you’ll have a tool that you can use for many situations, and you know it won’t just be thrown into your toolbox and never used again… &lt;/p&gt;

&lt;p&gt;But … what if you need to tighten loads of hex screws every day and have to do it quickly? Now, the decision to buy the Swiss Army knife doesn’t sound as obvious. Even though you know that you’ll use the Allen key just for that specific task, you’d probably prefer to have the best tool for the job.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;development&lt;/strong&gt;, when we have to &lt;strong&gt;build a team&lt;/strong&gt; and &lt;strong&gt;distribute the work&lt;/strong&gt; between the team members, we have to make a similar decision. Do we choose the Swiss Army knife or the Allen key?&lt;/p&gt;

&lt;p&gt;If I told you that you could have a team where all the team members could develop, test, define tasks, create the infrastructure, manage the deployments, automatize CI/CD pipelines, etc, and do it all really well and fast, it would sound like a dream come true, and you would sign up without question. But achieving that is no easy feat. It would take a long time and a lot of effort from the whole team, and that &lt;strong&gt;investment&lt;/strong&gt; would also have to be applied to new members that recently join the team.&lt;/p&gt;

&lt;p&gt;So if you think of the long term, and assuming that time is not a concern, I would say “Go for it! You will build the best team ever”. But working on a project where the timeline is not a constant concern doesn't usually happen, because in our business, &lt;strong&gt;time is money&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For most people however, the normal situation is to have &lt;strong&gt;strict deadlines&lt;/strong&gt;, because the client is waiting for an application, and the team has committed to delivering the product by a specific date. Usually, whatever that timeframe is, it’s never enough and we always have a lot to do during the final days leading up to the deployment.&lt;/p&gt;

&lt;p&gt;So, that means we need to &lt;strong&gt;optimize resources&lt;/strong&gt;, and try to get the best out of everyone if we want to meet the deadline successfully. And in that kind of situation where we have adjusted timelines, having &lt;strong&gt;specialists&lt;/strong&gt; for each task would be the best option. We can take advantage of each person’s strengths, and as a team, achieve our objective.&lt;/p&gt;

&lt;p&gt;This is the eternal debate of “&lt;strong&gt;specialization vs versatility&lt;/strong&gt;” but history tells us with &lt;a href="https://en.wikipedia.org/wiki/Scientific_management"&gt;Taylorism&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Fordism"&gt;Fordism&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Toyota_Production_System"&gt;Toyotism&lt;/a&gt;, that when &lt;strong&gt;productivity&lt;/strong&gt; and &lt;strong&gt;efficiency&lt;/strong&gt; become key for any requirement, specialization is the shorter and more successful path. And I have to say that I agree with history. Having a team where you could put anyone on to any task without affecting the &lt;strong&gt;performance&lt;/strong&gt; of the team is simply not realistic. Everyone has their own strengths and weaknesses, and everyone has their own skill set. Having a team of clones, where everyone is a champion at everything only happens in the best sci-fi movies. In my opinion, a good team leader should know their team and take advantage of the &lt;strong&gt;capabilities&lt;/strong&gt; of each person. They should be able to configure the team where they complement each other, leveraging their strengths and focusing on the tasks that they can nail.&lt;/p&gt;

&lt;p&gt;Of course, investing in &lt;strong&gt;learning&lt;/strong&gt; should be a top priority for any company, because at the end of the day people are what really matter. They must be the center around which the company should be built. And the only way to achieve that is to provide time and create an environment where your team can learn, increase their skills and grow professionally. They are the seeds, and with the right environment, they will grow into an extremely strong team. That is the long term goal, a team of Swiss Army knives. But when a project requires fast and decisive decisions and actions, choosing specialization over versatility is the key.&lt;/p&gt;

</description>
      <category>development</category>
      <category>team</category>
      <category>specialization</category>
      <category>learning</category>
    </item>
    <item>
      <title>Web Pentesting Learning - Beginner edition</title>
      <dc:creator>J2RGEZ</dc:creator>
      <pubDate>Thu, 01 Sep 2022 09:37:07 +0000</pubDate>
      <link>https://dev.to/theagilemonkeys/web-pentesting-learning-beginner-edition-4clg</link>
      <guid>https://dev.to/theagilemonkeys/web-pentesting-learning-beginner-edition-4clg</guid>
      <description>&lt;p&gt;After a couple of years of learning on my own, I created a brief list of the assets I think were most useful for me at the time of learning web pentesting. Hope you find it helpful!&lt;/p&gt;

&lt;h2&gt;
  
  
   Books
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Linux Basics for Hackers: Getting Started with Networking, Scripting, and Security in Kali, by OccupyTheWeb&lt;/strong&gt;. =&amp;gt; Beginner friendly and very well written.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Penetration Testing: A Hands-On Introduction to Hacking, by Georgia Weidman&lt;/strong&gt; =&amp;gt; In my opinion it’s a bit outdated and some parts are difficult to understand but still a very good book.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web Hacking 101, by Peter Yaworski&lt;/strong&gt; =&amp;gt; A summary of all common web vulnerabilities with examples.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hands-On Penetration Testing on Windows, by Phil Bramwell&lt;/strong&gt; =&amp;gt; Also focusing on the registry tree and how the most common keys work (such as kerberos keys that handles authentication). Microsoft official docs are good for this.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Twitter accounts
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/three_cube"&gt;@three_cube&lt;/a&gt; a.k.a OccupytheWeb. This is from the author of the first book listed above and also has a very good hacking blog: &lt;a href="https://www.hackers-arise.com/"&gt;https://www.hackers-arise.com/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/theXSSrat"&gt;@theXSSrat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/stokfredrik"&gt;@stokfredik&lt;/a&gt; =&amp;gt;The coolest hacker ever! He also has a great YouTube channel&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/NahamSec"&gt;@NahamSec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/TheHackersNews"&gt;@TheHackersNews&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/thecybermentor"&gt;@thecybermentor&lt;/a&gt; and &lt;a href="https://twitter.com/TCMSecurity"&gt;@TCMSecurity&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Overall &lt;strong&gt;#infosec&lt;/strong&gt; twitter is a very good place to start reading writeups and latest news.&lt;/p&gt;

&lt;h2&gt;
  
  
  Platforms to get your hands dirty
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.pentesterlab.com/"&gt;Pentesterlab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tryhackme.com/"&gt;Tryhackme&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.hackthebox.com/"&gt;Hackthebox&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you’re just starting, I recommend Tryhackme. It’s amazing! And it has a lot of walkthrough boxes (just be aware of &lt;a href="https://tryhackme.com/resources/blog/tryhackmes-vpn-explained"&gt;this&lt;/a&gt;). Then, I would jump to Hackthebox which has the most realistic machines. In my opinion pentesterlab is a bit expensive for the quality their competitors have for almost half the price, but their certificates are good.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug bounty platforms
&lt;/h2&gt;

&lt;p&gt;Bug bounty is about hacking as a freelancer, but it’s nice to read writeups (if public), as these are real business-level vulnerabilities. Also reading about bug bounty will teach you tricks to increase your speed and overall organization, which is one of the key skills you need in this category. Why? Because you want to report your findings before anyone else to get paid and avoid duplicates. Hackerone is one of these platforms: &lt;a href="https://hackerone.com/directory/programs?order_direction=DESC&amp;amp;order_field=resolved_report_count"&gt;https://hackerone.com/directory/programs?order_direction=DESC&amp;amp;order_field=resolved_report_count&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools you should know (basic level)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.metasploit.com/"&gt;Metasploit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sqlmap.org/"&gt;sqlmap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nmap.org/"&gt;nmap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://portswigger.net/burp"&gt;Burp Suite&lt;/a&gt; or any other web scanner alternative&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.kali.org/tools/hydra/"&gt;Hydra&lt;/a&gt; login cracker&lt;/li&gt;
&lt;li&gt;Any hash cracker like &lt;a href="https://www.openwall.com/john/"&gt;john the ripper&lt;/a&gt;, &lt;a href="https://hashcat.net/hashcat/"&gt;hashcat&lt;/a&gt;, etc&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.shodan.io/"&gt;Shodan&lt;/a&gt;: at least to understand what it is, in case you want to use it one day&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What are writeups?&lt;/strong&gt; Instructions about how someone hacked something in detail.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’m most probably missing something here, but I think it’s a nice starting point. Let me know in the comments if you would add anything else to this list and/or what helped you when you started learning pentesting.&lt;/p&gt;

</description>
      <category>pentesting</category>
      <category>security</category>
      <category>infosec</category>
    </item>
    <item>
      <title>How to build a native iOS dApp that uses the Flow blockchain as the backend</title>
      <dc:creator>Juan Sagasti</dc:creator>
      <pubDate>Thu, 07 Jul 2022 22:59:11 +0000</pubDate>
      <link>https://dev.to/theagilemonkeys/how-to-buid-a-native-ios-dapp-that-uses-the-flow-blockchain-as-the-backend-n9k</link>
      <guid>https://dev.to/theagilemonkeys/how-to-buid-a-native-ios-dapp-that-uses-the-flow-blockchain-as-the-backend-n9k</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This is the second and final part of a web3 tutorial about the &lt;a href="https://www.onflow.org/" rel="noopener noreferrer"&gt;Flow blockchain&lt;/a&gt;. &lt;strong&gt;Understanding the first part is essential and a pre-requisite&lt;/strong&gt; because I explain there how to create and test Smart Contracts, the one we developed to create notes, its API, and how to write transactions and scripts to mutate and read data in the blockchain. Please take your time and make sure you understand it before continuing :) &lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/theagilemonkeys/web3-tutorial-a-notepad-in-the-flow-blockchain-5458"&gt;First part: A notepad in the Flow blockchain&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, in this final part, you will learn:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;How to deploy smart contracts&lt;/strong&gt; in a Flow blockchain network: &lt;code&gt;testnet&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How to build an iOS dApp&lt;/strong&gt; that communicates with that contract in Flow's &lt;code&gt;testnet&lt;/code&gt;. For user authentication, the app will use the &lt;a href="https://portto.com" rel="noopener noreferrer"&gt;Blocto Wallet&lt;/a&gt;, a cross-chain crypto wallet compatible with Flow. I assume you have a basic understanding of iOS programming. We will be using &lt;em&gt;SwiftUI&lt;/em&gt; + &lt;em&gt;Combine&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Deploying the Smart Contract
&lt;/h2&gt;

&lt;p&gt;Note that the &lt;code&gt;NotepadManager&lt;/code&gt; contract we will be using in the iOS dApp is already deployed in a flow account of my own. Remember that you can use any public smart contract in the blockchain, so you don't need to deploy the contract again in every account that wants to use it, as we learned in the previous article. This step is only for learning purposes in case you are interested in how to deploy contracts. &lt;strong&gt;You can skip this section&lt;/strong&gt; and go directly to the dApp implementation part.&lt;/p&gt;

&lt;p&gt;We are going to deploy the &lt;code&gt;NotepadManager&lt;/code&gt; contract to the &lt;code&gt;testnet&lt;/code&gt;, which is nearly identical to the &lt;code&gt;mainnet&lt;/code&gt;, but we can operate without paying real gas. This is ideal for learning and testing our projects before deploying them to the production network (&lt;code&gt;mainnet&lt;/code&gt;).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://docs.onflow.org/flow-cli/install/" rel="noopener noreferrer"&gt;Install the Flow CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.onflow.org/flow-cli/generate-keys/" rel="noopener noreferrer"&gt;Generate the account keys&lt;/a&gt;. &lt;strong&gt;Remember to safely store the private key and don't share it with anyone.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Create a Testnet flow account &lt;a href="https://testnet-faucet.onflow.org" rel="noopener noreferrer"&gt;here&lt;/a&gt; with your public key.&lt;/li&gt;
&lt;li&gt;Create a folder for your contracts project, open it in the terminal, and do &lt;code&gt;flow init&lt;/code&gt;. This will create a &lt;code&gt;flow.json&lt;/code&gt; file with a default configuration.&lt;/li&gt;
&lt;li&gt;Open your project folder in an editor. I'm using Visual Studio Code, which has an excellent Cadence plugin you can install from the Extensions Marketplace. &lt;/li&gt;
&lt;li&gt;Add a new file to your project called &lt;code&gt;NotepadManager.cdc&lt;/code&gt;. Paste the contract code we developed in the &lt;a href="https://dev.to/theagilemonkeys/web3-tutorial-a-notepad-in-the-flow-blockchain-5458"&gt;previous article&lt;/a&gt;. You can find it in the &lt;a href="https://play.onflow.org/ee8594f9-e491-45cb-a9d6-d6ef759dda93?type=account&amp;amp;id=5722cef9-e962-4458-9123-2b7bbb5f2434&amp;amp;storage=0x02" rel="noopener noreferrer"&gt;Playground&lt;/a&gt;, too.&lt;/li&gt;
&lt;li&gt;Edit the flow.json file so it looks like this:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"emulators"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"contracts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"NotepadManagerV1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NotepadManagerV1.cdc"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"networks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"emulator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"127.0.0.1:3569"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"mainnet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"access.mainnet.nodes.onflow.org:9000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"testnet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"access.devnet.nodes.onflow.org:9000"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"accounts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"my-testnet-account"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"address"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR ACCOUNT ADDRESS (without the '0x' prefix)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR PRIVATE KEY"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"deployments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"testnet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"my-testnet-account"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"NotepadManagerV1"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that we emptied the &lt;em&gt;"emulators"&lt;/em&gt; field because we won't be using the local emulator but a real network. We also added the &lt;em&gt;"contracts"&lt;/em&gt; and &lt;em&gt;"deployments"&lt;/em&gt; fields to point to our contract and account. &lt;/p&gt;

&lt;p&gt;Remember to fill the &lt;em&gt;"address"&lt;/em&gt; and &lt;em&gt;"key"&lt;/em&gt; fields, as specified. You obtained your account address in step #3 and the private key in step #2. Be careful with that key, and don't commit it to a public repository. &lt;/p&gt;

&lt;p&gt;Now that everything is set up, it's time to deploy the contract! In the terminal, in your project folder, do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flow project deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll see something 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;  Deploying 1 contracts for accounts: my-testnet-account
  NotepadManagerV1 -&amp;gt; 0x9bde7238c9c39e97 (09d8818a9d41ae2fc92f9dd6d7355772e7d97e28fb9e20b2f66f473420a16b31) 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which can be read as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NotepadManagerV1 -&amp;gt; the address containing it (the transaction ID)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see the transaction status or the account details through blockchain explorers like &lt;a href="https://testnet.flowscan.org" rel="noopener noreferrer"&gt;Tesnet Flowscan&lt;/a&gt; or &lt;a href="https://flow-view-source.com" rel="noopener noreferrer"&gt;Flow View Source&lt;/a&gt;. For example, if I introduce my account address &lt;code&gt;0x9bde7238c9c39e97&lt;/code&gt; in Flowscan:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkibuozxuwiumsvqtfu8v.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkibuozxuwiumsvqtfu8v.png" alt="Flowscan"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;You can see the account balance, transaction history, and contracts deployed to the account. If you click the &lt;code&gt;NotepadManagerV1&lt;/code&gt; link, you can see the contract's code! This is powerful for public audits of the contracts in the blockchain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;Our iOS dApp will have a pretty straightforward architecture:&lt;br&gt;
&lt;a href="https://media.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%2Fvxf1us7da2ebrbdkjs3l.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvxf1us7da2ebrbdkjs3l.png" alt="dApp Architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All the elements in that picture are &lt;code&gt;.swift&lt;/code&gt; files. You can start by creating an Xcode project (iOS 15.5 for the time being) and all those files. Files with the &lt;code&gt;...View&lt;/code&gt; suffix are SwiftUI views.&lt;/p&gt;

&lt;p&gt;For communicating with the Flow blockchain, we will be using the &lt;a href="https://github.com/Outblock/fcl-swift" rel="noopener noreferrer"&gt;iOS SDK&lt;/a&gt; that &lt;a href="https://outblock.io" rel="noopener noreferrer"&gt;Outblock&lt;/a&gt; is building. A big update containing breaking changes is planned to be released soon, so we are going to lock now the SDK version to a particular commit (latest as of today) to be sure our code keeps working overtime. To do that, just add the dependency of the Swift Package Manager tied to the &lt;code&gt;b4a9cfaaa0003f3f250490e6ccdf8b75065199a3&lt;/code&gt; commit:&lt;br&gt;
&lt;a href="https://media.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%2Fxmi42stvghmuwtplgulr.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxmi42stvghmuwtplgulr.png" alt="Package Dependency"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can start adding code to our Swift files! &lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;FlowNotesApp.swift&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This is the entry point of our app. It's in charge of initializing the fcl-swift framework with the needed endpoints to communicate with the Flow blockchain and Blocto Wallet and showing the &lt;code&gt;LoginView&lt;/code&gt; or the &lt;code&gt;MyNotesView&lt;/code&gt; depending on the user's authorization state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Combine&lt;/span&gt;
&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;FCL&lt;/span&gt;
&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;SwiftUI&lt;/span&gt;

&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="kt"&gt;UI&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;flowGreen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;red&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;green&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;130&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;@main&lt;/span&gt;
&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;FlowNotesApp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;App&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;@State&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;User&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;

    &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// FCL configuration with the Tesnet Nodes URLs needed &lt;/span&gt;
        &lt;span class="c1"&gt;// to stablish the connection with the blockchain and &lt;/span&gt;
        &lt;span class="c1"&gt;// the Blocto Wallet:&lt;/span&gt;
        &lt;span class="n"&gt;fcl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;appName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"FlowNotes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="nv"&gt;appIcon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"https://placekitten.com/g/200/200"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="nv"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"https://foo.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="nv"&gt;walletNode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"https://fcl-discovery.onflow.org/testnet/authn"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="nv"&gt;accessNode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"https://access-testnet.onflow.org"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="nv"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"testnet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="nv"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="nv"&gt;authn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"https://flow-wallet-testnet.blocto.app/api/flow/authn"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;flowGreenColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;UIColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;cgColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flowGreen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cgColor&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="kt"&gt;UIColor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;green&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cgColor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// Color to UIColor conversion&lt;/span&gt;
        &lt;span class="kt"&gt;UINavigationBar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appearance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;largeTitleTextAttributes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;foregroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flowGreenColor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="kt"&gt;UINavigationBar&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appearance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;titleTextAttributes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;foregroundColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flowGreenColor&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;Scene&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;WindowGroup&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;VStack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;currentUser&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="kt"&gt;MyNotesView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MyNotesVM&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="kt"&gt;LoginView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preferredColorScheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onReceive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fcl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;$currentUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
                &lt;span class="n"&gt;currentUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;LoginView.swift&lt;/code&gt;
&lt;/h3&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkx6b8eq69avpf1yp2ea7.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkx6b8eq69avpf1yp2ea7.png" alt="LoginView"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Simple screen with a big login button that invokes the &lt;code&gt;authenticate()&lt;/code&gt; method on the &lt;code&gt;LoginVM&lt;/code&gt; &lt;em&gt;ViewModel&lt;/em&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;LoginVM.swift&lt;/code&gt;
&lt;/h3&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fku3xayaa8yxas713053w.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fku3xayaa8yxas713053w.png" alt="Blocto Wallet authentication"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;authenticate()&lt;/code&gt; method will invoke the FCL's authentication method, which will present us with the Blocto Wallet webView for the user to log in. After successful authentication, the FCL's &lt;code&gt;currentUser&lt;/code&gt; property will be populated, triggering an update in our &lt;em&gt;FlowNotesApp&lt;/em&gt; class, which is listening to that property. The &lt;code&gt;MyNotesView&lt;/code&gt; will be shown then.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Combine&lt;/span&gt;
&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;FCL&lt;/span&gt;
&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Foundation&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;LoginVM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ObservableObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;cancellables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;AnyCancellable&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fcl&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
                &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;receiveValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
                &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cancellables&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;MyNotesView.swift&lt;/code&gt;
&lt;/h3&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbdpj1uhz5t8t44oetscs.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbdpj1uhz5t8t44oetscs.png" alt="MyNotesView"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This view is in charge of showing the list of notes retrieved by &lt;code&gt;MyNotesVM&lt;/code&gt;. The users can also: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Delete notes with the swipe-to-left gesture.&lt;/li&gt;
&lt;li&gt;Present the &lt;code&gt;NoteEditorView&lt;/code&gt; from the "+" button to create new notes. &lt;/li&gt;
&lt;li&gt;Show the action menu from the "..." button. Here, users can manually refresh the list, delete the entire Notepad or sign out. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You will note that the transactions are pretty slow compared to a regular backend. This is because mutations of the blockchain need to be accepted and mined, which could take several seconds to happen. For simplicity, we present a full-screen loading screen while the VM's state is &lt;code&gt;loading&lt;/code&gt;, until the transaction is sealed and a script can safely retrieve the final result. Read-only operations (scripts) like the notes fetch are blazing fast. If the transaction fails with an error, we present it to the user with an &lt;code&gt;AlertView&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As you see, the transactions and script code used here are nearly identical to the ones in the first article (I omitted the comments in these to avoid repetition):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;SwiftUI&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;MyNotesView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;@StateObject&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MyNotesVM&lt;/span&gt;

    &lt;span class="kd"&gt;@State&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;isLoading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="kd"&gt;@State&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;isShowingNoteEditor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="kd"&gt;@State&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;isShowingErrorAlert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

    &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MyNotesVM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_vm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;wrappedValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;signOutButton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;Button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;signOut&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sign Out"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;systemImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"person.crop.circle.badge.xmark"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;refreshNotepadButton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;Button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;queryNotes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Refresh notepad"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;systemImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"arrow.clockwise"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;deleteNotepadButton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;Button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deleteNotepad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Delete notepad"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;systemImage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"trash"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notes&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notes&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;moreOptionsButton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;Menu&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;refreshNotepadButton&lt;/span&gt;
            &lt;span class="kt"&gt;Divider&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;deleteNotepadButton&lt;/span&gt;
            &lt;span class="kt"&gt;Divider&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;signOutButton&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;systemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"ellipsis"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;addNoteButton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;Button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;isShowingNoteEditor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;systemName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"plus"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;ZStack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;NavigationView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;Group&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;notes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notes&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="kt"&gt;List&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                            &lt;span class="kt"&gt;ForEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;note&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
                                &lt;span class="kt"&gt;NoteRow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;note&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listRowBackground&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Color&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;black&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                            &lt;span class="p"&gt;}&lt;/span&gt;
                            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onDelete&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
                                &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deleteNote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;atIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                            &lt;span class="p"&gt;}&lt;/span&gt;
                        &lt;span class="p"&gt;}&lt;/span&gt;

                    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loading&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="kt"&gt;EmptyView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Your notepad is empty 🤓&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Add a new note from&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;the'＋'button"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;multilineTextAlignment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;center&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;font&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headline&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;foregroundColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gray&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigationBarItems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;leading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;moreOptionsButton&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;trailing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;addNoteButton&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigationTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Flow Notes"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flowGreen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="kt"&gt;ZStack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;Color&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;black&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;edgesIgnoringSafeArea&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isLoading&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                &lt;span class="kt"&gt;ProgressView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"On it! 🚀 &lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Please wait..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;multilineTextAlignment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;center&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;foregroundColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;white&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;progressViewStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;CircularProgressViewStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;tint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;white&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isLoading&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;newValue&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="n"&gt;isLoading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newValue&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loading&lt;/span&gt;
            &lt;span class="n"&gt;isShowingErrorAlert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newValue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isFailed&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;isPresented&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;$isShowingErrorAlert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;Alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error!"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="nv"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errorMessage&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="s"&gt;"Unknown"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                  &lt;span class="nv"&gt;dismissButton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"OK"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;currentErrorDidDismiss&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}))&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sheet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;isPresented&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;$isShowingNoteEditor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;isShowingNoteEditor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;NoteEditorView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;environmentObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;NoteRow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;note&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Note&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;HStack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;VStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;alignment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;leading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;foregroundColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;black&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;font&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

                &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;foregroundColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;black&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;font&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;caption&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="kt"&gt;Spacer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;background&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flowGreen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cornerRadius&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;PreviewWrapper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;vm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;MyNotesVM&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Note&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"This is a great note"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"This is the body of a great note."&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                    &lt;span class="kt"&gt;Note&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Another note"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"The best body that was ever written."&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;MyNotesView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preferredColorScheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;MyNotesView_Previews&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;PreviewProvider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;previews&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;PreviewWrapper&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;MyNotesVM&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This is the VM that defines the set of operations available to mutate the notepad through transactions or fetch the notes through a script. &lt;/p&gt;

&lt;p&gt;Every time you send a transaction, the SDK will present a transaction confirmation screen (webView) from the Blocto Wallet, so you can review the transaction's code and approve it:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F29xzckyg5t3xaexa7r4g.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F29xzckyg5t3xaexa7r4g.png" alt="Transaction Confirmation Screen"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;
&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Combine&lt;/span&gt;
&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;FCL&lt;/span&gt;
&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Flow&lt;/span&gt;
&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Foundation&lt;/span&gt;

&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="kt"&gt;LoadingState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Equatable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;idle&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;loading&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nf"&gt;didFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;isFailed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;didFail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;didFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;MyNotesVM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;ObservableObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;@Published&lt;/span&gt; &lt;span class="kd"&gt;private(set)&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;LoadingState&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;idle&lt;/span&gt;
    &lt;span class="kd"&gt;@Published&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Note&lt;/span&gt;&lt;span class="p"&gt;]?&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;notepadManagerAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0x9bde7238c9c39e97"&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;cancellables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;AnyCancellable&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;queryNotes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// MARK: - Public API&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;createNote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="n"&gt;fcl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loading&lt;/span&gt;

        &lt;span class="n"&gt;fcl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mutate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;cadence&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Transaction that checks if the Notepad &lt;/span&gt;
                &lt;span class="c1"&gt;// exists (and creates it if needed) before &lt;/span&gt;
                &lt;span class="c1"&gt;// creating and adding the note to it:&lt;/span&gt;
                 &lt;span class="s"&gt;"""
                 import NotepadManagerV1 from &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;notepadManagerAddress&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;

                 transaction {
                     prepare(acct: AuthAccount) {
                         var notepad = acct.borrow&amp;lt;&amp;amp;NotepadManagerV1.Notepad&amp;gt;(from: /storage/NotepadV1)

                         if notepad == nil { 
                             // Create it and make it public
                             acct.save(&amp;lt;- NotepadManagerV1.createNotepad(), to: /storage/NotepadV1)
                             acct.link&amp;lt;&amp;amp;NotepadManagerV1.Notepad&amp;gt;(/public/PublicNotepadV1, target: /storage/NotepadV1)
                         }

                         var theNotepad = acct.borrow&amp;lt;&amp;amp;NotepadManagerV1.Notepad&amp;gt;(from: /storage/NotepadV1)
                         theNotepad?.addNote(title: "&lt;/span&gt;&lt;span class="p"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s"&gt;", body: "&lt;/span&gt;&lt;span class="p"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s"&gt;")
                     }
                 }
                 """&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="n"&gt;gasLimit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="mi"&gt;1000&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;completion&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;completion&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;didFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;localizedDescription&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;receiveValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;transactionId&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;self&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForSealedTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transactionId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;queryNotes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cancellables&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;deleteNote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;atIndex&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="n"&gt;fcl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;idToDelete&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;?[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loading&lt;/span&gt;

        &lt;span class="n"&gt;fcl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mutate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;cadence&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Transaction that tries to delete the note &lt;/span&gt;
                &lt;span class="c1"&gt;// if the Notepad exists:&lt;/span&gt;
                 &lt;span class="s"&gt;"""
                 import NotepadManagerV1 from &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;notepadManagerAddress&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;

                 transaction {
                     prepare(acct: AuthAccount) {
                            let notepad = acct.borrow&amp;lt;&amp;amp;NotepadManagerV1.Notepad&amp;gt;(from: /storage/NotepadV1)
                            notepad?.deleteNote(noteID: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;idToDelete&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;)
                     }
                 }
                 """&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="n"&gt;gasLimit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="mi"&gt;1000&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;completion&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;completion&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;didFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;localizedDescription&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;receiveValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;transactionId&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;self&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForSealedTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transactionId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;queryNotes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cancellables&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;deleteNotepad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="n"&gt;fcl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loading&lt;/span&gt;

        &lt;span class="n"&gt;fcl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mutate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;cadence&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Transaction that deletes the Notepad:&lt;/span&gt;
                 &lt;span class="s"&gt;"""
                 import NotepadManagerV1 from &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;notepadManagerAddress&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;

                 transaction {
                     prepare(acct: AuthAccount) {
                         var notepad &amp;lt;- acct.load&amp;lt;@NotepadManagerV1.Notepad&amp;gt;(from: /storage/NotepadV1)!
                         NotepadManagerV1.deleteNotepad(notepad: &amp;lt;- notepad)
                     }
                 }
                 """&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="n"&gt;gasLimit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="mi"&gt;1000&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;completion&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;completion&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;didFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;localizedDescription&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;receiveValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;transactionId&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;self&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForSealedTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transactionId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;idle&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cancellables&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;queryNotes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;currentUserAddress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fcl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loading&lt;/span&gt;

        &lt;span class="n"&gt;fcl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;cadence&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Script that tries to get all notes from the &lt;/span&gt;
                &lt;span class="c1"&gt;// current Notepad. It returns nil in case the &lt;/span&gt;
                &lt;span class="c1"&gt;// Notepad doesn't exist yet publicly:&lt;/span&gt;
                &lt;span class="s"&gt;"""
                import NotepadManagerV1 from &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;notepadManagerAddress&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;

                pub fun main(): [NotepadManagerV1.NoteDTO]? {
                    let notepadAccount = getAccount(0x&lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;currentUserAddress&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;)

                    let notepadCapability = notepadAccount.getCapability&amp;lt;&amp;amp;NotepadManagerV1.Notepad&amp;gt;(/public/PublicNotepadV1)
                    let notepadReference = notepadCapability.borrow()

                    return notepadReference == nil ? nil : notepadReference?.allNotes()
                }
                """&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;completion&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;self&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;completion&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;didFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;localizedDescription&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;receiveValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;self&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;valuesArray&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toOptional&lt;/span&gt;&lt;span class="p"&gt;()?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;idle&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Note&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;valuesArray&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;compactMap&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;noteData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toStruct&lt;/span&gt;&lt;span class="p"&gt;()?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="c1"&gt;// It's not the best decoding code, but enough &lt;/span&gt;
                &lt;span class="c1"&gt;// for what we are illustrating. The SDK &lt;/span&gt;
                &lt;span class="c1"&gt;// maintainer is working on a better data &lt;/span&gt;
                &lt;span class="c1"&gt;// decoder for future versions.&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;noteData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUInt64&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;noteData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;noteData&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

                &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;Note&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;notes&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;idle&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;cancellables&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;currentErrorDidDismiss&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;idle&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;signOut&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fcl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// MARK: - Private&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;waitForSealedTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;transactionId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;onSuccess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// We are using a background thread because we don't &lt;/span&gt;
        &lt;span class="c1"&gt;// want the .wait() to block the main event loop:&lt;/span&gt;
        &lt;span class="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;global&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;qos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userInitiated&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// We want to wait for the transaction to be &lt;/span&gt;
                &lt;span class="c1"&gt;// sealed (last transaction state) because we &lt;/span&gt;
                &lt;span class="c1"&gt;// need the final result to be available in &lt;/span&gt;
                &lt;span class="c1"&gt;// the blockchain. It's slower, but we don't &lt;/span&gt;
                &lt;span class="c1"&gt;// want intermediate transaction states where &lt;/span&gt;
                &lt;span class="c1"&gt;// you can still get empty errors or data when &lt;/span&gt;
                &lt;span class="c1"&gt;// querying the blockchain with a Script.&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="kt"&gt;Flow&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;transactionId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onceSealed&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

                &lt;span class="c1"&gt;// And we update the state again in the main thread:&lt;/span&gt;
                &lt;span class="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errorMessage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isEmpty&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;didFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;errorMessage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nf"&gt;onSuccess&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;DispatchQueue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;didFail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;localizedDescription&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;NoteEditorView.swift&lt;/code&gt;
&lt;/h3&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fykr14lqcdcyh73x1vq8p.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fykr14lqcdcyh73x1vq8p.png" alt="NoteEditorView"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;NoteEditorView&lt;/code&gt; is just a form to compose and send a new note.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;SwiftUI&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;NoteEditorView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;@EnvironmentObject&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;MyNotesVM&lt;/span&gt;
    &lt;span class="kd"&gt;@Environment&lt;/span&gt;&lt;span class="p"&gt;(\&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dismiss&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;dismiss&lt;/span&gt;

    &lt;span class="kd"&gt;@State&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;noteTitle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
    &lt;span class="kd"&gt;@State&lt;/span&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;noteBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;canSaveNote&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;noteTitle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isEmpty&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;noteBody&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isEmpty&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;saveButton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Save"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;vm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createNote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;noteTitle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;noteBody&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;dismiss&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;canSaveNote&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;canSaveNote&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;NavigationView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;VStack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;VStack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="kt"&gt;TextField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;$noteTitle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;foregroundColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;black&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;font&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accentColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;black&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vertical&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                    &lt;span class="kt"&gt;TextField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Body"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;$noteBody&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;foregroundColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;black&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accentColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;black&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vertical&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;horizontal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;background&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flowGreen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cornerRadius&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                &lt;span class="kt"&gt;Spacer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigationTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"New note"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigationBarTitleDisplayMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inline&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigationBarItems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;trailing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;saveButton&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UI&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flowGreen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;NoteEditor_Previews&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;PreviewProvider&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;previews&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;NoteEditorView&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preferredColorScheme&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;environmentObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;MyNotesVM&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;Note.swift&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Just the Note model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Flow&lt;/span&gt;
&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Foundation&lt;/span&gt;

&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;Note&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UInt64&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it! I hope you find this helpful and that it inspires you to find more cool use cases. If you want to see a full demo video in action and check this project's source code, please refer to the &lt;a href="https://github.com/jfsagasti/FlowNotes" rel="noopener noreferrer"&gt;FlowNotes repository&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;There's an edit transaction use case in the &lt;code&gt;NotepadManager&lt;/code&gt; contract that I haven't used in the app. I leave it to you as an exercise if you are motivated enough :)&lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

</description>
      <category>ios</category>
      <category>web3</category>
      <category>blockchain</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Web3 tutorial: A notepad in the Flow blockchain</title>
      <dc:creator>Juan Sagasti</dc:creator>
      <pubDate>Tue, 28 Jun 2022 16:04:00 +0000</pubDate>
      <link>https://dev.to/theagilemonkeys/web3-tutorial-a-notepad-in-the-flow-blockchain-5458</link>
      <guid>https://dev.to/theagilemonkeys/web3-tutorial-a-notepad-in-the-flow-blockchain-5458</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;While learning about web3 and blockchain technologies at &lt;a href="https://www.theagilemonkeys.com" rel="noopener noreferrer"&gt;&lt;strong&gt;The Agile Monkeys&lt;/strong&gt;&lt;/a&gt;, we found out &lt;a href="https://www.onflow.org/" rel="noopener noreferrer"&gt;Flow&lt;/a&gt;. According to them, &lt;em&gt;"Flow was designed for exceptional consumer and developer UX"&lt;/em&gt;. And after playing with it for some time, I agree with that. Their developer UX is among the best, if not the best, we've tried. Some things that make Flow different are: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A greener web3 network.&lt;/strong&gt; Flow starts with HotStuff, a proven Proof of Stake consensus mechanism, and adds a unique multi-node architecture to drive dramatic improvements in speed, throughput, and environmental friendliness without sharding or "layer two". This means Flow is the greenest web3 network among leading platforms.&lt;/li&gt;
&lt;/ul&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy3oh1s6sodsl9yd66d0n.gif" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy3oh1s6sodsl9yd66d0n.gif" alt="Multi-node architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resource-oriented programming with &lt;a href="https://docs.onflow.org/cadence/" rel="noopener noreferrer"&gt;Cadence&lt;/a&gt;&lt;/strong&gt;, their own programming language. If you are familiar with Swift, Rust, or TypeScript, you will love Cadence and will be writing Smart Contracts in no time. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Playgrounds.&lt;/strong&gt; An online editor to write and test your Smart Contracts without needing to deploy them to the main or test networks. You can focus first on the business logic. This is what we will be using in this tutorial. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Upgradeable Smart Contracts.&lt;/strong&gt; Securely and transparently patch bugs and upgrade pre-specified parts of a smart contract.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No Sharding.&lt;/strong&gt; On Flow, every application can be a platform. Smart contracts and user accounts on Flow can always interact with each other in one atomic, consistent, isolated, and durable (ACID) transaction. In other words: all applications on Flow can run in the same shared execution state. This ensures Flow apps benefit from great user experience and full composability, letting developers easily build on each other’s work. Sharding and layer 2 solutions break composability and reduce network effects for dApps and smart contracts by removing ACID guarantees from the execution environment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Client libraries to help you build your dApps, Smart User Accounts, and more!&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;First of all, why will we build a notepad on the blockchain? That makes no sense! I know paying gas fees for creating notes wouldn't be an ideal use case. But the Internet is already crowded with NFTs tutorials, and I wanted a more classic approach for non-web3 devs that illustrates how Smart Contracts + the user account in Flow can act as the API and the backend of our hypothetical dApp. And hopefully, this will give you more ideas about other possible dApps!&lt;/p&gt;

&lt;p&gt;Cadence is a resource-oriented programming language. This means it makes it easy to work with digital assets (resources) as if they were physical assets. A resource can only be in one place at a time. So, for example, if you &lt;em&gt;assign&lt;/em&gt; (this is, move with the &lt;code&gt;&amp;lt;-&lt;/code&gt; operator) a resource to a new variable, the resource won't be available in the original variable anymore, and that variable will be invalid:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;movedResource&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;originalResource&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes the experience of working with digital assets pretty natural. A resource can't be left forgotten in a variable. It must live in your user account or should be destroyed at the end of the function you are currently executing. Otherwise, the compiler will complain about the resource loss. It's pretty safe in this regard. &lt;/p&gt;

&lt;p&gt;I encourage you to read the quick &lt;a href="https://docs.onflow.org/cadence/" rel="noopener noreferrer"&gt;Introduction to Cadence&lt;/a&gt; and the &lt;a href="https://docs.onflow.org/cadence/language/" rel="noopener noreferrer"&gt;Cadence Language Reference&lt;/a&gt; before continuing this tutorial if you want to understand things better. Much of the language's syntax is inspired by Swift, Kotlin, and TypeScript, so you could feel at home if you are used to them. &lt;/p&gt;

&lt;p&gt;Open a &lt;a href="https://play.onflow.org/local-project" rel="noopener noreferrer"&gt;Flow Playground&lt;/a&gt;; you will see something 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1xa57k58jkcuvccvfk2a.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1xa57k58jkcuvccvfk2a.png" alt="Flow Playground"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll find the test accounts, the transactions, and the script folders in the left sidebar. Transactions are mutations of the blockchain and require gas fees. Scripts are read-only, blazing-fast operations that allow you to perform queries without paying gas fees. Anyway, we don't need to worry about transaction fees in this tutorial. &lt;/p&gt;

&lt;p&gt;The user's account filesystem domain structure can be seen as 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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsbkzglnk62oevuajg8p8.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsbkzglnk62oevuajg8p8.png" alt="Account Filesystem Domain Structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;According to Flow docs:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;storage&lt;/code&gt; domain is where all objects (such as structs and resource objects representing tokens or NFTs) are stored. It is only directly accessible by the owner of the account.&lt;/li&gt;
&lt;li&gt;The `private domain is like a private API. You can optionally create &lt;a href="https://docs.onflow.org/cadence/language/capability-based-access-control/" rel="noopener noreferrer"&gt;links&lt;/a&gt; to any of your stored assets here. Only the owner and anyone they give access to can use these interfaces to call functions defined in their stored assets.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;public&lt;/code&gt; domain is your account's public API. It is like the &lt;code&gt;private&lt;/code&gt; domain in that the owner can link capabilities here that point to stored assets. The difference is that anyone in the network can access the &lt;code&gt;public&lt;/code&gt; domain's functionality.
A &lt;a href="https://docs.onflow.org/cadence/language/transactions" rel="noopener noreferrer"&gt;Transaction&lt;/a&gt; in Flow is defined as an arbitrary-sized block of Cadence code that is signed by one or more accounts. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Transactions have access to the &lt;code&gt;/storage/&lt;/code&gt; and &lt;code&gt;/private/&lt;/code&gt; domains of the accounts that signed the transaction. Transactions can also read and call functions in public contracts and access public domains in other users' accounts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I wanted to deploy a public contract in one user address and let the other users use it without needing to deploy the contract to every account that wants to use it. So let's start by selecting the &lt;code&gt;0x01&lt;/code&gt; user account in the sidebar, removing the example code, and pasting our contract code. The code includes comments so you can understand the reasoning behind every part as part of this tutorial:&lt;br&gt;
`&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// There are different access levels, as defined in &lt;/span&gt;
&lt;span class="c1"&gt;// https://docs.onflow.org/cadence/language/access-control/#gatsby-focus-wrapper, &lt;/span&gt;
&lt;span class="c1"&gt;// but we want our contract to be accessible from outside this &lt;/span&gt;
&lt;span class="c1"&gt;// account, so we defined it as public (pub). &lt;/span&gt;
&lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;contract&lt;/span&gt; &lt;span class="kt"&gt;NotepadManagerV1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// This var is just for fun, to know how many Notepads &lt;/span&gt;
    &lt;span class="c1"&gt;// this contract created.&lt;/span&gt;
    &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;numberOfNotepadsCreated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UInt64&lt;/span&gt;

    &lt;span class="c1"&gt;// The Notepad resource. It contains the notes as nested &lt;/span&gt;
    &lt;span class="c1"&gt;// resources in the 'notes' dictionary. &lt;/span&gt;
    &lt;span class="c1"&gt;// It also defines the Notepad API.&lt;/span&gt;
    &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="kt"&gt;Notepad&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="c1"&gt;// Dictionary of notes. We will use the note.uuid &lt;/span&gt;
        &lt;span class="c1"&gt;// (UInt64) as the indexing key:&lt;/span&gt;
        &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;UInt64&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Note&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// When a Notepad is created, we initialize the &lt;/span&gt;
            &lt;span class="c1"&gt;// 'notes' property with an empty dictionary:&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notes&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Every Resource needs a 'destroy' method.&lt;/span&gt;
        &lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// As we have nested resources, we need to destroy &lt;/span&gt;
            &lt;span class="c1"&gt;// them here too:&lt;/span&gt;
            &lt;span class="n"&gt;destroy&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notes&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Public method to add a note to the user's Notepad.&lt;/span&gt;
        &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;addNote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Create a new note Resource and move it to the &lt;/span&gt;
            &lt;span class="c1"&gt;// constant:&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;note&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="kt"&gt;Note&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="c1"&gt;// As we are using a dictionary of resources and &lt;/span&gt;
            &lt;span class="c1"&gt;// we are adding a new note with the note.uuid as &lt;/span&gt;
            &lt;span class="c1"&gt;// the indexing key, Cadence requires you to &lt;/span&gt;
            &lt;span class="c1"&gt;// handle the note that could already be in that &lt;/span&gt;
            &lt;span class="c1"&gt;// dictionary's position to avoid a Resource loss.&lt;/span&gt;
            &lt;span class="c1"&gt;// So we move what could already be in that &lt;/span&gt;
            &lt;span class="c1"&gt;// position to the 'oldNote' constant and destroy &lt;/span&gt;
            &lt;span class="c1"&gt;// it. In this case, that won't do anything&lt;/span&gt;
            &lt;span class="c1"&gt;// because 'oldNote' will be nil (we are adding a &lt;/span&gt;
            &lt;span class="c1"&gt;// new note to that position with a new UUID). &lt;/span&gt;
            &lt;span class="c1"&gt;// And we move the new note to the new position. &lt;/span&gt;
            &lt;span class="c1"&gt;// This chained move (&amp;lt;-) operators instruction &lt;/span&gt;
            &lt;span class="c1"&gt;// could be read as: "We move the new note to that &lt;/span&gt;
            &lt;span class="c1"&gt;// position, and what was previously in that &lt;/span&gt;
            &lt;span class="c1"&gt;// position to a constant, so we don't lose it":&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;oldNote&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;note&lt;/span&gt;
            &lt;span class="n"&gt;destroy&lt;/span&gt; &lt;span class="n"&gt;oldNote&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Public method to edit a note in the Notepad.&lt;/span&gt;
        &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;editNote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;noteID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UInt64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;newTitle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;newBody&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// We create and move a new note to the previous &lt;/span&gt;
            &lt;span class="c1"&gt;// note position, and the old note to the &lt;/span&gt;
            &lt;span class="c1"&gt;// 'oldNote' constant (and then destroy it):&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;oldNote&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;noteID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="kt"&gt;Note&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;newTitle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;newBody&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="n"&gt;destroy&lt;/span&gt; &lt;span class="n"&gt;oldNote&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Public method to delete a note from the Notepad.&lt;/span&gt;
        &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;deleteNote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;noteID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UInt64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Move the desired note out from the dictionary &lt;/span&gt;
            &lt;span class="c1"&gt;// (to a constant) and destroy it: &lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;note&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;noteID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;destroy&lt;/span&gt; &lt;span class="n"&gt;note&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Public function that, given a note resource id in &lt;/span&gt;
        &lt;span class="c1"&gt;// the Notepad, returns a NoteDTO from it (see this &lt;/span&gt;
        &lt;span class="c1"&gt;// DTO definition below). &lt;/span&gt;
        &lt;span class="c1"&gt;// This will be useful for client queries (Scripts), &lt;/span&gt;
        &lt;span class="c1"&gt;// which are read-only, and we cannot just return a &lt;/span&gt;
        &lt;span class="c1"&gt;// Resource there. &lt;/span&gt;
        &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;note&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;noteID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UInt64&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;NoteDTO&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// We take the note out of the notes dictionary, &lt;/span&gt;
            &lt;span class="c1"&gt;// create a NoteDTO from it, put the note Resource &lt;/span&gt;
            &lt;span class="c1"&gt;// back into the dictionary, and return the NoteDTO:&lt;/span&gt;
            &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;note&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;noteID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;noteDTO&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;NoteDTO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;noteID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;oldNote&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;noteID&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;note&lt;/span&gt;
            &lt;span class="n"&gt;destroy&lt;/span&gt; &lt;span class="n"&gt;oldNote&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;noteDTO&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Public function that returns an array of NoteDTO &lt;/span&gt;
        &lt;span class="c1"&gt;// (see this DTO definition below). This will be &lt;/span&gt;
        &lt;span class="c1"&gt;// useful for client queries (Scripts), which are &lt;/span&gt;
        &lt;span class="c1"&gt;// read-only, and we cannot just return a Resource. &lt;/span&gt;
        &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;allNotes&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;NoteDTO&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// We get a NoteDTO array from the note Resources &lt;/span&gt;
            &lt;span class="c1"&gt;// in the Notepad. &lt;/span&gt;
            &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;allNotes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;NoteDTO&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;notes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;allNotes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;note&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;noteID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;allNotes&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Note Resource definition. This is a nested Resource inside the Notepad Resource.&lt;/span&gt;
    &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="kt"&gt;Note&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;pub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
        &lt;span class="nf"&gt;pub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;

        &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; 
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Helper DTO (Data Transfer Object) that will be used &lt;/span&gt;
    &lt;span class="c1"&gt;// when returning notes data to the clients from queries &lt;/span&gt;
    &lt;span class="c1"&gt;// (Scripts). We cannot just return Resources there.&lt;/span&gt;
    &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;NoteDTO&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UInt64&lt;/span&gt;
        &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;
        &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;

        &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UInt64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt; 
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Right after the contract is deployed, we initialize &lt;/span&gt;
        &lt;span class="c1"&gt;// this var to keep the count of the Notepads that &lt;/span&gt;
        &lt;span class="c1"&gt;// were created using this contract: &lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;numberOfNotepadsCreated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Public method to create and return a Notepad Resource.&lt;/span&gt;
    &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createNotepad&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kd"&gt;@Notepad&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;numberOfNotepadsCreated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;numberOfNotepadsCreated&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="kt"&gt;Notepad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Public method to destroy a Notepad resource from the &lt;/span&gt;
    &lt;span class="c1"&gt;// user's Account.&lt;/span&gt;
    &lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;deleteNotepad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;notepad&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@Notepad&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;numberOfNotepadsCreated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;numberOfNotepadsCreated&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;numberOfNotepadsCreated&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="n"&gt;destroy&lt;/span&gt; &lt;span class="n"&gt;notepad&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, let's deploy the contract by tapping on the &lt;code&gt;Deploy&lt;/code&gt; or &lt;code&gt;Redeploy&lt;/code&gt; button at the top-right corner of the Playground:&lt;br&gt;
&lt;a href="https://media.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%2Flhdn3l200xya01qv231f.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flhdn3l200xya01qv231f.png" alt="Deploy the Smart Contract"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the contract is deployed to the &lt;code&gt;0x01&lt;/code&gt; account, you will see it in the sidebar:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6j0nrqn9pkih14ccvtaq.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6j0nrqn9pkih14ccvtaq.png" alt="Deployed Contract"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now it's time to test our contract using Transactions and Scripts. Let's start by adding a new transaction to the sidebar. This transaction will create the needed notepad and test the API by adding, editing, and deleting notes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Import the Smart Contract from the user account it was deployed to:&lt;/span&gt;
&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;NotepadManagerV1&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="mh"&gt;0x01&lt;/span&gt;

&lt;span class="n"&gt;transaction&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

 &lt;span class="c1"&gt;// In the prepare function, we have access to the private &lt;/span&gt;
 &lt;span class="c1"&gt;// space of the user's account who's signing the transaction:&lt;/span&gt;
    &lt;span class="nf"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;acct&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;AuthAccount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// We try to borrow the notepad from the storage place &lt;/span&gt;
        &lt;span class="c1"&gt;// where it is stored. Borrowing here means that we &lt;/span&gt;
        &lt;span class="c1"&gt;// are creating a reference to the notepad without &lt;/span&gt;
        &lt;span class="c1"&gt;// actually moving it to a var from its location:&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;notepad&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;acct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;borrow&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="kt"&gt;NotepadManagerV1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Notepad&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/storage/&lt;/span&gt;&lt;span class="kt"&gt;Notepad&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// If the result of that borrow is nil, that means we &lt;/span&gt;
        &lt;span class="c1"&gt;// didn't store a notepad yet there, so we do it:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;notepad&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Create a notepad using our contract and move &lt;/span&gt;
            &lt;span class="c1"&gt;// the returned resource to the /storage/Notepad &lt;/span&gt;
            &lt;span class="c1"&gt;// path:&lt;/span&gt;
            &lt;span class="n"&gt;acct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="kt"&gt;NotepadManagerV1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createNotepad&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/storage/&lt;/span&gt;&lt;span class="kt"&gt;Notepad&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="c1"&gt;// Make the notepad public by creating a public &lt;/span&gt;
            &lt;span class="c1"&gt;// link stored in /public/PublicNotepad. We are &lt;/span&gt;
            &lt;span class="c1"&gt;// making it public because we need to expose it &lt;/span&gt;
            &lt;span class="c1"&gt;// if we want to query and return that info from a &lt;/span&gt;
            &lt;span class="c1"&gt;// Script later. These 'link' and 'borrow' &lt;/span&gt;
            &lt;span class="c1"&gt;// functions are related to Capability-based &lt;/span&gt;
            &lt;span class="c1"&gt;// Access Control, which is a pretty powerful &lt;/span&gt;
            &lt;span class="c1"&gt;// feature that lets you expose a public API over &lt;/span&gt;
            &lt;span class="c1"&gt;// the fields and functions of your stored assets &lt;/span&gt;
            &lt;span class="c1"&gt;// to other users. If you want to dig down deeper &lt;/span&gt;
            &lt;span class="c1"&gt;// on the topic, please refer to&lt;/span&gt;
            &lt;span class="c1"&gt;// https://docs.onflow.org/cadence/language/capability-based-access-control/:&lt;/span&gt;
            &lt;span class="n"&gt;acct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="kt"&gt;NotepadManagerV1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Notepad&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/public/PublicNotepad, target: /storage/&lt;/span&gt;&lt;span class="kt"&gt;Notepad&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Notepad created!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// We borrow the notepad (in this case we are sure we &lt;/span&gt;
        &lt;span class="c1"&gt;// have created it because of the previous code):&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;theNotepad&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;acct&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;borrow&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="kt"&gt;NotepadManagerV1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Notepad&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/storage/&lt;/span&gt;&lt;span class="kt"&gt;Notepad&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// Test note creation:&lt;/span&gt;
        &lt;span class="n"&gt;theNotepad&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addNote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"First note title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"This is the body of the first note."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The first note was created and added to the notepad!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// Test another note creation:&lt;/span&gt;
        &lt;span class="n"&gt;theNotepad&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addNote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Second note title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"This is the body of the second note."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The second note was created and added to the notepad!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// Test note edition by editing the second note:&lt;/span&gt;
        &lt;span class="n"&gt;theNotepad&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;editNote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;noteID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;newTitle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Edited second note title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;newBody&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"EDITED: This is the body of the second note."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The second note was edited!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// Test note deletion by deleting the first note:&lt;/span&gt;
        &lt;span class="n"&gt;theNotepad&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deleteNote&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;noteID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The first note was deleted!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;execute&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// We don't need to execute anything else for our &lt;/span&gt;
        &lt;span class="c1"&gt;// testing. You can even delete this method. &lt;/span&gt;
        &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Transaction executed!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To execute this transaction, tap on the &lt;code&gt;Send&lt;/code&gt; button in the top-right corner of the Playground, but make sure you add the &lt;code&gt;0x02&lt;/code&gt; account as the signer, so you test the transaction from a different account from where the contract is located (&lt;code&gt;0x01&lt;/code&gt;): &lt;br&gt;
&lt;a href="https://media.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%2Fsx917t4drvgj5oy2yz7w.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsx917t4drvgj5oy2yz7w.png" alt="Send Transaction"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After sending it, it will be executed, and you will see the logs in the Transaction Results console: &lt;br&gt;
&lt;a href="https://media.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%2F35l2w3t6pmvu04511usf.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F35l2w3t6pmvu04511usf.png" alt="Transaction Results"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you enable the Resources Explorer by tapping on the database icon next to the &lt;code&gt;0x02&lt;/code&gt; account in the sidebar, you will see an empty storage panel above the Transaction Result console: &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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbb0bmbbera179x6t47tu.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbb0bmbbera179x6t47tu.png" alt="Resources Explorer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The notepad containing the notes should appear there. This is a recent bug in the Playground they haven't fixed yet. It was working in previous versions. But don't worry, we can check the content with a script. &lt;/p&gt;

&lt;p&gt;So let's create a new script in the sidebar and paste this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;NotepadManagerV1&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="mh"&gt;0x01&lt;/span&gt;

&lt;span class="c1"&gt;// A script is a special type of Cadence transaction&lt;/span&gt;
&lt;span class="c1"&gt;// that does not have access to any account's storage&lt;/span&gt;
&lt;span class="c1"&gt;// and cannot modify state. Any state changes that it would&lt;/span&gt;
&lt;span class="c1"&gt;// do are reverted after execution.&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;// Scripts must have the following signature: pub fun main()&lt;/span&gt;
&lt;span class="c1"&gt;// We can specify a return type, in this case we are returning &lt;/span&gt;
&lt;span class="c1"&gt;// an array of NoteDTO:&lt;/span&gt;
&lt;span class="n"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;NotepadManagerV1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;NoteDTO&lt;/span&gt;&lt;span class="p"&gt;]?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Cadence code can get an account's public account object&lt;/span&gt;
    &lt;span class="c1"&gt;// by using the getAccount() built-in function.&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;notepadAccount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x02&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// Get the public capability from the public path of the &lt;/span&gt;
    &lt;span class="c1"&gt;// owner's account.&lt;/span&gt;
    &lt;span class="c1"&gt;// Remember that we made this public in the test &lt;/span&gt;
    &lt;span class="c1"&gt;// transaction. &lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;notepadCapability&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;notepadAccount&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getCapability&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="kt"&gt;NotepadManagerV1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;Notepad&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/public/&lt;/span&gt;&lt;span class="kt"&gt;PublicNotepad&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// Borrow a reference for the capability&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;notepadReference&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;notepadCapability&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;borrow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;// If the notepad doesn't exist yet publicly, we return nil. &lt;/span&gt;
    &lt;span class="c1"&gt;// Otherwise, we return all the notes in the form of an array of NoteDTO&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;notepadReference&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nv"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;notepadReference&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;allNotes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Execute the script by tapping on the &lt;code&gt;Execute&lt;/code&gt; button on the top-right side of the Playground, and you will see the result printed in the console. The notepad containing the edited note:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;57&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;37&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;span class="err"&gt;Query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;notes&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;span class="err"&gt;Result&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Optional"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Array"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:[{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Struct"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"A.0000000000000001.NotepadManager.NoteDTO"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"fields"&lt;/span&gt;&lt;span class="p"&gt;:[{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"UInt64"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"2"&lt;/span&gt;&lt;span class="p"&gt;}},{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"String"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Edited second note title"&lt;/span&gt;&lt;span class="p"&gt;}},{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"String"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"EDITED: This is the body of the second note."&lt;/span&gt;&lt;span class="p"&gt;}}]}}]}}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, if you want to easily reset all data stored in the Playground accounts, you can do it by redeploying the contract.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://play.onflow.org/ee8594f9-e491-45cb-a9d6-d6ef759dda93?type=account&amp;amp;id=5722cef9-e962-4458-9123-2b7bbb5f2434&amp;amp;storage=0x02" rel="noopener noreferrer"&gt;Link to the full Playground&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That is enough for now! I hope you have enjoyed playing with Flow. In the next article, we'll learn to deploy the contract to the actual &lt;code&gt;testnet&lt;/code&gt;, create a native iOS dApp that leverages all of this, and communicates directly with the Flow's network. Link to the second part:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/theagilemonkeys/how-to-buid-a-native-ios-dapp-that-uses-the-flow-blockchain-as-the-backend-n9k"&gt;How to build a native iOS dApp that uses the Flow Blockchain as the backend&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading! &lt;/p&gt;

</description>
      <category>web3</category>
      <category>blockchain</category>
      <category>flow</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building your next application using blockchain: Why and how</title>
      <dc:creator>Adrián Lorenzo</dc:creator>
      <pubDate>Tue, 14 Jun 2022 09:23:33 +0000</pubDate>
      <link>https://dev.to/theagilemonkeys/building-your-application-using-blockchain-why-and-how-3l2i</link>
      <guid>https://dev.to/theagilemonkeys/building-your-application-using-blockchain-why-and-how-3l2i</guid>
      <description>&lt;h2&gt;
  
  
  Why build an application using blockchain?
&lt;/h2&gt;

&lt;p&gt;The first question someone could have when considering building applications using blockchain is &lt;strong&gt;why doing it&lt;/strong&gt;. It is a very important question that we believe should be asked no matter the technology or the solution that you are trying to create, since usually our objective is to solve a problem, not to use a specific technology.&lt;/p&gt;

&lt;p&gt;Nowadays, the Web3 ecosystem is very focused on very specific use cases, but that doesn’t mean that those specific use cases are the only ones that blockchain can provide value to. I believe that the value that blockchain can provide is beyond digital assets and decentralized finance. &lt;strong&gt;I believe that trust is the most important value that blockchain can provide.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Trust as the value
&lt;/h3&gt;

&lt;p&gt;Any individual or entity that wants to make use of a solution needs a &lt;strong&gt;certain amount of trust&lt;/strong&gt; to make sure that it is going to work as expected. Sometimes this is easy to provide, but sometimes there are &lt;strong&gt;many environmental factors that can reduce the amount of trust&lt;/strong&gt; that someone can have in your application. If your user has too much to lose by using your application, then they may not want to use it.&lt;/p&gt;

&lt;p&gt;If you think that your solution is missing mechanisms to provide users with trust, it is possible that blockchain can provide those mechanisms, since &lt;strong&gt;it enhances trust by offering security, continuity, and transparency&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Be safe, then I can trust
&lt;/h3&gt;

&lt;p&gt;Security is one of the main concerns that people currently have when it comes to building software. &lt;strong&gt;Without security, you can’t obtain trust&lt;/strong&gt;, and therefore, many of the solutions that you could think of don’t make sense for the user, since they don’t really solve the problem. When we create an application that provides value to the user, you don’t want the rules of the games to be violated by an external party (hacker) or an internal party (team insiders, other users, etc.), because it means that the value that you offer to the user could be lost forever.&lt;/p&gt;

&lt;p&gt;And when we talk about value, we need to talk about data. &lt;strong&gt;The internet and all the applications that we use nowadays are driven by data&lt;/strong&gt;, and it even serves as the main way of generating revenue for some companies. That is why protecting the data that drives your application is essential. &lt;/p&gt;

&lt;p&gt;Current &lt;strong&gt;blockchains have been designed with security as their main objective&lt;/strong&gt;. If you don't trust any of the individual actors within a platform, it doesn't mean that you can't trust the system as a whole. The system has been designed to give more power to those actors who have a lot more to lose by being dishonest.&lt;/p&gt;

&lt;h3&gt;
  
  
  Expect continuity, then I can trust
&lt;/h3&gt;

&lt;p&gt;If the data that is hosted in your application &lt;strong&gt;is not guaranteed to be preserved&lt;/strong&gt; through time, many parties involved in the application have to accept the risk of potentially losing valuable data, which could decrease user trust.&lt;/p&gt;

&lt;p&gt;Blockchain transaction records immutability allows users to keep track of every data entry, forever. You can expect your data to always be stored in the system, or for it to be stored as long as predicted.&lt;/p&gt;

&lt;h3&gt;
  
  
  Be transparent, then I can trust
&lt;/h3&gt;

&lt;p&gt;In terms of the business logic rules of the game, when many parties are involved, it is essential for cooperative solutions to &lt;strong&gt;keep data transparent&lt;/strong&gt;, so people can trust each other and therefore, be confident when making use of the cooperation tools provided.&lt;/p&gt;

&lt;p&gt;If the application you are using is also being used by many different parties that you don’t trust, you can &lt;strong&gt;verify if dishonest participants are using the application maliciously&lt;/strong&gt;. This would therefore affect the value that the application is providing to you.&lt;/p&gt;

&lt;p&gt;Blockchains allow users to have a full history of the actions that are committed to the system, without the possibility of modifying previous records.&lt;/p&gt;

&lt;h2&gt;
  
  
  Smart contracts
&lt;/h2&gt;

&lt;p&gt;Smart contracts are a solution provided by &lt;strong&gt;general-purpose blockchains&lt;/strong&gt; (also known as layer-1 solutions) to &lt;strong&gt;program limited applications that run and store their data inside the network nodes&lt;/strong&gt;. They are usually executed in a virtual machine. Currently, the &lt;a href="https://ethereum.org/en/developers/docs/evm/"&gt;Ethereum Virtual Machine&lt;/a&gt; is the most popular one.&lt;/p&gt;

&lt;p&gt;You can use programming languages like &lt;a href="https://docs.soliditylang.org/en/v0.8.14/"&gt;Solidity&lt;/a&gt; or &lt;a href="https://vyper.readthedocs.io/en/stable/"&gt;Vyper&lt;/a&gt; to program smart contracts that run in the Ethereum Virtual Machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight solidity"&gt;&lt;code&gt;&lt;span class="c1"&gt;// SPDX-License-Identifier: MIT
&lt;/span&gt;&lt;span class="k"&gt;pragma&lt;/span&gt; &lt;span class="n"&gt;solidity&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Example contract in Solidity
&lt;/span&gt;&lt;span class="k"&gt;contract&lt;/span&gt; &lt;span class="n"&gt;Storage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint256&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;view&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This solution is the response of these general-purpose blockchains to those use cases that would benefit from the network effect of the blockchain. The advantages of this mechanism are pretty clear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The application takes &lt;strong&gt;full advantage of the network effect.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;You can &lt;strong&gt;interact with other smart contracts&lt;/strong&gt; in the ecosystem.&lt;/li&gt;
&lt;li&gt;The application is hosted in the &lt;strong&gt;same ecosystem&lt;/strong&gt; as any other app, &lt;strong&gt;reducing the entry barriers&lt;/strong&gt; for users to use it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Smart contracts are great, but not always enough
&lt;/h3&gt;

&lt;p&gt;However, smart contracts have some critical disadvantages that can cause huge drawbacks for many solutions:&lt;/p&gt;

&lt;h4&gt;
  
  
  It is not scalable
&lt;/h4&gt;

&lt;p&gt;Being in the same environment as everyone is a &lt;strong&gt;great advantage in a small number of use cases&lt;/strong&gt;. For example, solutions that are interconnected with many other “public-good” applications and have complex interactions (more than just querying) between them. Also, the security advantages are important for certain use cases.&lt;/p&gt;

&lt;p&gt;However, most applications do not take advantage of this, since the dynamics of an application are usually limited to a small set of interactions, or don’t need such an amount of security granularity.&lt;/p&gt;

&lt;p&gt;The thing is that usually, the most used general-purpose blockchains, those that have the &lt;strong&gt;best network effect, are VERY secure.&lt;/strong&gt; So secure, and so decentralized that they are often &lt;strong&gt;very slow and not scalable&lt;/strong&gt;. This problem is generally called &lt;strong&gt;&lt;a href="https://www.ledger.com/academy/what-is-the-blockchain-trilemma"&gt;The Blockchain Trilemma&lt;/a&gt;&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Many different smart contracts are being executed, and therefore, &lt;strong&gt;requesting the same amount of security and decentralization as any other&lt;/strong&gt;, even if their use case is not taking advantage of that level of security. The consequence of everyone taking advantage of the maximum network effect is a &lt;strong&gt;saturated network&lt;/strong&gt; that is not able to scale when the amount of users running transactions is unsustainable. &lt;/p&gt;

&lt;p&gt;Your application could be undestroyable and super-interconnected, but if &lt;strong&gt;one million requests per minute make your application unusable for those users,&lt;/strong&gt; maybe you are not as interested in that amount of security and interconnection as you thought.&lt;/p&gt;

&lt;h4&gt;
  
  
  It is not private
&lt;/h4&gt;

&lt;p&gt;Taking full advantage of a public network has the disadvantage of also &lt;strong&gt;submitting your data to the public domain&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To have a decentralized application doesn’t necessarily mean that you want to let everyone know about your data and let them participate in your network. In many organizations or cooperatives, individuals could have &lt;strong&gt;common objectives but also common secrets&lt;/strong&gt; that they don’t wish to share with anyone other than the participants of the organization. Ideally, everyone should be able to be a participant in the system they trust.&lt;/p&gt;

&lt;h4&gt;
  
  
  It is limited
&lt;/h4&gt;

&lt;p&gt;Smart contracts offer a &lt;strong&gt;very limited set of instructions that can be run.&lt;/strong&gt; It is much more limited than programming your own traditional application, for example, in the Java Virtual Machine (JVM).&lt;/p&gt;

&lt;p&gt;This limitation means fewer attack vectors, but also means less configuration and more work in many cases. &lt;/p&gt;

&lt;h2&gt;
  
  
  Application-specific blockchains
&lt;/h2&gt;

&lt;p&gt;Instead of making use of a general-purpose blockchain to build your application on top of it using smart contracts, a great alternative could be to &lt;strong&gt;build your own blockchain&lt;/strong&gt;, as your application.&lt;/p&gt;

&lt;p&gt;An application-specific blockchain is just a blockchain that &lt;strong&gt;understands and provides operations and queries for your business logic&lt;/strong&gt;. It uses the &lt;strong&gt;necessary resources&lt;/strong&gt; that your application needs to run, and is configured to &lt;strong&gt;match the requirements&lt;/strong&gt; that your application has.&lt;/p&gt;

&lt;p&gt;Since your blockchain is being used for just one purpose, it means that &lt;strong&gt;your resources are being used for just that purpose&lt;/strong&gt;, and therefore it is &lt;strong&gt;maximizing performance&lt;/strong&gt;. Also, the system can be &lt;strong&gt;customized&lt;/strong&gt; as you want to enable the best security, decentralization, and scalability configuration for your use case.&lt;/p&gt;

&lt;p&gt;In addition, since you are building everything “from scratch” and your business logic is not running in a limited set of instructions, you are free to make use of any of your programming language tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Independent networks: to be isolated or not to be?
&lt;/h2&gt;

&lt;p&gt;Having a custom network that runs independently from other networks has many advantages, but it also has disadvantages that we can’t ignore.&lt;/p&gt;

&lt;p&gt;If your application is hosted as an independent network blockchain, it means that &lt;strong&gt;it is not going to take advantage of the network effects that a major network is going to provide&lt;/strong&gt;, like security and decentralization.&lt;/p&gt;

&lt;p&gt;Also, if your system wants to &lt;strong&gt;communicate with other networks, those networks should understand the same language as your own&lt;/strong&gt;, and therefore, have a standard communication interface to make use of.&lt;/p&gt;

&lt;h3&gt;
  
  
  Permissioned blockchains
&lt;/h3&gt;

&lt;p&gt;In some cases, this isolation is something that your requirements may take advantage of. If you &lt;strong&gt;don’t want everyone to be a participant of the network&lt;/strong&gt;, a permissioned blockchain can match the requirements of your network.&lt;/p&gt;

&lt;h2&gt;
  
  
  Taking advantage of network effects with interoperability solutions
&lt;/h2&gt;

&lt;p&gt;Now, imagine that you could have an &lt;strong&gt;independent network that could make use of some of the advantages of a major network without losing its independence&lt;/strong&gt;. To allow that, there should be a mechanism that enables &lt;strong&gt;interconnection&lt;/strong&gt; between those independent networks so they can fulfill their wishes.&lt;/p&gt;

&lt;p&gt;Blockchain interoperability solutions allow independent networks to &lt;strong&gt;take advantage of at least part of the network effect of the major network&lt;/strong&gt; without compromising scalability or configuration.&lt;/p&gt;

&lt;p&gt;There isn’t one single way of enabling blockchain interoperability, and the way the mechanism is architected offers different capabilities to the solution you want to create.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sidechains
&lt;/h3&gt;

&lt;p&gt;A sidechain is a blockchain network that is &lt;strong&gt;interconnected to a bigger network&lt;/strong&gt;, usually called the “mainchain”, following a chief/worker pattern.&lt;/p&gt;

&lt;p&gt;The sidechains and the mainchain communicate with each other with a &lt;strong&gt;specific protocol&lt;/strong&gt;. The sidechains have to &lt;strong&gt;validate their state with the mainchain periodically&lt;/strong&gt; to remain part of the network, by submitting proofs. This allows the sidechain to have an extra layer of security by obtaining &lt;strong&gt;direct validation from a bigger network&lt;/strong&gt; and therefore, taking advantage of its network effect.&lt;/p&gt;

&lt;p&gt;Some key characteristics of sidechains are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The main network is &lt;strong&gt;never affected by the problems that sidechains could face&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The sidechain &lt;strong&gt;doesn’t need to be public or have the same implementation&lt;/strong&gt; as the mainchain.&lt;/li&gt;
&lt;li&gt;Since you &lt;strong&gt;don’t have to validate each sidechain’s transaction with the mainchain&lt;/strong&gt;, the mainchain is able to scale more effectively.&lt;/li&gt;
&lt;li&gt;The mainchain can &lt;strong&gt;act as a bridge between sidechains to communicate&lt;/strong&gt; if necessary.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Inter-communication protocols
&lt;/h3&gt;

&lt;p&gt;Another solution for better scalability through interoperability is the implementation of &lt;strong&gt;inter-communication protocols.&lt;/strong&gt; One of the most popular inter-communication protocols is the &lt;strong&gt;&lt;a href="https://ibcprotocol.org"&gt;Inter-Blockchain Communication Protocol&lt;/a&gt; (IBC)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This protocol allows chains with similar core configurations to interact with each other.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sharding
&lt;/h3&gt;

&lt;p&gt;Sharding is the database architecture concept of &lt;strong&gt;dividing a database horizontally into independent databases, called shards&lt;/strong&gt;. Each shard has different data and it is usually located in a different server, to allow better scalability.&lt;/p&gt;

&lt;p&gt;The sharding concept is being introduced in blockchain networks too: the idea is to &lt;strong&gt;create different shards&lt;/strong&gt; (subnetworks of nodes) that store a part of the blockchain. Each shard is going to be able to &lt;strong&gt;communicate with other shards&lt;/strong&gt; and participate in the network as one.&lt;/p&gt;

&lt;p&gt;Since &lt;strong&gt;no one should store the whole state&lt;/strong&gt; and receive transactions to obtain transaction finality, the network is going to be able to scale more effectively.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bridges
&lt;/h3&gt;

&lt;p&gt;A bridge is a mechanism to &lt;strong&gt;interconnect blockchains through an “information exchange” using an intermediary&lt;/strong&gt;. There are two types of bridges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Trusted bridges&lt;/strong&gt;: based on trust assumption, and handled by a centralized entity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trustless bridges&lt;/strong&gt;: based on an algorithm, usually written in a smart contract.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A bridge is made specifically for interconnection &lt;strong&gt;between a set of specific blockchains with specific configurations&lt;/strong&gt;. It doesn’t act as a protocol.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does this mean that I should discard smart contracts?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Smart contracts are VERY useful for many use cases&lt;/strong&gt;. There are a lot of applications like &lt;a href="https://uniswap.org"&gt;Uniswap&lt;/a&gt;, &lt;a href="https://filecoin.io"&gt;Filecoin&lt;/a&gt; or &lt;a href="https://www.developerdao.com"&gt;Developer DAO&lt;/a&gt; that make an excellent use of smart contracts to implement their applications.&lt;/p&gt;

&lt;p&gt;In this article I have analyzed some of the current advantages and disadvantages of building smart contracts and application-specific blockchains. Depending on your use case, &lt;strong&gt;you may find one of the solutions more suitable than the other.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wait, should I implement application-specific blockchains from scratch?! 😦
&lt;/h2&gt;

&lt;p&gt;You could actually implement any of these mechanisms and blockchain specifications from scratch, but you probably don’t have the time and the resources to even consider it.&lt;/p&gt;

&lt;p&gt;However, we are in luck. There are &lt;strong&gt;a lot of useful open-source tools that allow developers to build application-specific blockchains without having to worry about low-level implementations and cryptographic details&lt;/strong&gt;. This is done by making use of industry-standard specifications and protocols backed up by the community.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In my next article, I’m going to review some of the most relevant solutions&lt;/strong&gt; that you can find in the market right now. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stay tuned!&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;This article represents a very small piece of what we are building at &lt;a href="https://www.theagilemonkeys.com"&gt;The Agile Monkeys&lt;/a&gt;. If you like what we do, you may want to &lt;a href="https://theagilemonkeys.notion.site/Want-to-join-us-as-a-developer-b46c51d7ad4741159475c9ebdaca475a"&gt;join us in our journey&lt;/a&gt;!&lt;/p&gt;




&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@theshubhamdhage?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Shubham Dhage&lt;/a&gt; on &lt;a href="https://unsplash.com/@theshubhamdhage?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>blockchain</category>
      <category>security</category>
      <category>web3</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Playing the "no game" in meetings.</title>
      <dc:creator>David Godoy</dc:creator>
      <pubDate>Tue, 07 Jun 2022 11:35:10 +0000</pubDate>
      <link>https://dev.to/theagilemonkeys/playing-the-no-game-in-meetings-3i53</link>
      <guid>https://dev.to/theagilemonkeys/playing-the-no-game-in-meetings-3i53</guid>
      <description>&lt;p&gt;Ok, I need to confess something. I have lost uncountable hours in meetings during my career. Not only because they could have been an email or not needed at all, but for things that seemed reasonable. Those hours spend on legit meetings are always justifiable, and we see them as necessary but sometimes they take more than needed.&lt;/p&gt;

&lt;p&gt;Don't get me wrong. I'm not saying those meetings were a complete waste of time. My point is that sometimes those meetings are missing something essential to be effective, The Objective™. &lt;strong&gt;Being in a meeting without a clear objective is like playing a game without knowing the rules or the goal you need to reach; you are playing the “no game” game.&lt;/strong&gt; Without it, something that could take 10-15 minutes is "done" in 40, people in the meeting lose focus, and your energy level after the session is sea bottom level. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eeIi915E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/15zvps5rzzwgrfwzk7f5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eeIi915E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/15zvps5rzzwgrfwzk7f5.png" alt="Two dots from different colors in a white background, so nobody knows the game they are playing" title="The “No game” game" width="411" height="171"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;center&gt;&lt;em&gt;The “No game” game&lt;/em&gt;&lt;/center&gt;
&lt;br&gt;

&lt;p&gt;This is especially relevant with teams with very different skills and backgrounds. When you don't know which game you are playing, you just play the game you are more comfortable with. Developers play code, Managers play hours, DevOps play security... you know "their games". Even when the objective is mentioned in the event's email or at the start of the meeting, someone can start playing the "no game", and our natural tendency is to play with them. This is not related to the team experience or excellence, I have been in meetings with brilliant and capable people, and we have started to play the "no game" pretty heavily. &lt;/p&gt;

&lt;p&gt;Let me share three real-world situations I have been involved in and how noticing we were playing the "no game" game saved us from the bottomless time pit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Unblock the release
&lt;/h3&gt;

&lt;p&gt;We migrated a mobile app backend from Firebase to Booster framework to support multi-cloud, and use some exciting features (event-sourcing, serverless, etc.). Hence, we needed to update the app code to use the new GraphQL interface. We updated the iOS application and applied some design changes along the way. Still, the Android app was a bit behind on the update, so we decided to have a meeting to discuss how to unblock the situation and release the new app as soon as possible since it was impossible to release only one version.&lt;/p&gt;

&lt;p&gt;The objective was evident when we started the meeting, but it didn't take much to start playing the "no game" game. We discussed the need to update the Android app to be on the latest and greatest software stack to make it easy to keep the iOS pace in the future. We mentioned that the app was old, and giving it a good refactor makes total sense. After some time, we started talking about taking two more months to release it, and as expected, the product owner was a bit concerned and started asking. &lt;/p&gt;

&lt;p&gt;Fortunately, someone from the team grabbed us back into the "right" game, remembering that the goal was to unblock the release, not update the Android app to the same point as the iOS. After that, we all agreed on a plan that could be executed in a few weeks. We ended the meeting there, and everyone could keep going with their stuff. This saved us a lot of time and frustration on the team.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bAKN_wyY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wseesoh6852306h99vs4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bAKN_wyY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wseesoh6852306h99vs4.png" alt="Same two dots but now the white background has the football field lines, so they are playing football" title="The Football game" width="411" height="173"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;center&gt;&lt;em&gt;The Football game&lt;/em&gt;&lt;/center&gt;
&lt;br&gt;
&lt;h3&gt;
  
  
  Unit testing a Proof of concept project
&lt;/h3&gt;

&lt;p&gt;At that time, we were doing some product research, and we had a potential client we wanted to show some concepts to and discover if they were appealing to them. The first meetings were tremendous, and they wanted to keep exploring the solution, so we decided that we could present them with a "Proof of Concept" application to engage even more with the product.&lt;/p&gt;

&lt;p&gt;We had a meeting to coordinate and plan that "Proof of Concept". Since our team was excellence-focused and we were all passionate engineers, someone started talking about adding tests so the future refactors and maintenance were easier. We would create it from scratch, and we could enforce them in every PR. That way, we could ensure the highest code coverage possible. If you have been in this situation, you know that early testing debates can last forever. Someone mentioned that our goal was to have something pretty and functional to show to the client quickly. After that, we all agreed to enforce the tests later on when building the real thing. It seems trivial, but by clarifying our objective, the game got so clear that we quickly create a plan and finished the meeting.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AmlSbwpg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/70ii3gkb8ldioo9j0woh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AmlSbwpg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/70ii3gkb8ldioo9j0woh.png" alt="Same two dots but now the white background has the Squid Game field lines, so they are playing Squid Game" title="The Squid game" width="411" height="171"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;center&gt;&lt;em&gt;The Squid game&lt;/em&gt;&lt;/center&gt;
&lt;br&gt;
&lt;h3&gt;
  
  
  Brainstorming too specific
&lt;/h3&gt;

&lt;p&gt;We were throwing crazy ideas to the table in a brainstorming session, and suddenly we started going way too far with the reality checks. We started designing a specific solution for that idea and arguing about different approaches. It is always lovely to debate and get passionate about implementation details, but sometimes it is outstanding that someone just raises their hand and remembers the game we are playing. It saves time and prevents going too deep into the design of something that will change or be dismissed by another idea.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BfaUwe7W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wfu736t3ws2a48f5g2pm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BfaUwe7W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wfu736t3ws2a48f5g2pm.png" alt="Same two dots but now the white background has the Tennis field lines, so they are playing Tennis" title="The Tennis game" width="412" height="172"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;center&gt;&lt;em&gt;The Tennis game&lt;/em&gt;&lt;/center&gt;
&lt;br&gt;

&lt;p&gt;With no effort, you can probably tell similar situations you have been involved in, and they took ages to finish with probably no clear outcome. The worst part is not the time you waste arguing in the meetings but the frustrating feeling of talking with a different game in mind. Whether is a manager, team lead, or teammate, clarifying the objective is always helpful.&lt;/p&gt;

&lt;p&gt;From my experience, the biggest takeaways from those situations are the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Always communicate the objective of the meeting&lt;/li&gt;
&lt;li&gt;Having an objective in mind removes noise and brings you clarity for the decisions to make&lt;/li&gt;
&lt;li&gt;Sometimes you need to remember the objective of the meeting. A.K.A.: The "game" you are playing.&lt;/li&gt;
&lt;li&gt;Have the main objective clear. If other games need to be played, it is vital to do it at the right time (or meeting).&lt;/li&gt;
&lt;li&gt;Even when you agree with the given statements, if they are playing a different game, the best thing to do is remember the objective and leave it aside for a moment.&lt;/li&gt;
&lt;li&gt;Great leaders always try to keep the objective in mind and fresh to help the team be on the same page and focus on the current game.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Knowing the game you are playing is key to being practical. It is a positive spiral that allows you to waste less time, have less anxiety/frustration, solve problems better and faster, and make things 10x better.&lt;/p&gt;

</description>
      <category>management</category>
      <category>meetings</category>
      <category>leadership</category>
    </item>
    <item>
      <title>Bugs will happen. Are you prepared?</title>
      <dc:creator>Jorge Rodríguez</dc:creator>
      <pubDate>Thu, 02 Jun 2022 11:02:02 +0000</pubDate>
      <link>https://dev.to/theagilemonkeys/bugs-will-happen-are-you-prepared-3m5g</link>
      <guid>https://dev.to/theagilemonkeys/bugs-will-happen-are-you-prepared-3m5g</guid>
      <description>&lt;p&gt;It's very common for developers (and managers!) to focus on new features, performance, or bug fixing when coding. But when a project is complex enough, there's a hard truth that we all must take into account: &lt;strong&gt;bugs will happen&lt;/strong&gt;. Period. I have never seen a new project go live without issues. In fact, I don't think I've ever seen a project stay bug-free in production for more than a month straight. Software engineering is imperfect, and &lt;strong&gt;our code must be prepared to deal with it&lt;/strong&gt;. This post is about what you can do to make life easier for you and your team.&lt;/p&gt;

&lt;p&gt;A couple of years ago, a bunch of us at &lt;strong&gt;The Agile Monkeys&lt;/strong&gt; started this huge project for a bank. We rebuilt a critical part of their system, with an &lt;strong&gt;event-driven architecture&lt;/strong&gt; that would be processing &lt;strong&gt;millions of monetary (and non-monetary) transactions daily&lt;/strong&gt;. The team did a fantastic job and it's still in production and working well to this day. However, &lt;strong&gt;it was not a bed of roses&lt;/strong&gt;. We faced some important challenges that I believe made us all much better developers today.&lt;/p&gt;

&lt;p&gt;As usual with any big project, there was a lot of &lt;strong&gt;technical learning&lt;/strong&gt; involved. From do's and don'ts in event-driven architectures, to communication both inside and across the teams. There were loads of lessons learned. But there was one huge takeaway that I took from the project. We dedicated &lt;strong&gt;way too much time&lt;/strong&gt; to code optimization, bug fixing, and new features. And we didn't work enough on &lt;strong&gt;defensive programming&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's defensive programming?
&lt;/h2&gt;

&lt;p&gt;Quoting Wikipedia directly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Defensive programming&lt;/strong&gt; is a form of defensive design intended to ensure the continuing function of a piece of software under unforeseen circumstances. Defensive programming practices are often used where high availability, safety, or security is needed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The emphasis here is on &lt;strong&gt;unforeseen circumstances&lt;/strong&gt;. &lt;em&gt;Bad Things™&lt;/em&gt; will happen, no matter what you do. So &lt;strong&gt;you have to prepare for them&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At our first launch, we thought that we had a &lt;strong&gt;very robust application&lt;/strong&gt;. It was performant and well tested. But, again, &lt;em&gt;Bad Things™&lt;/em&gt; can and will happen. In our case, it was an &lt;strong&gt;unknown rate limitation&lt;/strong&gt; on our &lt;strong&gt;vendor production API&lt;/strong&gt; that temporarily shut our application account down. Then, even when our services had a retry mechanism in place, they all ended up retrying simultaneously. As a result, a large majority of our transactions &lt;strong&gt;failed&lt;/strong&gt;. Recovering from those errors required a lot of work from all of us. We were clearly &lt;strong&gt;not prepared enough for an issue at such a scale&lt;/strong&gt;. We found ourselves doing a lot of manual, tedious work to solve the transactions in pending status. It resulted in many hours of hard work, and it naturally grew into some &lt;strong&gt;automatic tooling for reconciliation&lt;/strong&gt;. Tooling that we should have implemented right away, instead of dedicating that much time to optimize performance, fixing bugs or even adding new features.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reconciliation tooling
&lt;/h2&gt;

&lt;p&gt;In regards to the tooling that you should have in place, it will greatly depend on the needs of your system. But for an event-driven architecture like the one that we were working with, we found it incredibly useful to have an &lt;strong&gt;Admin API&lt;/strong&gt; (be careful with the security on this one!), with some automatic checks and reconciliation logic. The methods in this API would be able to replay events, look for inconsistent values in DB, or for the most extreme scenarios, even update some DB fields directly.&lt;/p&gt;

&lt;p&gt;That, combined with an &lt;strong&gt;event store&lt;/strong&gt; where every event received is kept (especially if not completed successfully), will allow your team to work wonders. It's important that the developers are able to &lt;strong&gt;safely and consistently replay the events&lt;/strong&gt;. One of the issues that we faced in our project was that, even though our log aggregator worked very well to grab event data, it was not &lt;strong&gt;consistent enough for our scale&lt;/strong&gt;. A small percentage (below 1%) of events were lost, but it equated to thousands of events that need to be manually searched for. Having a more complete and reliable event store for our needs was &lt;strong&gt;a huge relief&lt;/strong&gt; for our reconciliation process.&lt;/p&gt;

&lt;p&gt;There's another very good benefit that you'll get from all of this tooling: you can &lt;strong&gt;automatize those checks and processes to run periodically&lt;/strong&gt; once you've verified their robustness. For instance, you could run a reconciliation task daily on all of those events that failed or stalled for more than an hour. Once the tooling is in place, there are many advantages that you can enjoy!&lt;/p&gt;

&lt;p&gt;So, for every reader out there, I'll be proud if you can just carry home the following takeaway: &lt;strong&gt;bugs will happen. Are you prepared to deal with them in production?&lt;/strong&gt; If not, start dedicating some time to it, even before bug fixing or optimizing your code. Invest in a calm mind. Future &lt;em&gt;You&lt;/em&gt; will thank you when enjoying the spare time with your friends instead of dealing with on-call issues!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>design</category>
      <category>devjournal</category>
      <category>eventdriven</category>
    </item>
    <item>
      <title>Logging Ethereum events with NodeJS</title>
      <dc:creator>Roberto Diaz</dc:creator>
      <pubDate>Wed, 25 May 2022 22:50:59 +0000</pubDate>
      <link>https://dev.to/theagilemonkeys/logging-ethereum-events-with-node-5b37</link>
      <guid>https://dev.to/theagilemonkeys/logging-ethereum-events-with-node-5b37</guid>
      <description>&lt;p&gt;Believe it or not, Web3 and distributed applications are here to stay! These technologies are contributing to creating a more decentralised Internet where the data is not owned by single institutions and applications are not necessarily running on servers managed by big companies. We are talking about a utopic future where data and applications are not attached to any particular place, they just will exist in the networks.&lt;/p&gt;

&lt;p&gt;Until that utopic point, traditional cloud applications are going to coexist with distributed applications and in some use cases, they will need to interact between them. Cloud applications could need to read transactions around a specific address, check that a smart contract fires a specific event or simply send a transaction or data to a specific address, among other interactions.&lt;br&gt;
We are going to cover the necessary pieces to achieve that a nodeJS application will be able to interact with the Ethereum network with some simple examples. &lt;/p&gt;
&lt;h2&gt;
  
  
  The Intermediary
&lt;/h2&gt;

&lt;p&gt;The first actor in this integration between the traditional nodeJS application and the Ethereum network is the mechanism that will allow us to listen to the blockchain and send data to the blockchain. &lt;/p&gt;

&lt;p&gt;To have this communication mechanism we have two options, create an Ethereum node or use a third-party provider. The main difference between the two options is confidence. &lt;/p&gt;

&lt;p&gt;If we manage our node, we know that information is not managed by a third party and we can trust the data that we are reading. On the contrary, the drawback of managing your node is that normally it is more complex than using a third party to connect to the blockchain network.  &lt;/p&gt;

&lt;p&gt;To mount an Ethereum node, the recommended option is to use &lt;a href="https://geth.ethereum.org/" rel="noopener noreferrer"&gt;Geth&lt;/a&gt;. Geth is one of the three original implementations of the Ethereum protocol implemented in Go and it is one of the most used implementations to create an Ethereum node. You need a machine with A LOT space in your hard drive, and download, configure and launch Geth. &lt;/p&gt;

&lt;p&gt;Another alternative to mounting your node is to use a cloud provider such as AWS or Azure. In cloud providers, you can mount Geth on a normal cloud instance or use specific services such as &lt;a href="https://aws.amazon.com/es/managed-blockchain/" rel="noopener noreferrer"&gt;Amazon Managed Blockchain&lt;/a&gt; or the Ethereum node from &lt;a href="https://azuremarketplace.microsoft.com/es-es/marketplace/apps/techlatest.ethereum-fullnode" rel="noopener noreferrer"&gt;Azure Marketplace&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you don’t want to deal with the configuration of an Ethereum node you can use a third-party provider that can provide you access to the network through them. Some of the most well-known providers are &lt;a href="https://infura.io/" rel="noopener noreferrer"&gt;Infura&lt;/a&gt;, &lt;a href="https://www.alchemy.com/" rel="noopener noreferrer"&gt;Alchemy&lt;/a&gt; and &lt;a href="https://www.quicknode.com/" rel="noopener noreferrer"&gt;QuickNode&lt;/a&gt;. In our example, we are going to use Infura. &lt;/p&gt;

&lt;p&gt;Finally, not covered here, another option to interact with blockchain could be to use the Etherscan API to read information about accounts, transactions, blocks, etc… using a REST API. &lt;/p&gt;
&lt;h2&gt;
  
  
  The Javascript interface
&lt;/h2&gt;

&lt;p&gt;From the previous step, using a self-owned node or a node provided by a third party, we are going to obtain an URL to a JSON gRPC API. &lt;/p&gt;

&lt;p&gt;To interact with the Ethereum node we are going to use a JSON gRPC API but fortunately, we won’t need to interact directly with it. Several libraries work as a wrapper around the node API making our life easier. Web3js and Ethers are two of the most commonly used. In our examples, we are going to use Web3js.&lt;/p&gt;

&lt;p&gt;At this point, we have all the pieces in place to start to connect nodeJS with Ethereum and start to receive events and monitoring addresses. The following diagram summarises what we have said. &lt;br&gt;
&lt;a href="https://media.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%2Fy8cv6hab2im2eog2mgql.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy8cv6hab2im2eog2mgql.png" alt="Integration between NodeJS and Ethereum network using Web3Js"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Reading information
&lt;/h2&gt;

&lt;p&gt;Once we have everything ready in our NodeJS application, we can start to receive information from the Ethereum network. Web3js provides us with some convenient methods to receive information depending on what we want to monitor.  If we want to monitor what’s going on around a smart contract we are going to use the &lt;code&gt;subscribe&lt;/code&gt; method. This method allows us to receive every event emitted by a smart contract. &lt;br&gt;
An important consideration here is that with emitted events we are talking about &lt;a href="https://ethereum.org/es/developers/tutorials/logging-events-smart-contracts/" rel="noopener noreferrer"&gt;Solidity logging events&lt;/a&gt;. If your contract doesn’t emit any event you won’t see any data using the subscribe method. Here is an extract of code using the subscribe method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0xcontract_address&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;web3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;logs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
 &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;got result&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decodedLogs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;abiDecoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decodeLogs&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
 &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decodedLogs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;changed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
 &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;changed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this fragment of code, we are simply subscribing our application to Ethereum logs of a specific contract address provided in the &lt;code&gt;options&lt;/code&gt; object. Additionally, we are decoding the event using the &lt;a href="https://github.com/ConsenSys/abi-decoder" rel="noopener noreferrer"&gt;library abiDecoder&lt;/a&gt;. To use this library, we are providing in the configuration the Contract.json file including the ABI (Application Binary Interface) of the contract. &lt;/p&gt;

&lt;p&gt;Using Web3js we can subscribe our application to specific events using the configuration of the topic. In this case, we are subscribed to all the events emitted by the contract. Here is an example of an event received from our test contract after emitting a transfer:&lt;br&gt;
&lt;a href="https://media.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%2Fmmrpmprqeoolt2xjcvma.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmmrpmprqeoolt2xjcvma.png" alt="smart contract event"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Inside the event array we get more information about the emitted event:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F35bxbuofnqjjv02k55z8.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F35bxbuofnqjjv02k55z8.png" alt="smart contract event detail"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Get more information from the network
&lt;/h2&gt;

&lt;p&gt;At this point, we can monitor a smart contract but we can try to go further and try to monitor what’s going on around a specific address. Thanks to Web3js we can also subscribe to every block added to the blockchain and we can explore the content of that block.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;blockSubscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;web3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;newBlockHeaders&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;blockSubscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error subscribing to event&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;blockHeader&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;blockHeader&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;blockHeader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;web3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blockHeader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, we are just subscribing our application to the &lt;code&gt;newBlockHeader&lt;/code&gt; and printing the result:&lt;br&gt;
&lt;a href="https://media.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%2Fqd8dt7wene2ze5sdhsv3.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqd8dt7wene2ze5sdhsv3.png" alt="Block Information"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the block header information, we have a lot of information about the latest mined block but there is a very important section for us, the &lt;code&gt;transactions&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;That array includes all the hashes of the transactions included in that block and again thanks to Web3js we have a method to obtain the information of a specific transaction. As you can see, if we want to monitor just a subset of addresses now is where the intensive processing stuff starts XD.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;web3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;blockHeader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;foreach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;transactionHash&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;transaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;web3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;eth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transactionHash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a result of this we can get all the information related to the transaction:&lt;br&gt;
&lt;a href="https://media.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%2Ff0ivynngx1d14nguo9f9.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff0ivynngx1d14nguo9f9.png" alt="Transaction information"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can get the &lt;code&gt;from&lt;/code&gt; and &lt;code&gt;to&lt;/code&gt; addresses, any additional information included inside the transaction in the &lt;code&gt;input&lt;/code&gt; field or the amount of the transaction in wei inside the &lt;code&gt;value&lt;/code&gt; field.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;DISCLAIMER:&lt;/strong&gt; As you might be guessing, we are performing a lot of requests against the network, for each received block, we are requesting the block information and then we are asking for the information about all transactions included in that block. Because of this, we could reach the limit of usage of a third party node such as Infura. For this specific use case, it could be recommended to have a self-managed node.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For more information about configurations and to check how it works, all the code shown can be found in &lt;a href="https://github.com/theam/web3js_events" rel="noopener noreferrer"&gt;this repository&lt;/a&gt;. The repository includes a simple smart contract developed with Hardhat and all the necessary code to monitor the contract and some Ethereum addresses using NodeJS.&lt;/p&gt;

&lt;p&gt;Cover Photo by &lt;a href="https://unsplash.com/@theshubhamdhage?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Shubham Dhage&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/ethereum?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>blockchain</category>
      <category>tutorial</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
