<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[The Agile Monkeys’ Journey - Medium]]></title>
        <description><![CDATA[We write about what we learn and what we think. - Medium]]></description>
        <link>https://medium.com/the-theam-journey?source=rss----f90e0a497750---4</link>
        <image>
            <url>https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png</url>
            <title>The Agile Monkeys’ Journey - Medium</title>
            <link>https://medium.com/the-theam-journey?source=rss----f90e0a497750---4</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Tue, 19 May 2026 06:43:12 GMT</lastBuildDate>
        <atom:link href="https://medium.com/feed/the-theam-journey" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[LLMs and Embeddings 101: Unleash the Power of GPT-4 with Unbounded Long-term Memory]]></title>
            <link>https://medium.com/the-theam-journey/llms-and-embeddings-101-unleash-the-power-of-gpt-4-with-unbounded-long-term-memory-edd77b83e536?source=rss----f90e0a497750---4</link>
            <guid isPermaLink="false">https://medium.com/p/edd77b83e536</guid>
            <category><![CDATA[vector-database]]></category>
            <category><![CDATA[embedding]]></category>
            <category><![CDATA[llm]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[embeddings-search]]></category>
            <dc:creator><![CDATA[Javier Toledo]]></dc:creator>
            <pubDate>Thu, 29 Jun 2023 11:39:39 GMT</pubDate>
            <atom:updated>2023-07-03T16:17:25.184Z</atom:updated>
            <content:encoded><![CDATA[<h4>An introductory-level catch-up for anyone interested in going beyond ChatGPT</h4><figure><img alt="Midjourney. Prompt: a galaxy of embeddings inside of a robot mind" src="https://cdn-images-1.medium.com/max/1024/1*-QbkfF6ddzLQssLSyjHXzA.png" /><figcaption>Generated with Midjourney. Promt: <em>a galaxy of embeddings inside of a robot mind</em>.</figcaption></figure><p>In the dynamic world of Artificial Intelligence, the tools and concepts we use are continually evolving. Language models, an integral part of this landscape, have grown in complexity and capability, resulting in the creation of Large Language Models (LLMs) such as GPT-4. Alongside LLMs, the concept of semantic embeddings has emerged, unlocking new ways to represent and utilize information. This article serves as a guide, detailing the essentials of LLMs and embeddings, and showcasing how they can be leveraged to extend the power of AI models, providing them with a form of unbounded long-term memory.</p><h3>What is a Large Language Model (LLM)?</h3><p>A Large Language Model is a type of AI model that is designed to generate human-like text. These models are trained on vast amounts of text data, enabling them to predict the next word in a sentence, given the context of the previous words. The “largeness” in LLMs refers to both the training data’s size and the model’s complexity, which often involves billions, or even trillions, of parameters (Each of the individual connections inside of the model). GPT-4, for example, leverages transformer-based architectures to process and generate text in a contextually and semantically rich way.</p><p>Thanks to the expansive and high-quality training data they employ, these models have acquired a certain level of problem-solving and reasoning capabilities. These skills are inherited from the vast array of language and literature they’ve been trained on. Consequently, they offer innovative ways to process and comprehend documents and data. Moreover, they provide more user-friendly and intuitive interfaces for human interaction.</p><h3>What does mean to “train” a model?</h3><p>Training a model, such as GPT-4, is an intricate and resource-intensive process. Drawing inspiration from the workings of biological brains, a large AI model is a network comprised of millions of nodes (or artificial neurons), connected by billions of weighted links. The training process necessitates the calculation of a specific set of weights to make the neural network function in the desired manner.</p><p>To illustrate, the fundamental objective of an LLM like GPT-4 is, quite simply, to predict the most sensible next word given a piece of text. To accomplish this, OpenAI engineers utilized a substantial corpus of text examples, presenting each document to the network and systematically adjusting the weights until the correct words began to surface.</p><p>Training a large language model is a remarkably complex undertaking, necessitating months of computation on specialized hardware and finely honed algorithms. Hence, it’s not a venture that just any organization can embark upon. To harness the power of LLMs using your own data — a prevalent use case — it’s more common not to train a custom model, but to utilize an existing model coupled with a database of embedding-indexed data.</p><h3>What are the Embeddings?</h3><p>Embeddings are numerical representations that encapsulate the semantic meanings and relationships among words, paragraphs, or even entire documents. While that may sound complex, consider this analogy: The word “apple” is semantically closer to the word “fruit”, signifying that an apple is a type of fruit, a relationship our brains naturally discern. However, we view the word “apple” as semantically distant from the word “car”. Embeddings provide a mathematical depiction of these meanings, maintaining the relative semantic distances as we cognitively perceive them. But how? By representing them as vectors or points in high-dimensional space. In this context, “apple” would be positioned closer to “fruit” and further from “car”, thereby reflecting the semantic relationships among these words. Specialized models are used to generate these embeddings.</p><p>In mathematical terms, a vector can be understood as a collection of coordinates that represent a point in space, corresponding to the size or dimensions of the vector itself. For instance, a vector of three numbers could denote a specific point in space, such as latitude, longitude, and altitude. Embeddings function on a similar principle, but typically involve thousands of dimensions, thus creating a high-dimensional space. Even though we cannot visually represent these in a way that’s comprehensible to humans, we can still manipulate them mathematically. For example, to calculate the distance between two text pieces, which would be a numerical measurement of how much their semantics are related.</p><h3>Generating Embeddings for custom data</h3><p>Embeddings can be created with specialized AI models that are specifically designed for this. OpenAI provides its own API endpoint to generate embeddings, but there are other models that can be used, the important thing is that you use the same model for all the documents you’re handling. The embeddings model processes a given text and outputs the corresponding high-dimensional vector.</p><p>This operation is not reversible, given an embedding, you can’t get the original text again, so the original text must be kept in order to retrieve it later. The interest in generating embeddings is that once we have them for two documents, we can compare how close or far they are from each other from a semantics point of view.</p><p>To enhance the efficiency of our embeddings and circumvent the size constraints inherent in embedding models, it might be necessary to partition large documents into smaller segments. The more distinct these segments are, the better. For instance, if we were to generate embeddings for this article, we would likely create one for each individual section.</p><h3>Specialized Databases for Embeddings</h3><p>When dealing with extensive text collections in Language Learning Models (LLMs), the large embeddings created require a special operation for retrieval, known as Nearest Neighbours Search. This operation is not supported by most conventional databases, necessitating the use of specialized databases adept at handling high-dimensional data.</p><p>There are many solutions designed for efficient storage, search, and management of vectors like <a href="https://ai.facebook.com/tools/faiss/">Faiss by Meta</a>, <a href="https://milvus.io/">Milvus</a>, <a href="https://qdrant.tech/">Qdrant</a>, <a href="https://www.trychroma.com/">Chroma DB</a>, or <a href="https://www.pinecone.io/">Pinecone</a>, among others​.</p><p>For more traditional setups, it is possible to use <a href="https://github.com/pgvector/pgvector">PostgreSQL with the pgvector extension</a>, which could be convenient if you’re planning to keep all the data in the same place​, or use the advanced vector search features of indexing engines as <a href="https://www.elastic.co/">ElasticSearch</a> or <a href="https://opensearch.org/">OpenSearch</a>.</p><h3>Using Embeddings for Semantic Search</h3><p>Once we have generated embeddings for all our documents and inserted them in a database that supports vector searches, they can be used to perform semantic searches, a type of search that understands the searcher’s intent and the contextual meaning of terms to generate more relevant results.</p><p>Because embeddings capture the semantic meaning of words and sentences, they can be used to find the “closest” (in terms of vector distance) entries in a database to a given query or question.</p><p>For example, if we input a query like “juicy fruit”, a semantic search powered by embeddings might return entries containing “apple” or “orange”, even if the exact phrase “juicy fruit” is not present. This is because the embeddings for “juicy fruit” and “apple” are close in the high-dimensional space.</p><h3>In-Context Learning and Extending the LLM’s Long-Term Memory</h3><p>A key aspect of LLMs like GPT-4 is their ability to generate text that is contextually relevant. However, these models traditionally do not have long-term memory, meaning they don’t remember information beyond the current context window (a few thousand tokens for GPT-4).</p><p>To expand this capacity and give the model a form of “long-term memory,” we can perform semantic searches for any user input, select the closest documents, and inject them as part of the model prompt to augment its knowledge of the matter before answering. This technique is known as in-context learning, because instead of training the model with new data, we inject relevant information as part of the prompt within the model’s context window.</p><p>For instance, if we’ve previously generated an embedding for a phrase like “Paris is the capital of France”, we can feed this embedding into the model when we ask it about French landmarks. Even though “Paris is the capital of France” is not in the immediate context, the model will still have this information available thanks to the injected embedding.</p><p>This method enables the model to recall and use information beyond its standard context window. This approach is particularly useful in applications where the model needs to maintain consistency or recall information over a large set of documents like a company’s Wiki or the documentation of a technical tool.</p><h3>Conclusion</h3><p>The development of LLMs like GPT-4 has been a major stride in AI and NLP with important implications at many levels, but when organizations want to use them with their own data, training a dedicated LLM from scratch is probably not the best solution. With the power of embeddings, we can store and use semantic information in previously unfeasible ways, allowing us to “teach” commercially available LLMs to work with data outside of their training corpus without having to re-train them.</p><p>This technique enables the possibility to any organization to build specialized LLM-powered tools that take advantage of private or very specific or private data and knowledge.</p><p>Do you want to know more? Visit our <a href="https://building.ellmental.com/">‘Open Kitchen’ page</a> to find everything we’ve learned on our AI journey. Don’t hesitate to contact us if you need help!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=edd77b83e536" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-theam-journey/llms-and-embeddings-101-unleash-the-power-of-gpt-4-with-unbounded-long-term-memory-edd77b83e536">LLMs and Embeddings 101: Unleash the Power of GPT-4 with Unbounded Long-term Memory</a> was originally published in <a href="https://medium.com/the-theam-journey">The Agile Monkeys’ Journey</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[LLMs Raise the Bar in Software Development: Adapting to a New Era of Democratized 10x Productivity]]></title>
            <link>https://medium.com/the-theam-journey/llms-raise-the-bar-in-software-development-adapting-to-a-new-era-of-democratized-10x-productivity-fa448a702593?source=rss----f90e0a497750---4</link>
            <guid isPermaLink="false">https://medium.com/p/fa448a702593</guid>
            <category><![CDATA[chatgpt]]></category>
            <category><![CDATA[github-copilot]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[productivity]]></category>
            <category><![CDATA[ai]]></category>
            <dc:creator><![CDATA[Javier Toledo]]></dc:creator>
            <pubDate>Tue, 09 May 2023 21:51:46 GMT</pubDate>
            <atom:updated>2023-05-09T21:51:46.278Z</atom:updated>
            <content:encoded><![CDATA[<h4><a href="https://en.wikipedia.org/wiki/Large_language_model"><strong>Large Language Models (LLMs)</strong></a><strong> like </strong><a href="https://openai.com/product/gpt-4"><strong>GPT-4</strong></a><strong> are transforming how we work and learn in the software development industry. With cutting-edge knowledge now available to everyone, how will developers thrive in a post-GPT world?</strong></h4><figure><img alt="A software developer and a futuristic robot writing code together during a pairing session" src="https://cdn-images-1.medium.com/max/1024/1*-2AtmkW23InrSTspIRbTnQ.png" /></figure><p><em>This is a personal opinion piece with my current view on what’s coming. I might be plain wrong or change opinions tomorrow, so I invite you to respond to this post and share your thoughts and perspectives on this topic too.</em></p><h3>Introduction</h3><p><a href="https://en.wikipedia.org/wiki/Large_language_model">Large Language Models (LLMs)</a> such as <a href="https://openai.com/product/gpt-4">OpenAI’s GPT-4</a> are revolutionizing the software development industry by democratizing access to advanced knowledge and programming expertise. <a href="https://github.com/features/copilot">GitHub Copilot</a>, for example, brings LLM capabilities directly into developers’ Integrated Development Environments (IDEs), and the upcoming release of <a href="https://github.com/features/preview/copilot-x">GitHub Copilot X</a> promises even more advanced features.</p><p>These tools will make us faster and produce higher-quality code, thus producing below-average code will soon become unacceptable, and developers must adapt to stay competitive.</p><h3>The Evolving Role of the AI-enhanced Software Developers</h3><p>In this new landscape, the day-to-day work of a software developer could shift towards a role more similar to that of a lead developer, with less emphasis on writing code and more focus on ensuring quality, reviewing code, deeply understanding business requirements, and agreeing with their team on code style, architecture, and boundaries. One of the most critical skills that software developers might need to acquire soon is their ability to build prompts and evaluate, fix, accept, or reject code and documentation <a href="https://githubnext.com/projects/copilot-for-pull-requests/#resolving-issues-with-ai">proposed by LLMs</a>.</p><p>Additionally, LLMs can significantly accelerate the learning process for developers. Previously, learning a new tool or language could take weeks or months of practice, with developers often becoming stuck in the process. The learning experience typically involved long periods of confusion followed by small moments of realization. <a href="https://docs.boosterframework.com/">LLMs can absorb the documentation of any tool</a> and, with <a href="https://www.howtogeek.com/881159/chatgpt-can-now-surf-the-web-with-plugins/">browsing capabilities</a>, inspect the entire internet to find solutions to blockages in seconds. This drives developers through a series of realization moments, one after another, without getting stuck in obstacles. As a result, there’s no reason not to produce not only good but also idiomatic code for any technology you can imagine.</p><blockquote>The post-GPT software engineers will barely write code themselves but still hold responsibility for any code pushed.</blockquote><p>As I see it, the software engineer of the post-GPT world will need more knowledge of quality standards, design patterns and architecture, security, understanding of business processes, and soft skills. All of them already desirable qualities for excellent developers, but now made essential, because knowing how to write code for a specific stack won’t be enough anymore. They will need to master transferable programming skills that make them effectively polyglot, being able to use any programming language or framework in no time, and there will be no excuses for undocumented or poorly tested code.</p><h3>Thriving in a Post-GPT Software Development World</h3><p>Many developers are afraid of the upcoming changes, and there are good reasons to be concerned. We come from a world with a massive demand for anyone who could contribute to creating software. Knowing how to code could easily get you a great job offer with great perks. Now we are headed to a world where one developer with the proper set of skills could produce as much work as an entire team does today.</p><p>To remain competitive in such a landscape, developers must rethink their strategies and adapt to the new situation. Embracing continuous learning, specialization into hard-to-master topics, focusing on creative problem-solving, honing soft skills, and staying up-to-date with industry trends and emerging technologies will be essential. By cultivating their ability to evaluate others’ code and effectively guide its improvement critically, developers can navigate the evolving demands of the job market and thrive in a post-GPT software development world.</p><blockquote>I think the world is gonna find out that if you can have ten times as much code at the same price, you can just use even more — <a href="https://youtu.be/L_Guz73e6fw?t=5812">Sam Altman in the Lex Fridman podcast (1:36:52)</a></blockquote><p>But is it worth the effort? Many are worried that having AI-enhanced developers who do 10x the work will result in 10x fewer developers needed. I believe that at least during the next few years, even if productivity is increased by 10x, the amount of work required and what we expect from software might easily outgrow the productivity increase. AI is not here to compete against competent software developers but to allow us to work on all those ideas that never left the backlog because we had to focus on delivering the ones from the top.</p><p><em>As a personal opinion piece, I welcome your thoughts, experiences, and perspectives on this topic. Please feel free to share them and contribute to the conversation!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fa448a702593" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-theam-journey/llms-raise-the-bar-in-software-development-adapting-to-a-new-era-of-democratized-10x-productivity-fa448a702593">LLMs Raise the Bar in Software Development: Adapting to a New Era of Democratized 10x Productivity</a> was originally published in <a href="https://medium.com/the-theam-journey">The Agile Monkeys’ Journey</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[You can no longer afford time amnesia in your software systems.]]></title>
            <link>https://medium.com/the-theam-journey/you-can-no-longer-afford-time-amnesia-in-your-software-systems-52304e79d1d3?source=rss----f90e0a497750---4</link>
            <guid isPermaLink="false">https://medium.com/p/52304e79d1d3</guid>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[event-driven-systems]]></category>
            <category><![CDATA[event-sourcing]]></category>
            <category><![CDATA[machine-learning]]></category>
            <dc:creator><![CDATA[Javier Toledo]]></dc:creator>
            <pubDate>Tue, 14 Mar 2023 19:26:27 GMT</pubDate>
            <atom:updated>2023-03-15T09:48:43.612Z</atom:updated>
            <content:encoded><![CDATA[<h3>In the AI-driven world, you can no longer afford time amnesia in your software systems.</h3><h4>Event-driven machine learning will enable a new generation of businesses that will be able to make incredibly thoughtful decisions faster than ever, but is your data ready to take advantage of it?</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BMDn-3fXEP4uZadTq6f55A.png" /></figure><p>When you look at the speed of innovation in the AI world, it seems like each business out there will eventually fall within one of these two categories: <a href="https://hbr.org/2020/01/competing-in-the-age-of-ai">the ones that took advantage of AI and the ones that went out of business because they could no longer compete</a>. And <strong>the key differentiation factor is going to be the amount and quality of their data</strong>. Here, let me especially highlight the word <strong>quality</strong> because <strong>knowing what, when, and why something happened in your company will be crucial</strong>.</p><p>But <strong>how can you be certain that you can recover this information since you turned your system on for the first time</strong>? This is exactly the core value of <a href="https://martinfowler.com/eaaDev/EventSourcing.html">event sourcing</a>: Instead of storing only the current state of a system, <strong>everything that happens is stored permanently</strong> as a long series of immutable events. Then, <strong>the state shown to the users is calculated on demand, but the events are never discarded</strong>, they can always be inspected, reprocessed, or forwarded to other places.</p><p><a href="https://event-driven.io/en/when_not_to_use_event_sourcing/"><strong>Not all developers are willing to adopt this way of storing data</strong> <strong>though</strong></a>. <a href="https://martinfowler.com/eaaDev/EventSourcing.html">Event sourcing</a> and <a href="https://en.wikipedia.org/wiki/Command%E2%80%93query_separation#Command_Query_Responsibility_Separation">CQRS</a>, an intimately related pattern, require a slightly different way of thinking. Software developers that are not used to them tend to fall back into implementing <a href="https://en.wikipedia.org/wiki/Representational_state_transfer">RESTful solutions</a> instead, as they’re <a href="https://eventmodeling.org/"><strong><em>perceived</em></strong></a> simpler, but at design time <a href="https://www.forbes.com/sites/forbestechcouncil/2022/06/27/data-culture-what-it-is-and-how-to-make-it-work/?sh=1557ffba2096">it’s hard to predict who and when will need the extra data</a>, so why going the extra mile? Why making the extra investment on development time and data storage?</p><blockquote>In the era of AI, a company can no longer afford to discard a whole dimension of their data, especially when it is as relevant as time.</blockquote><p>That is exactly the risk, once you’ve discarded the time-series data, it becomes unrecoverable. <strong>We’re sacrificing a dimension of the data that could become of high relevance in the mid-term for a perceived short-term benefit</strong>.</p><p>Data science teams mitigate this problem using <a href="https://en.wikipedia.org/wiki/Change_data_capture">Change Data Capture (CDC)</a>. Most databases keep an operations log that provide a reliable source of differential changes. But <strong>CDC misses another important variable: the semantics of each change</strong>, that is, why the change happened. It’s not the same to say “the order has been updated” as saying “the order has been paid,” the second statement is way more relevant from a business analytics point of view.</p><p>A development team that is aware of the importance of data will always make an effort to generate enough metadata to infer the context. Still, <strong>humans will make mistakes, and more frequently, we will easily decide to deprioritize this when there’s a hard deadline</strong>. A team that uses <strong>event sourcing generates high-quality data by design, </strong>without the team needing to make a conscious decision or extra effort.</p><blockquote>Event sourcing removes the responsibility from the development team to decide whether a change must be stored, because the only way to change the system state is by creating an event that encapsulates what changed, when, and why.</blockquote><p>But the advantages of storing events don’t end there. Events are also structurally different, <strong>they can be easily sorted and consumed in progressive chunks</strong>, and as they’re immutable, <strong>there’s no risk that a piece of data you’ve already processed gets out of sync because other process updates it</strong>. All event consumers can work assuming that they only need to process the next event in the queue and won’t miss a byte of data. Hence, <strong>they enable, </strong><a href="https://medium.com/swlh/the-engineers-guide-to-event-driven-architectures-benefits-and-challenges-3e96ded8568b"><strong>among other things</strong></a><strong>, what some authors are starting to describe as </strong><a href="https://medium.com/phi-skills/event-driven-machine-learning-52680a97cf64"><strong>event-driven machine learning</strong></a>:</p><ul><li><strong>Collecting data becomes easier</strong> with a real-time flow of events available to data analysts, as opposed to relying on static data dumps that provide a snapshot of a database at a particular moment. The event stream is akin to a live sports broadcast, which <strong>can be paused to view specific details in a scene, replayed to analyze interesting moments from the past, or monitored in real-time to observe the most current data</strong>.</li><li><a href="https://towardsdatascience.com/how-to-apply-continual-learning-to-your-machine-learning-models-4754adcd7f7f"><strong>Continual learning</strong></a> becomes possible, this is a technique that <strong>emulates the human ability to adapt their behavior in a dynamic environment.</strong> The models are re-trained with recent events to continuously adapt them to changing environments (i.e. <a href="https://www.invisibly.com/learn-blog/netflix-recommendation-algorithm/">the recommendation system of Netflix requires constant fine-tuning in response to the introduction of new shows and evolving viewer preferences</a>).</li><li>Fine-grained data manipulation enables data-driven decision-making. <strong>Analysts can view data from different angles by reprocessing events and uncover previously inaccessible information</strong>. Each event represents <strong>a change that can be analyzed at an individual level</strong>, such as individual transactions in a bank account, <strong>or aggregated to see a broader picture at a particular time</strong>, such as the account balance. <strong>Data can also be processed to create new perspectives</strong>, like categorizing expenses by type.</li></ul><p>With nowadays tools, using the data in this way can be expensive, and still require the expertise of specialized developers or data scientists, but <strong>we’re expecting advancements in large language models capabilities to provide natural language interfaces for manipulating and visualizing data.</strong> These new data manipulation models will make these techniques available for anyone in an organization, fostering actual <a href="https://www.gartner.com/smarterwithgartner/the-key-to-establishing-a-data-driven-culture#:~:text=A%20key%20characteristic%20of%20a%20data-driven%20culture%20is,transparent%20about%20data%20access%20restrictions%20and%20governance%20methods.">data-driven business cultures</a>.</p><blockquote><strong>New advancements in large language models capabilities will provide natural language interfaces for manipulating and visualizing data, and make data-driven decisions at every level in an organization.</strong></blockquote><p>In short, with all the amazing AI products we’ve seen recently, such as DALL·E or ChatGPT, <strong>we’re barely scratching the surface of what’s to come</strong>. It’s clear that AI is here to stay and <strong>will deeply affect how we conduct business</strong>. To stay competitive in this new AI-driven world, <strong>companies will need to collect high-quality data of everything that happens in their systems</strong>.</p><p><strong>Event sourcing captures high-quality data by design</strong>, packing the what, why, and when for every change, recording events that can be compared to the individual frames of a high-definition security camera for your data.</p><p>This constant stream of events provides extra benefits. <strong>Data can be analyzed or manipulated in real-time</strong>, and <strong>previous states can be replayed</strong>. <strong>Event-driven machine learning models enable accurate predictions and automatic reactions to complex scenarios</strong>, working as a restless security guard that continuously monitor the cameras and find inefficiencies and risks.</p><p>For all these reasons, we believe that <strong>companies that adopt event-driven designs and learn to take advantage of event-driven machine learning models will have a strong competitive advantage and lead the market in this new AI-driven generation</strong>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=52304e79d1d3" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-theam-journey/you-can-no-longer-afford-time-amnesia-in-your-software-systems-52304e79d1d3">You can no longer afford time amnesia in your software systems.</a> was originally published in <a href="https://medium.com/the-theam-journey">The Agile Monkeys’ Journey</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building an Automated Coding Model for Our High-Level Abstraction Framework]]></title>
            <link>https://medium.com/the-theam-journey/building-our-own-automated-coding-model-29118f444f96?source=rss----f90e0a497750---4</link>
            <guid isPermaLink="false">https://medium.com/p/29118f444f96</guid>
            <category><![CDATA[code-generation]]></category>
            <category><![CDATA[language-model]]></category>
            <category><![CDATA[openai]]></category>
            <category><![CDATA[machine-learning]]></category>
            <dc:creator><![CDATA[Doramas Báez Bernal]]></dc:creator>
            <pubDate>Tue, 28 Feb 2023 15:13:38 GMT</pubDate>
            <atom:updated>2023-03-08T09:12:40.649Z</atom:updated>
            <content:encoded><![CDATA[<p><em>Hello there! We are </em><a href="https://www.theagilemonkeys.com/"><em>The Agile Monkeys</em></a><em> and we’re trying to build our custom code generation model for our high-level abstraction event-sourcing framework called </em><a href="https://www.boosterframework.com/"><em>Booster</em></a><em>. We believe that Booster’s approach of removing a significant amount of accidental complexity from the code and the highly semantic code generated with it can make a difference in the precision of code generation models. In this article, we share our first round of experiments.</em></p><figure><img alt="Image of an AI using a computer to programming" src="https://cdn-images-1.medium.com/max/1024/1*8NZTgUWE-e-Xux7nlMakkw.png" /></figure><p>So, you’re probably asking, why are these guys trying to create their own model instead of using tools like ChatGPT or GitHub copilot? Well, we believe that we can improve the performance of these state-of-the-art tools for code generation by reducing the scope of the model. In order to achieve this, we are using <a href="https://www.boosterframework.com/">Booster framework</a>, a framework that allows us to build <strong>event-driven microservices</strong> with the minimal amount of code possible. This will allow us to work on a constrained problem, reducing its complexity. The final result should be an AI assistant that empowers a new kind of development experience that doesn’t require you to know about a specific set of tools.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgiphy.com%2Fembed%2FkuTpXMNmCnNte%2Ftwitter%2Fiframe&amp;display_name=Giphy&amp;url=https%3A%2F%2Fmedia.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExNTgyNDA0OGNmNTM0MjRhN2ZiNGVkNjhlMzc1MGVjNmY5ZTdhMGEyZSZjdD1n%2FkuTpXMNmCnNte%2Fgiphy-downsized-large.gif&amp;image=https%3A%2F%2Fi.giphy.com%2Fmedia%2FkuTpXMNmCnNte%2Fgiphy-downsized-large.gif&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=giphy" width="435" height="289" frameborder="0" scrolling="no"><a href="https://medium.com/media/b9cd64de8c6583bdab8be52cdfc25829/href">https://medium.com/media/b9cd64de8c6583bdab8be52cdfc25829/href</a></iframe><h3>First steps</h3><p>We believe that code generation models offer a wide range of benefits to software developers, including <strong>saving time</strong>, <strong>reducing errors</strong>, and <strong>improving overall productivity</strong>. However, we also recognize that creating an effective code generation model can be a complex and challenging task. For that reason, we have carefully planned and executed a series of steps:</p><ol><li>Analyze the state-of-the-art models and select the most promising model to create an effective code generation model.</li><li>Collect all the necessary data that will be used to help our model learn the intricacies of our particular framework.</li><li>Explore the possibility of using in-context learning techniques to enhance the model capabilities.</li><li>Investigate if we can achieve further improvement by fine-tuning our model.</li><li>Measure the results of our code generation efforts</li></ol><p>By carefully following these steps, we believe that we can build a highly effective and efficient code generation model that will be a valuable asset to our team, and Booster’s developers.</p><h3>State-of-the-art model</h3><p>We have invested considerable time analyzing the state-of-the-art models as they can significantly impact the performance and accuracy of the code generation system. After analyzing these models, we decided to use OpenAI’s text completion model, which is a Large Language Model (LLM) that will provide us with the necessary capabilities to build a highly effective code generation model. In addition, OpenAI provides all the necessary infrastructure and tools that will allow us to perform experiments in a very fast way to validate our hypothesis.</p><p>In fact, OpenAI has emerged as a leading <strong>provider of state-of-the-art models</strong> in machine learning and natural language processing. By making their models available through an API, OpenAI has democratized access to cutting-edge AI and enabled researchers and developers around the world to build on their work. However, it is more complex than just selecting the model, training a code generation model requires labeling enough quality examples of our code algorithms. So, what do we need to create a model that generates code with our framework?</p><h3>Data data and data</h3><p>Collecting the data is a crucial step to creating a good machine learning model. In this sense, we also want to <strong>encourage you to contribute to our mission. </strong>If you are interested in helping us to generate data to train this model, you are more than welcome to join the <a href="https://discord.com/invite/bDY8MKx">booster discord</a> and start collaborating with us.</p><p>As we all know, the foundations of machine learning are built on data. It’s like trying to make a sandwich without bread — no matter how many delicious ingredients you have, without the basics, you don’t have much. But what makes data so critical for training models? The importance of data is to provide context to your AI. Deep learning models are really good at predicting and inferring patterns. They need to know the situation they are going to handle to make an accurate prediction. It’s like having your own Sherlock Holmes and asking him to solve a case without giving him any details.</p><p>However, simply having a large dataset is not enough, the <strong>quality of the data is also crucial</strong>. For a model to learn effectively, the data must be <strong>clean</strong>, <strong>well-labeled</strong>, and <strong>representative</strong> of the real-world scenarios the model will encounter. However, obtaining such quality data can be challenging, particularly in certain domains.</p><p>Based on our experience, training a model to generate code can be a challenging task that requires high-quality input data in the form of code snippets and associated descriptions or prompts. The main issue is that this type of data is often proprietary and not widely available, which can limit the amount of quality data that can be obtained. In our case, we tackled this problem by collecting all the Booster projects available and then manually labeling them. However, despite our efforts, we found that the <strong>lack of examples was still an issue</strong> due to the current limited availability of Booster projects.</p><p>If you want to <strong>help us create the next generation of software development experience</strong>, as mentioned before you can join us in the discord channel. In addition, a very simple solution, but an effective one is to start using GitHub tags for your own Booster projects. This way, we’ll be able to filter projects on GitHub and find Booster’s projects quickly. However, to make this idea work, there must be a commitment from the developers/community that they will use the tag. We want you to <strong>use the Booster framework tag!</strong></p><h4>Advice time</h4><p>Based on our experience, we want to share some tips that will improve the performance of the OpenAI model:</p><ul><li>Use a separator at the end of the prompt, e.g. <strong>\\n\\n###\\n\\n</strong>. It’s important to remember to use the separator when we’re performing inference.</li><li>Use an ending token at the end of the completion, e.g. <strong>END.</strong> In addition, it’s important to add the ending token as a stop sequence during inference, e.g. <strong>stop=[&quot; END&quot;]</strong></li><li>It would be ideal if the dataset has at least ~500 examples.</li><li>Ensure that the prompt + completion doesn’t exceed 2048 tokens, including the separator.</li><li>It’s supposed to use a lower learning rate and only 1–2 epochs the model tends to work better for conditional generation.</li></ul><p>It’s also important to keep in mind that the <strong>quality of the data is more important than the quantity</strong>. In other words, it’s better to have a smaller number of high-quality examples than a larger number of low-quality examples.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*zlgbkCKpZ94c-s8s2aWDjw.png" /></figure><h3>In-context learning</h3><p>For our initial experiments, we decided to use the base model of GPT-3 and conduct some in-context learning tests. The basic concept of in-context learning is to provide a list of input-output pairs as input to the language model to demonstrate how to solve a particular task.</p><p>This approach allows us to append a test input and enable the model to make predictions based on the prompt and predicted next tokens. The interesting idea behind using this method is that it will allow us to quickly assess whether the model shows signs of being able to learn to generate Booster code. Once we validate this, we can proceed with other techniques such as fine-tuning that will improve previous results.</p><p>Based on the results of the experiment, we can assume that the model can learn how to generate Booster’s code quite well. Therefore, we believe that if we were able to generate a sufficiently large dataset that covers most of the possible cases, we should obtain a model with good performance for generating entire Booster microservices from natural language.</p><p>As mentioned before, it’s time to move to other ways of training our model. In-context learning is good for quickly testing this idea but it has some limitations. The biggest one is the number of tokens allowed as input. We will be limited in the number of cases we are able to provide as context to the model. Infrastructure costs will also increase since we have to provide context for every code generation. We believe that it’s better to proceed with other training methods at this step of the process.</p><h3>Fine-tuning model</h3><p>Fine-tuning is the process of retraining a pre-trained network on a new dataset to improve its performance for a specific task. The advantage of performing fine-tuning is that the network can fit the new data while preserving the knowledge it acquired from the pre-training.</p><p>We have already validated the hypothesis that booster code could be generated using GPT-3 through in-context learning. Therefore, for this step, we will be using fine-tuning, so there is no need to provide examples in the prompt anymore. This saves costs and enables lower-latency requests. For that reason, we decided to fine-tune our model (The monkey developer). This should allow us to have a model that we can explain with natural language how we want the code of our framework to be, and obtain the desired code as a result. These are our conclusions after fine tuning our model:</p><ul><li>The results obtained are promising; if we compare the base model of GPT-3 with the results obtained with the fine-tuned model, this model is infinitely better.</li><li>We need to increase the number of examples provided to the model in the training phase. Through this, we believe that we could achieve better results.</li><li>We should perform one experiment using a bigger training dataset, in order to measure the correlation between the performance and the size of the dataset.</li></ul><p>However, we have not been able to carry out these experiments, as we were unable to collect more data.</p><h3>Evaluating the results</h3><p>Evaluating the model’s performance is important to determine how well it’s working and whether it’s providing accurate results. In order to track all the experiments, we recommend using a platform like <a href="https://wandb.ai/site">weights &amp; biases</a>, which allows you to manage and version your data, collaborate with your team, and focus on building the best models.</p><p>In addition, to compare different experiments, we used the <a href="https://machinelearningmastery.com/calculate-bleu-score-for-text-python/">Bleu score</a>. This measures the similarity between the generated code and the reference code, and gives a good idea of how close the generated code is to the reference code. By doing this, we could compare different techniques as in-context learning. As we can see in the following image, by using in-context learning and fine-tuning, we got the best performance in generating <a href="https://www.boosterframework.com/">Booster’s code</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*F92s8g3Svdfvte3sowIIAw.png" /></figure><p>The question is, are these results enough to use these code generation models in a real application?</p><h3>Conclusion</h3><p>The results obtained are not good enough to be able to use this tool in a real application. Although the performance of the base model has been improved and, in some cases, the expected code has been generated, there are other cases, perhaps less general and more complex, where the output of the model has been completely wrong. However, these experiments have helped us understand the following points::</p><ul><li>The Fine-tuned GPT-3 model shows improvements over the base model.</li><li>Increasing the number of examples provided to the model is important. In addition, there is a correlation between performance and dataset size.</li><li>We predict that the model may be able to learn how to generate Booster’s code well, using a large dataset covering most cases.</li><li>Community involvement and a data platform are potential options for generating more of Booster’s code or code for your framework.</li></ul><p><strong>We need your help!</strong> We would like to call on the community to help us build a more complete dataset to improve our code generation tool. If you want to be part of this amazing community you can get in touch using <a href="https://discord.com/invite/bDY8MKx">booster discord</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=29118f444f96" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-theam-journey/building-our-own-automated-coding-model-29118f444f96">Building an Automated Coding Model for Our High-Level Abstraction Framework</a> was originally published in <a href="https://medium.com/the-theam-journey">The Agile Monkeys’ Journey</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Cloud File Management with Booster]]></title>
            <link>https://medium.com/the-theam-journey/cloud-file-management-with-booster-cf54c6b83ee2?source=rss----f90e0a497750---4</link>
            <guid isPermaLink="false">https://medium.com/p/cf54c6b83ee2</guid>
            <category><![CDATA[cloud-storage]]></category>
            <category><![CDATA[cloud-computing]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[backend-development]]></category>
            <category><![CDATA[serverless]]></category>
            <dc:creator><![CDATA[Juan Sagasti]]></dc:creator>
            <pubDate>Mon, 13 Feb 2023 12:49:26 GMT</pubDate>
            <atom:updated>2023-02-13T12:49:26.716Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mssK9v3NA7DfBWu40QX7VA.png" /></figure><p><strong>Storage</strong> is one of the <strong>essential</strong> features for most projects. This tutorial will show you how to easily add <strong>cloud file management</strong> to your <strong>Booster backend.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*zz2Pd3U7oQDWy95Pgnz-Fw.gif" /></figure><p>As a reminder, our previous articles showed you how to create a cloud-based backend application using Booster. We also demonstrated how to connect this backend with an iOS application easily. All this process was documented in these two articles:</p><ul><li>Backend part: <a href="https://medium.com/the-theam-journey/build-scalable-low-code-backends-with-booster-a32b9386dd27">“Build Scalable Low-Code Backends with Booster”</a></li><li>Frontend part: <a href="https://medium.com/the-theam-journey/from-ios-dev-to-full-stack-in-no-time-with-booster-f2eda6463c40">“From iOS Dev to Full-Stack in No Time with Booster”</a></li></ul><p>To showcase this new file feature, we will use the Live Questions app documented in those articles to allow users to set a profile picture that will be uploaded to the Booster backend.</p><h3>Rockets are cool 🚀</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/426/1*N5_JJqXhY3-4by6DqtX-kA.gif" /></figure><p><strong>Booster utilizes <em>Rockets</em> to extend your backend</strong> infrastructure and runtime with features not included in the framework core. Think of rockets as reusable and composable <strong>plug-ins</strong> that <a href="https://docs.boosterframework.com/going-deeper#extending-booster-with-rockets">anyone can create</a> to extend Booster functionality.</p><p>In this case, for adding file management to our Live Questions Booster backend, we will integrate the <a href="https://github.com/boostercloud/rocket-file-uploads">File Uploads Rocket</a> already created and available to the Booster community.</p><h3>Backend part</h3><p>This rocket allows <strong>file storage in AWS or Azure</strong> as the cloud providers. We are going to use AWS for our backend and examples. Here’s a quick overview of the things you can do with the 1.0.0 of this rocket, as you can see in the <em>Readme</em> file in the <a href="https://github.com/boostercloud/rocket-file-uploads">repository</a>:</p><ul><li>Get the <strong>pre-signed upload URL</strong> to which you will do the multipart file <strong>upload</strong>.</li><li>Get the <strong>pre-signed download URL</strong> of an existing file.</li><li><strong>List</strong> all the files in a directory.</li><li><strong>Delete</strong> a file.</li><li>Add <strong>authorization</strong> to those operations easily through your Booster <strong>commands and user roles.</strong></li><li>When a file is uploaded to the cloud, the rocket will generate a <strong>new Booster event and entity</strong>. This way, you can create a Booster <strong>ReadModel</strong> in your backend to provide a view of the files uploaded to a directory.</li></ul><p>As a reminder, let’s ask ChatGPT what a pre-signed URL is and why we need them. Answer:</p><blockquote>A pre-signed URL is a URL that has been signed with authentication credentials, allowing anyone with the URL to upload or download the associated object in your Amazon S3 bucket, without requiring AWS security credentials or permissions.</blockquote><blockquote>Pre-signed URLs are useful when you want to give time-limited permission to upload or download a specific object. For example, you might use a pre-signed URL to allow a user to upload a file to your S3 bucket, or to download a specific file that they have been granted access to. The pre-signed URL contains all the information required to perform the upload or download, including the bucket name, object key, and a signature that verifies the authenticity of the request. The signature is generated using your AWS access key, which is used to calculate the signature for the URL.</blockquote><blockquote>Pre-signed URLs are valid for a limited period of time, which is specified when the URL is generated. Once the URL has expired, it can no longer be used to upload or download the associated object. This helps to ensure that your data remains secure, as it cannot be accessed after the pre-determined expiration time.</blockquote><h4>Update dependencies</h4><p>To include the AWS Rocket in your project, go to your package.json file and add the following packages in the dependenciespart:</p><pre>  &quot;@boostercloud/rocket-file-uploads-aws&quot;: &quot;VERSION&quot;,<br>  &quot;@boostercloud/rocket-file-uploads-core&quot;: &quot;VERSION&quot;,<br>  &quot;@boostercloud/rocket-file-uploads-types&quot;: &quot;VERSION&quot;,</pre><p>And the the infrastructure package in the devDependencies part:</p><pre>&quot;@boostercloud/rocket-file-uploads-aws-infrastructure&quot;: &quot;VERSION&quot;</pre><p><strong>Note:</strong> If you are using Azure as your cloud provider, make sure to use the appropriate packages (<em>-azure</em> instead of <em>-aws</em>).</p><h4>Configure the rocket in your Booster backend</h4><p>As you can see in our <a href="https://github.com/theam/livequestions-booster/blob/main/src/config/config.ts">config.ts</a> file:</p><pre> const rocketFilesConfigurationDefault: RocketFilesUserConfiguration = {<br>         storageName: &#39;&lt;STORAGE_NAME&gt;&#39;, // The name you want for your AWS S3 bucket.<br>         containerName: &#39;&#39;, // You can leave this empty, not needed in AWS.<br>         directories: [&lt;DIRECTORY_NAME_1&gt;] // Root directories for your files.<br> }<br><br><br>Booster.configure(environment.name, (config: BoosterConfig): void =&gt; {<br><br>[...]<br><br>config.rockets = [new BoosterRocketFiles(config, <br>                      [rocketFilesConfigurationDefault]).rocketForAWS()]</pre><p>Note: The containerName parameter is <strong>not used</strong> in AWS, so the final structure created will be storage &gt; directory &gt; files.</p><h4>Create a Command for getting the Pre-signed Upload URL</h4><p>As we will use this rocket to upload and download profile pictures, we created a command that abstracts the clients without specifying parameters like the file name and the file directory. Our <a href="https://github.com/theam/livequestions-booster/blob/main/src/commands/profile-picture-upload-url.ts">profile-picture-upload-url.ts</a> command make that decision internally (and extra validations). The image will be stored in “files/&lt;userId&gt;/profilePicture.jpg”. Our command interacts with the rocket through the FileHandler API:</p><pre>@Command({<br>     authorize: [UserRole],<br>     before: [CommonValidations.userValidation]<br> })<br> export class ProfilePictureUploadURL {<br>   public constructor() {}<br><br>   public static async handle(command: ProfilePictureUploadURL, register: Register): Promise&lt;PresignedPostResponse&gt; {<br>     const boosterConfig = Booster.config<br>     const fileHandler = new FileHandler(boosterConfig, ConfigConstants.rocketFilesConfigurationDefault.storageName)<br>     return await fileHandler.presignedPut(ConfigConstants.rocketFilesConfigurationDefault.directories[0], `${getUserId(register)}/${profilePictureKey}`) as Promise&lt;PresignedPostResponse&gt;<br>   }<br> }</pre><p>The PresignedPostResponse contains the upload URL and the metadata fields needed to perform the multipart upload from the client:</p><pre>export class PresignedPostResponse {<br>  public constructor(<br>    readonly url: string,<br>    readonly fields: { [key: string]: string }<br>  ){}<br>}</pre><h4>Create a Command for getting the Pre-signed Download URL</h4><p>The command for getting the download URL is similar, but the response will be just the download URL string this time. As you can see in<a href="https://github.com/theam/livequestions-booster/blob/main/src/commands/profile-picture-download-url.ts">profile-picture-download-url.ts</a>:</p><pre>@Command({<br>    authorize: [UserRole],<br>    before: [CommonValidations.userValidation]<br>})<br>export class ProfilePictureDownloadURL {<br>  public constructor() {}<br><br>  public static async handle(command: ProfilePictureDownloadURL, register: Register): Promise&lt;string&gt; {<br>    const boosterConfig = Booster.config<br>    const fileHandler = new FileHandler(boosterConfig, ConfigConstants.rocketFilesConfigurationDefault.storageName)<br>    return await fileHandler.presignedGet(ConfigConstants.rocketFilesConfigurationDefault.directories[0], `${getUserId(register)}/${profilePictureKey}`)<br>  }<br>}</pre><p>You can also check the <a href="https://github.com/theam/livequestions-booster/blob/main/src/commands/files-list.ts">files-list.ts</a> and <a href="https://github.com/theam/livequestions-booster/blob/main/src/commands/delete-profile-picture.ts">delete-profile-picture.ts</a> commands.</p><p>And that’s it. That was the backend part. Easy, right?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/400/1*djZseGiupgrgPoIOouIIHg.gif" /></figure><h3>iOS part</h3><h4>Mutations and client API generation</h4><p>Once you have deployed your Booster changes and the new GraphQL schema is generated, we can start adding the mutations needed to communicate with our new commands in the app.</p><p><a href="https://github.com/theam/livequestions-iOS/blob/main/LiveQuestions/graphql/Mutation/ProfilePictureUploadURL.graphql">ProfilePictureUploadURL.graphql</a></p><pre>mutation ProfilePictureUploadURL {<br>    ProfilePictureUploadURL {<br>        url<br>        fields<br>    }<br>}</pre><p><a href="https://github.com/theam/livequestions-iOS/blob/main/LiveQuestions/graphql/Mutation/ProfilePictureDownloadURL.graphql">ProfilePictureDownloadURL.graphql</a></p><pre>mutation ProfilePictureDownloadURL {<br>    ProfilePictureDownloadURL<br>}</pre><p>You can also check <a href="https://github.com/theam/livequestions-iOS/blob/main/LiveQuestions/graphql/Mutation/FilesList.graphql">FilesList.graphql</a> and <a href="https://github.com/theam/livequestions-iOS/blob/main/LiveQuestions/graphql/Mutation/DeleteProfilePicture.graphql">DeleteProfilePicture.graphql</a>.</p><p>As we previously mentioned in the other <a href="https://medium.com/the-theam-journey/from-ios-dev-to-full-stack-in-no-time-with-booster-f2eda6463c40">article</a>, you can use Apollo’s Code Generation tool to download your schema and generate the Swift API for the types defined in it. Execute the following command in the terminal on the root folder of your iOS project:</p><pre>./apollo-ios-cli generate -f</pre><h4>Profile image upload</h4><p>To upload the profile picture, you will first need to call the ProfilePictureUploadURL mutation to obtain the necessary information for the file upload, such as the URL and the fields required for the pre-signed multipart request:</p><pre>func uploadProfilePicture(data: Data) async throws {<br>        let mutation = BoosterSchema.ProfilePictureUploadURLMutation()<br>        <br>        guard let result = try await networkClient.mutate(mutation: mutation)?.profilePictureUploadURL,<br>              let fields = result.fields.value as? [String: String] else { throw FileError.presignPostFailure }<br>                   <br>        let presignedPost = PresignedPost(url: result.url, fields: fields)<br>        let uploadEndpoint = API.uploadFile(data: data, metadata: presignedPost)<br>        let uploadRequest = try URLRequest(endpoint: uploadEndpoint)<br><br><br>        _ = try await URLSession.shared.data(for: uploadRequest)<br> }</pre><h4>Profile image download</h4><p>You need to call the ProfilePictureDownloadURL mutation to get the pre-signed URL of the file you want to download:</p><pre> func downloadProfilePicture() async throws -&gt; Data {<br>        let mutation = BoosterSchema.ProfilePictureDownloadURLMutation()<br>        <br>        guard let urlString = try await networkClient.mutate(mutation: mutation)?.profilePictureDownloadURL,<br>              let url = URL(string: urlString) else { throw FileError.presignGetFailure }<br>        <br>        let fileRequest = URLRequest(url: url)<br>        let (imageData, _) = try await URLSession.shared.data(for: fileRequest)<br>        return imageData<br> }</pre><p>You can also see examples of the removeProfilePicture() and filesList() methods in <a href="https://github.com/theam/livequestions-iOS/blob/main/LiveQuestions/LiveQuestions/Core/Network/FileService.swift">FileService.swift</a>.</p><h3>Conclusion</h3><p>Integrating file upload and download into your Booster app was easy with this rocket. With a few new mutations and requests, you now have file management capabilities!</p><p>Booster offers a convenient way to add file management with access control to enterprise-grade apps without cloud expertise. Reach out to our supportive developer community on Discord for any questions or help. <a href="https://discord.gg/bDY8MKx"><strong>Join us on Discord</strong></a> and become part of our thriving community!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*AMSZJkk0zdiCBFrZDAvmMg.gif" /></figure><p><em>This article was co-authored by </em><a href="https://medium.com/u/fde5117cf177?source=post_page-----a32b9386dd27--------------------------------"><em>Damien Vieira</em></a><em> and </em><a href="https://medium.com/u/9264cd49404b?source=post_page-----a32b9386dd27--------------------------------"><em>Juan Sagasti</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cf54c6b83ee2" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-theam-journey/cloud-file-management-with-booster-cf54c6b83ee2">Cloud File Management with Booster</a> was originally published in <a href="https://medium.com/the-theam-journey">The Agile Monkeys’ Journey</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Matilda Joslyn Gage]]></title>
            <link>https://medium.com/the-theam-journey/matilda-joslyn-gage-66f349ff930?source=rss----f90e0a497750---4</link>
            <guid isPermaLink="false">https://medium.com/p/66f349ff930</guid>
            <dc:creator><![CDATA[Chaxiraxi Cabrera]]></dc:creator>
            <pubDate>Sat, 11 Feb 2023 15:14:34 GMT</pubDate>
            <atom:updated>2023-02-11T15:21:52.284Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/550/1*kl5fnLDj2lzUqrZfqiwcxw.jpeg" /></figure><p>On March 24, 1826, Matilda Joslyn Gage was born in New York. A prolific <strong>writer and activist </strong>who contributed to many social causes such as <strong>abolition, feminism, Native American rights and religion</strong>, but best known for or her contributions to the <strong>suffragette movement</strong>. These contributions began in 1869 with significant accomplishments including:</p><ul><li>Funding, along with Susan B. Anthony and Elizabeth Cady Stanton, the National Woman Suffrage Association.</li><li>Publishing the National Citizen and Ballot Box, NWSA’s official newspaper from 1878 until 1881.</li><li>Writing The History of Woman Suffrage, along with Stanton and Anthony.</li><li>Funding the Women’s National Liberal Unity.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/1*29CWYDSjsSNOog2s9XRwdQ.jpeg" /></figure><p>She encouraged her son-in-law, L. Frank Baum, to write down stories. Gage’s words and writings about how governments and churches have persecuted innocent women throughout the centuries by accusing them of heresy and witchcraft (Woman, Church and State, 1893) inspired his stories, in particular, his most famous work: <strong>The Wizard of Oz</strong>. Many of Gage’s ideas can be recognized in the themes of the book. He used his mother-in-law’s vivid descriptions of witch-hunting as inspiration for world building, where he created <strong>a world where men and women are treated as equals, basic needs are met, contributions are made according to ability, moral principles exist independent of religious institutions, cultural differences are valued, and conflicts are not tolerated</strong>. Gage’s views influenced Baum’s portrayal of the <strong>strong and independent female characters</strong> in the book, as well as his critiques of organized religion. Some authors say, Baum’s character of “the good witch” may have been inspired by her mother-in-law, being Glinda a contraction of good and Matilda.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mKFFX8zCqEvxc_9L_tSdoQ.png" /></figure><p>Matilda has also been the inspiration for the <strong>NoMoreMatildas movement</strong>. In 1870 she published an essay entitled Woman as Inventor (1870) in which she denounced a social situation in which <strong>women scientists receive less credit and recognition for their scientific work than men</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*cRWLXv8oQFUqm06b5er-RQ.jpeg" /></figure><p>Matilda’s figure not only inspires us but also has taught us the importance of <strong>giving credit to those who deserve it</strong>. Most of the time we don’t think about the importance of giving credit, do you ever use an image for an article or presentation without credit to the artist that created it? This could be seen as a simple thing, I find something on the Internet so I use it. But this scenario can be extrapolated to other areas such as science or software. Giving credit to someone works means you appreciate that work you can use, you’re giving value to someone else&#39;s work so they can gain confidence in that work and receive feedback so they can grow stronger as professionals.</p><h3>References:</h3><ul><li>https://msmagazine.com/2021/03/29/wizard-of-oz-matilda-joslyn-gage-suffrage-feminist/</li><li>https://matildajoslyngage.org/gage-biography</li><li>https://matildajoslyngage.org/about-the-gage-home</li><li>https://www.historynet.com/matilda-josyln-gage-the-unlikely-inspiration-for-the-wizard-of-oz/</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=66f349ff930" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-theam-journey/matilda-joslyn-gage-66f349ff930">Matilda Joslyn Gage</a> was originally published in <a href="https://medium.com/the-theam-journey">The Agile Monkeys’ Journey</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Build scalable Low-Code backends with Booster ]]></title>
            <link>https://medium.com/the-theam-journey/build-scalable-low-code-backends-with-booster-a32b9386dd27?source=rss----f90e0a497750---4</link>
            <guid isPermaLink="false">https://medium.com/p/a32b9386dd27</guid>
            <category><![CDATA[backend]]></category>
            <category><![CDATA[typescript]]></category>
            <category><![CDATA[event-sourcing]]></category>
            <category><![CDATA[scalability]]></category>
            <category><![CDATA[low-code]]></category>
            <dc:creator><![CDATA[Juan Sagasti]]></dc:creator>
            <pubDate>Fri, 23 Dec 2022 01:13:06 GMT</pubDate>
            <atom:updated>2023-02-13T13:19:31.093Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fnQyqvgymonXywdjtL6siA.jpeg" /></figure><p>Are you a backend developer looking to significantly boost your <strong>productivity</strong>, or an iOS (or mobile) developer wanting to become a <strong>full-stack</strong> developer in no time? Keep reading!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/420/1*33YvQEmGj3gAfYRww6bjtw.gif" /></figure><h3>The Problem</h3><p>When choosing a backend stack for a new app, <strong>developers often use no-code or low-code platforms</strong> like Firebase because they offer a variety of features. However, <strong>these tools might not be suitable for more complex data or situations requiring scalability and robust business logic</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*XEaTiUFc6_EALKaHefvoqA.gif" /></figure><p>On the other hand, using <strong>serverless solutions</strong> from scratch can be <strong>time-consuming and require a lot of effort</strong> to set up and manage.</p><p>You just want to <strong>move fast and care most about your business</strong> <strong>logic</strong>, right? The good news is that there’s a <strong>new framework called </strong><a href="https://www.boosterframework.com/"><strong>Booster</strong></a> that can make backend development a breeze, even for those who are new to it, thanks to its <strong>high level of abstraction</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*OwX4VI0egzH-LdXovha0fg.gif" /></figure><h3>Why this tutorial?</h3><p>We are two developers from <a href="https://www.theagilemonkeys.com/"><strong>The Agile Monkeys</strong></a> with a strong background in iOS development, but very limited experience with backend production projects. Despite this, <strong>we have successfully used the Booster framework in several production projects!</strong> We want to share our experience with you, and for that we have created an <strong>open-source iOS app</strong> and an <strong>open-source Booster backend</strong>, as well as written <strong>three</strong> <strong>articles</strong> detailing the process.</p><ul><li>This tutorial covers the Booster backend, and the Booster code can be accessed <a href="https://github.com/theam/livequestions-booster">here</a>.</li><li>A tutorial on the iOS integration can be found <a href="https://medium.com/the-theam-journey/from-ios-dev-to-full-stack-in-no-time-with-booster-f2eda6463c40">here</a>, and you can view the iOS code <a href="https://github.com/theam/livequestions-iOS">here</a>.</li><li>An optional tutorial on how to integrate a Booster Rocket for file storage can be found <a href="https://medium.com/the-theam-journey/cloud-file-management-with-booster-cf54c6b83ee2">here</a>.</li></ul><p>In addition, <strong>the iOS application built for this tutorial is </strong><a href="https://apps.apple.com/app/id1659446314"><strong>available on the App Store</strong></a>. The app, called Live Questions, is a tool for live events, keynotes, and Q&amp;A sessions that allows hosts to create a topic and gather questions from other users in real time.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/256/1*tP_bKhgYR6tLXnTYbDjHmg.png" /><figcaption>‘Live Questions’ app icon</figcaption></figure><p>To be transparent, Booster is actually a framework developed by another team within our company. <strong>Our backend and event-sourcing experts have been working on creating this high level of abstraction for years.</strong> As iOS developers, we have used Booster as if we were external clients of the tool, and have been extremely <strong>impressed with the developer experience and support</strong> we have received.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/716/1*zZ8IZhI6oUCuEb6gMelWxg.png" /></figure><h3>WTF is Booster?</h3><p>In short, <strong>Booster is a Low-Code TypeScript framework</strong> that allows you to quickly and easily create a backend application in the cloud that is <strong>highly efficient, scalable, and reliable</strong>. It follows an <strong>event-driven, event sourcing, and domain-driven design</strong> (DDD) to achieve these goals and it reimagines the software development experience to maximize your team’s speed and <strong>reduce friction</strong> on every level.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/466/1*IpZ8ruvqzExRroKFv6HJ4w.gif" /></figure><p>The <strong>event-driven design</strong> of Booster means that the server is designed to process and <strong>respond to events</strong> rather than traditional requests, making it highly efficient as it can process multiple events concurrently and asynchronously.</p><p>The <strong>event sourcing </strong>design of <strong>Booster stores all changes to the state of the backend as a sequence of events</strong>, like an event log, rather than in a traditional database. This allows the backend to reconstruct the current state of the system at any point in time and makes it easier to track and debug changes to the system. It also allows for the easy implementation of new features by replaying stored events.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*3cYvgVf6-u_VyLoBzTjcNA.gif" /></figure><p>Finally, the <strong>Domain-Driven Design</strong> of Booster involves breaking down the system into <strong>small, cohesive components</strong> that represent different business entities and their relationships. This helps to create a backend that is more <strong>scalable, maintainable, and adaptable</strong> to changing business needs.</p><p>A backend project using Booster is organized, on-rails, into the following components:</p><ul><li><strong>Commands:</strong> Actions that users can take within the system (e.g. create a topic).</li><li><strong>Events:</strong> Simple records of facts (e.g. user X reacted to question Y on topic Z). As Booster is an event-driven framework, events are central to the design of a Booster project.</li><li><strong>Entities:</strong> The source of truth, representing data about the subjects discussed within your company (e.g. topics, questions, users).</li><li><strong>ReadModels:</strong> Public projections of Entities. While Entities are private within the system, ReadModels are publicly accessible (e.g. get topics).</li><li><strong>Handlers:</strong> Code that processes commands, reacts to events to trigger other actions, or updates Entities based on new events.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XrQHW_aF2_v8loW6IEa3Hg.png" /><figcaption>Booster Architecture</figcaption></figure><p><strong>Modeling a reactive backend</strong> is made easy with these building blocks! The high level of abstraction makes it <strong>intuitive, even for non-technical people</strong>. As an example, here is a subset of the backend we created for the Live Questions app:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*oiHrOBx49peJrD4Vx7p1gw.jpeg" /><figcaption>Live Questions Booster Architecture</figcaption></figure><h3>Let’s create our Booster backend!</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/409/1*RtuOE6i1ObVRWdy6XRTsKg.gif" /></figure><p>Before starting, it is recommended that you open our <a href="https://github.com/theam/livequestions-booster">open-source repository</a> and refer to it as a guide during this process.</p><h4>1. Install the Booster CLI</h4><p>Booster is supported on macOS, Windows, and Linux. You can follow the installation steps on this <a href="http://docs.booster.cloud/getting-started/installation">page</a>.</p><h4>2. Create the Booster project</h4><p>Navigate to the root folder of your new project, and then run the following command in the Terminal:</p><pre>boost new:project [Project-Name]</pre><p>Follow the prompts and select one of the available <strong>cloud providers</strong> as the main provider for your project. <strong>We recommend AWS</strong> for this project. You first need to <a href="https://docs.boosterframework.com/getting-started/configuration">set up a free AWS account</a> in order to <strong>deploy</strong> your project.</p><p>After running the command to create your project, you will have a properly configured Booster project that you can open in your preferred code editor (such as Visual Studio Code or VSCodium).</p><p>The project folder will contain configuration files and empty folders for you to add your commands, entities, events, etc:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/652/1*hQJTqs_ibEZe8l-HiKoyNw.png" /></figure><p>For more detailed information about creating a project with Booster, refer to the <a href="https://docs.booster.cloud/getting-started/coding#1-create-the-project">official documentation</a>.</p><h4>3. Create Commands</h4><p><strong>Commands are input for our system</strong> that are typically initiated by the users of our application. Upon receipt, we can validate the data, perform any necessary business logic, and register one or more events.</p><p>To create a new command, you can use the command line generator in the root directory of your project (you can also create the file manually). Here is an example of how to do this:</p><pre>boost new:command CreateTopic --fields title:string timeToLive:number</pre><p>This command will create a TypeScript file called ‘create-topic.ts’ in the ‘src/commands’ directory. The ‘fields’ flag is optional, and you can also add attributes to your command through code after the file has been created.</p><p>You can specify who is authorized to execute the command by adding the <strong>authorized roles</strong>. For now, you can use ‘all’ to authorize anyone. We will discuss user authorization in more detail later.</p><pre>@Command({<br>authorize: &#39;all&#39;<br>})<br>export class CreateTopic {…}</pre><p>To know more about commands, refer to the <a href="https://docs.boosterframework.com/architecture/command">official documentation</a>.</p><h4>4. Create Events</h4><p>Rather than creating, updating, or deleting objects, <strong>Booster stores data in the form of events</strong>, which are <strong>records of facts</strong> and serve as the <strong>source of truth</strong>. To generate an event called ‘TopicCreated’ with initial topic information, run the following command:</p><pre>boost new:event TopicCreated --fields topictId:UUID title:string</pre><p>This command will create a new file in the ‘src/events’ directory. Once you have created all your events, return to your commands to register them. To know more about events, refer to the <a href="https://docs.boosterframework.com/architecture/event">official documentation</a>.</p><h4>5. Create Entities</h4><p><strong>Entities</strong> represent the<strong> internal state of our system</strong> and are responsible for <strong>combining all events with the same entityID</strong>. To create an entity, run the following command:</p><pre>boost new:entity Topic</pre><p>This command will create a new file in the ‘src/entities’ directory. Once you have added all your entities, you can use them to reduce events and update the entity state. To know more about entities, refer to the <a href="https://docs.boosterframework.com/architecture/entity">official documentation</a>.</p><h4>6. Create Read Models</h4><p>In a real application, it is often necessary to limit access to the full domain model (entities), and different users may have different views of the data depending on their permissions. Read models provide a solution to this problem by projecting one or more entities into a new object that can be accessed through a GraphQL query or subscription.</p><p>To create a read model, run the following command:</p><pre>boost new:read-model TopicReadModel --projects Topic:id</pre><p>The ‘ — projects’ flag allows you to specify the entities that the read model will observe for changes to project onto the read model. The ‘:id’ after the entity name is the join key.</p><p>As mentioned earlier when creating commands, you will need to specify who is authorized to query your read models. For now, you can use ‘all’.</p><p>To know more about read models, refer to the <a href="https://docs.boosterframework.com/architecture/read-model">official documentation</a>.</p><h4>7. Local Testing</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*loMH_6zMtJ7m9lw--3D_yA.gif" /></figure><p>We have:</p><ul><li>Created a publicly accessible command</li><li>Emitted an event as a mechanism for storing data</li><li>Reduced the event into an entity to represent the internal state of the system</li><li>Projected the entity into a publicly accessible read model</li></ul><p>To ensure that your code is error-free and compiles correctly, run the following command:</p><pre>boost build –verbose</pre><p>To start the application locally:</p><pre>boost start -e local</pre><p>This will execute a local Express.js server and try to expose it on port 3000. <strong>Booster applications come with a GraphQL API out of the box</strong>, which you can use to send commands through mutations and retrieve read model data through queries or subscriptions.</p><p>For testing in local or development environments, we suggest using the <a href="https://altairgraphql.dev"><strong>Altair GraphQL client</strong></a>. Simply enter the endpoint URL for your application, which is located at <a href="http://localhost:3000/graphql">http://localhost:3000/graphql</a>. It will also load the documentation for your API schema!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6jB7vtRc0xw9CasxpdKxZw.jpeg" /></figure><p>If you are testing a deployed backend (not on your local machine), the endpoint URLs will be displayed in the console after a successful deployment to AWS.</p><p>Keep in mind that <strong>subscriptions are currently not supported in a local environment</strong>. For that, you need to <strong>deploy the app to AWS</strong>.</p><p>In order to ensure that only authorized users can access data or perform actions on the system, it is important to include an ‘Authorization’ header with the value ‘Bearer &lt;user_valid_access_token&gt;’ in your requests using Altair for commands or read models that require authorization. Don’t forget to do this when making requests:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/512/1*Lkv720UVWDdV23-78UZoGw.png" /></figure><p>Note that if you are testing some Commands locally and don’t want to deal with the authentication part (we explain authentication later in the article), you can just keep the Command public and authorize it for ‘all’:</p><pre>@Command({<br>authorize: &#39;all&#39;<br>})<br>export class CreateTopic {…}</pre><h4>8. Configuration</h4><p>The config.ts file is where you can configure the environments you will be using in your project. If you take a look to <a href="https://github.com/theam/livequestions-booster/blob/main/src/config/config.ts">our config file</a>:</p><pre>function buildEnvironment(environment: Environment): void {<br><br>  Booster.configure(environment.name, (config: BoosterConfig): void =&gt; {<br>    config.appName = environment.appName<br>    config.providerPackage = packageOfProvider(environment.provider)<br><br>    switch (environment.provider) {<br>      case EnvironmentProvider.Local:<br>        config.logLevel = Level.debug<br>        break<br><br>      case EnvironmentProvider.AWS:<br>        config.logLevel = Level.debug<br>        config.assets = [&#39;.env&#39;] // Needed for secrets. Fill your secrets in the .env file.<br>        config.tokenVerifiers = [<br>          new JwksUriTokenVerifier(<br>            environment.auth0Issuer,<br>            environment.jwksURL,<br>            &quot;custom:roles&quot;<br>          )<br>        ]<br><br>        break<br>    }<br>  })<br>}<br><br>buildEnvironment(productionEnvironment)<br>buildEnvironment(developmentEnvironment)<br>buildEnvironment(localEnvironment)<br>dotenv.config()</pre><p>It is generally best practice to store sensitive information, such as passwords or API keys, in<strong> environment variables rather than hardcoding them in your code</strong>. This helps to prevent accidental exposure of sensitive information, such as when committing code to a public repository. The dotenv module can be used to separate environment-specific configuration from your code, making it easier to manage and deploy your application. It loads environment variables from a .env file, as seen in the line config.assets = [&#39;.env&#39;]. This file can be used to store your Auth0 secret keys, which will be discussed later in the authentication portion of the tutorial.</p><p>To add the dotenv module or other dependencies to your project, you can use the npm install command, for example: npm install dotenv. This will add the dependency the project&#39;s <a href="https://github.com/theam/livequestions-booster/blob/main/package.json">package.json</a> file, as shown in the example below:</p><pre>{<br>  &quot;name&quot;: &quot;livequestions&quot;,<br>  &quot;description&quot;: &quot;Backend of the questions gathering app&quot;,<br>  &quot;version&quot;: &quot;0.1.0&quot;,<br>  &quot;author&quot;: &quot;The Agile Monkeys&quot;,<br>  &quot;dependencies&quot;: {<br>    &quot;@boostercloud/framework-core&quot;: &quot;^1.3.0&quot;,<br>    &quot;@boostercloud/framework-provider-aws&quot;: &quot;^1.3.0&quot;,<br>    &quot;@boostercloud/framework-types&quot;: &quot;^1.3.0&quot;,<br>    &quot;auth0&quot;: &quot;^2.30.0&quot;,<br>    &quot;dotenv&quot;: &quot;^16.0.0&quot;<br>  },<br>[...]</pre><p>To install all dependencies already defined in the package.json file, you can simply run npm install.</p><p>Additionally, you may want to take a look at the <a href="https://github.com/theam/livequestions-booster/blob/main/src/config/environment.ts">environment.ts</a> file we created to abstract the details of each environment:</p><pre>[...]<br><br>export const developmentEnvironment: Environment = {<br>  name: &#39;dev&#39;,<br>  appName: &#39;livequestions-dev&#39;,<br>  provider: EnvironmentProvider.AWS,<br>  auth0Issuer: &quot;&lt;AUTH0_ISSUER&gt;&quot;, // Example: &quot;https://blablabla.eu.auth0.com/&quot;,<br>  jwksURL: &quot;&lt;AUTH0_JWKS_URL&gt;&quot; // Example: &quot;https://blablabla.eu.auth0.com/.well-known/jwks.json&quot;<br>}<br><br>[...]</pre><h4>9. User Authorization with Auth0</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/620/1*-H4tT0ZK4JV9zCPeHOVtOw.gif" /><figcaption>Access denied</figcaption></figure><p>To ensure secure access, <strong>Booster uses the OAuth 2.0 protocol for authentication.</strong> This protocol involves the use of JSON Web Tokens (JWT) to identify and authorize users. These JWT tokens, also known as <strong>access tokens</strong>, are issued by an authentication provider such as <a href="https://auth0.com/"><strong>Auth0</strong></a>, which we are using in this project. Other popular providers that support OAuth 2.0 include Firebase and others.</p><p>As mentioned in our <a href="https://medium.com/the-theam-journey/from-ios-dev-to-full-stack-in-no-time-with-booster-f2eda6463c40">iOS tutorial</a>, we are utilizing Auth0 for user authentication in our system. In addition, we will be implementing a <strong>role-based authorization mechanism in the Booster backend</strong> to ensure that only <strong>authenticated users</strong> with the <strong>appropriate role</strong> can perform certain actions. To begin, let’s create the roles.ts file and define the <em>UserRole</em>:</p><pre>import { Role } from &#39;@boostercloud/framework-core&#39;<br><br>@Role()<br>export class UserRole {}</pre><p>While we could define additional roles, such as Admin, for the purposes of this tutorial we will only be adding one role to keep things simple.</p><p>To begin using Auth0 for your experiments, create a free account and then go to the Applications section to create a new API called ‘Booster API’.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/729/1*-iKigPcKmGLDet19NPNgtA.png" /></figure><p>Remember the <a href="https://github.com/theam/livequestions-booster/blob/main/src/config/environment.ts">environment.ts</a> file? There we can add the issuer URLs that Booster will use to validate the token:</p><pre>export const developmentEnvironment: Environment = {<br>  name: &#39;dev&#39;,<br>  appName: &#39;livequestions-dev&#39;,<br>  provider: EnvironmentProvider.AWS,<br>  auth0Issuer: &quot;&lt;AUTH0_ISSUER&gt;&quot;, // Example: &quot;https://blablabla.eu.auth0.com/&quot;,<br>  jwksURL: &quot;&lt;AUTH0_JWKS_URL&gt;&quot; // Example: &quot;https://blablabla.eu.auth0.com/.well-known/jwks.json&quot;<br>}</pre><p>Now we need to <strong>add a custom claim to our Auth0 token that Booster will use to get the allowed role</strong> (in this case our role is UserRole). To do this, we will create a <strong>custom action</strong> called ‘Assign User Role’ that will be executed every time a user logs in and before the token is issued:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/497/1*CMu9CuSG7yotPjVoYYKX3w.png" /></figure><p>Inside the code for the Auth0 action, we will add a key-value claim that Booster will look for within the token:</p><pre>exports.onExecutePostLogin = async (event, api) =&gt; {<br>  if (event.authorization) {<br>    api.idToken.setCustomClaim(&quot;custom:roles&quot;, &quot;UserRole&quot;);<br>    api.accessToken.setCustomClaim(&quot;custom:roles&quot;, &quot;UserRole&quot;);<br>  }<br>}</pre><p>If you remember our <a href="https://github.com/theam/livequestions-booster/blob/main/src/config/config.ts">config.ts</a> in Booster, we had that key defined at the token verifier level:</p><pre>[...]<br>case EnvironmentProvider.AWS:<br>        config.logLevel = Level.debug<br>        config.assets = [&#39;.env&#39;]<br>        config.tokenVerifiers = [<br>          new JwksUriTokenVerifier(<br>            environment.auth0Issuer,<br>            environment.jwksURL,<br>            &quot;custom:roles&quot; // &lt;-------- <br>          )<br>        ]<br>[...]</pre><p>Now Booster and Auth0 are working together!</p><p>You can now add proper role-based authorization to your commands and read models!</p><pre>@Command({<br>  authorize: [UserRole]<br>})</pre><pre>@ReadModel({<br>  authorize: [UserRole]<br>})</pre><p>But we are going to go a step further and allow Booster to trigger user accounts deletions in Auth0 for the deletion feature. For that, we need to grant Booster access to the Auth0 Management API.</p><p>Go to the Applications section in Auth0 and create a new <strong>Machine-to-Machine application</strong> called “Booster Users Management.” In the APIs tab, ensure that this application has access to the Auth0 Management API and enable the “delete:users” permission.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-0Qi0YPH_eT0ZL4wcCxAng.png" /></figure><p>Now, in Booster, you need to add the <strong>Domain, Client ID, and Client Secret </strong>values of this Machine-to-Machine application to the <strong>.env</strong> file that we previously mentioned:</p><pre>AUTH0_DOMAIN_DEV=TODO // Example: blablabla.eu.auth0.com<br>AUTH0_CLIENT_ID_DEV=TODO<br>AUTH0_CLIENT_SECRET_DEV=TODO</pre><p>Install the auth0 dependency in Booster:</p><pre>npm install auth0</pre><p>You can check how we call the <strong>Auth0 Management API</strong> from the <a href="https://github.com/theam/livequestions-booster/blob/main/src/commands/delete-user.ts">delete-user.ts</a> Booster command:</p><pre>[...]<br><br>@Command({<br>  authorize: [UserRole],<br>  before: [CommonValidations.userValidation]<br>})<br>export class DeleteUser {<br>  public constructor() {}<br><br><br>  public static async handle(command: DeleteUser , register: Register): Promise&lt;void&gt; {<br>    const userID = getUserId(register)<br>    const environment = currentEnvironment()<br><br>    /// Delete user from Auth0<br>    const management = new ManagementClient({<br>      domain: process.env[`AUTH0_DOMAIN_${environment.name.toUpperCase()}`]!,<br>      clientId: process.env[`AUTH0_CLIENT_ID_${environment.name.toUpperCase()}`],<br>      clientSecret: process.env[`AUTH0_CLIENT_SECRET_${environment.name.toUpperCase()}`],<br>      scope: &#39;delete:users&#39;<br>    })<br><br>    await management.deleteUser({ id: userID })<br><br>[...]</pre><p>It’s important to note that we have already initialized the <strong>dotenv</strong> library with the <em>dotenv.config()</em> function in the config.ts file.</p><p>To know more about authorization, refer to the <a href="https://docs.boosterframework.com/security/authorization">official documentation</a>.</p><h4>10. Deployment</h4><p>Now that we have our environments and roles are properly configured, we can deploy our application to the cloud!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/450/1*pV-Q5tkiZ-KEi01YyDcJQA.gif" /></figure><pre>boost deploy -e dev --verbose</pre><p>The ‘-e &lt;environment name&gt;’ flag specifies which <a href="https://github.com/theam/livequestions-booster/blob/main/src/config/environment.ts">environment</a> to deploy.</p><p>By running the ‘deploy’ command, <strong>Booster will handle the creation of all necessary resources in AWS, such as Lambdas and API Gateway, and configure the necessary permissions, events, and triggers</strong> to connect them. It even creates a fully functional <strong>GraphQL API</strong>. Forget about infrastructure code!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*130OjCYSwohuxNmCfGHy1A.gif" /></figure><h3>Worth mentioning</h3><h4><strong>Logging</strong></h4><p>You can check the application <strong>log groups in CloudWatch</strong>, in your AWS account:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*GECL1zd1ySsF6D6eNGMc5w.png" /><figcaption>CloudWatch</figcaption></figure><p>To know more about logging, Refer to the <a href="https://docs.boosterframework.com/features/logging">official documentation</a>.</p><h4><a href="https://docs.boosterframework.com/features/error-handling#custom-error-handling"><strong>Error handling</strong></a></h4><h4><strong>Data deletion</strong></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/524/1*3YTnZs9_TSkOsLzKlPczBQ.gif" /></figure><p>As you know, <strong>Booster uses event sourcing</strong> to store and manage changes to an application’s state by recording them as a <strong>sequence of events in an event store.</strong> Deleting data can be challenging in event sourcing because events are typically append-only and may have dependencies on other events. Currently, the Booster framework only supports soft deletion. <strong>Hard deletion</strong>, which permanently removes events from the event store, <strong>will be supported</strong> in the near future!</p><p><strong>With soft deletion, you can mark entities as deleted by adding a new event indicating this, rather than deleting the events themselves.</strong> This allows you to maintain the integrity of the event stream while still effectively <strong>deleting a read model</strong>. For example, in our application, we can update a topic or question entity to a deleted state. We also support deletion of users. We encourage you to check these <a href="https://github.com/theam/livequestions-booster/blob/main/src/read-models/user-read-model.ts">use cases</a>.</p><h4>Migrations</h4><p>When implementing a Booster application, you may need to <strong>update your entities and perform some schema migration</strong>. While <strong>data migrations are </strong><a href="https://docs.boosterframework.com/features/data-migrations"><strong>supported in Booster</strong></a>, they can be complex and require careful planning and testing.</p><p>During the development phase, when the state of your application is not critical, it may be easier and faster to delete all of your data directly from your cloud provider and redeploy your application because <strong>having incompatible versions of events can prevent Booster reducers to work</strong>. This will help you avoid any inconsistencies in the system and make the migration process simpler.</p><h3>Conclusion</h3><p>By using Booster, it is possible to create an <strong>enterprise-grade, scalable application without needing extensive expertise in cloud technologies or event-sourcing.</strong> We found the reactive nature of Booster to be very intuitive and effective in boosting productivity.</p><p><strong>Booster is constantly improving. The team is working on new features that will make our lives even easier in the near future.</strong> For instance, they are developing a native authentication solution, the ability to delete events and data permanently, and simpler storage options for file uploads. Stay tuned for updates!</p><p>Remember that we’ve also written an article on <a href="https://medium.com/the-theam-journey/from-ios-dev-to-full-stack-in-no-time-with-booster-f2eda6463c40">how to use a Booster backend with an iOS app</a>, and an article on <a href="https://medium.com/the-theam-journey/cloud-file-management-with-booster-cf54c6b83ee2">how to extend Booster with a rocket to add the file storage feature</a>.</p><p>If you have <strong>any questions</strong> about these articles or want to learn more about using Booster, or if you’d like to <strong>contribute to this open source framework</strong>, come and join us on <a href="https://discord.gg/bDY8MKx"><strong>Discord</strong></a>! Our community of developers is always happy to help and share their knowledge, no matter your skill level. We hope to see you there!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*lElFgY3NLg5IRiConMYMCQ.gif" /></figure><p><em>This article was co-authored by </em><a href="https://medium.com/u/fde5117cf177"><em>Damien Vieira</em></a><em> and </em><a href="https://medium.com/u/9264cd49404b"><em>Juan Sagasti</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a32b9386dd27" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-theam-journey/build-scalable-low-code-backends-with-booster-a32b9386dd27">Build scalable Low-Code backends with Booster 🚀</a> was originally published in <a href="https://medium.com/the-theam-journey">The Agile Monkeys’ Journey</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[From iOS Dev to full-stack in no time with Booster ]]></title>
            <link>https://medium.com/the-theam-journey/from-ios-dev-to-full-stack-in-no-time-with-booster-f2eda6463c40?source=rss----f90e0a497750---4</link>
            <guid isPermaLink="false">https://medium.com/p/f2eda6463c40</guid>
            <category><![CDATA[low-code]]></category>
            <category><![CDATA[graphql]]></category>
            <category><![CDATA[backend]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[serverless]]></category>
            <dc:creator><![CDATA[Juan Sagasti]]></dc:creator>
            <pubDate>Fri, 23 Dec 2022 01:04:33 GMT</pubDate>
            <atom:updated>2023-02-13T13:24:55.185Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nc91Dfx5SWkcmXpLpOIA-g.png" /></figure><p>Are you an iOS (or mobile) developer who wants to become <strong>full-stack</strong> <strong>in no time?</strong> Keep reading!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/342/1*Tbe0TXGsSkmJS69vTnT3Og.gif" /></figure><h3>The Problem</h3><p>When developing a new app, it’s important to consider which backend stack to use for data synchronization and storage. <strong>No-code or low-code </strong>platforms like Firebase <strong>are often popular choices for app developers </strong>because they provide a range of useful features out of the box. While these tools can be helpful for quickly creating an MVP or getting a simple application into production, <strong>they may not be suitable for more complex data sets or situations where robust business logic and scalability are required.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*pTR63w2hC7a9iVFUncH4jA.gif" /></figure><p>On the other hand, setting up and using complex <strong>serverless solutions</strong> from scratch can be <strong>time-consuming</strong> and often require a significant amount of <strong>effort</strong>. There are many different tools and components to manage, and it can be error-prone and involve a lot of boilerplate code. You want to <strong>move fast and care most about your business</strong> <strong>logic</strong>, right? Then keep reading.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*P8KKlPTbKasji6EvcrQKUA.gif" /></figure><p>The good news is that there’s a <strong>new framework called </strong><a href="https://www.boosterframework.com/"><strong>Booster</strong></a> that can make backend development a breeze, even for those who are new to it, thanks to its <strong>high level of abstraction</strong>.</p><h3>Why this tutorial?</h3><p>We are two developers from <a href="https://www.theagilemonkeys.com/"><strong>The Agile Monkeys</strong></a> with a strong background in iOS development, but very limited experience with backend production projects. Despite this, <strong>we have successfully used the Booster framework in several production projects!</strong> We want to share our experience with you, and for that we have created an <strong>open-source iOS app</strong> and an <strong>open-source Booster backend</strong>, as well as written <strong>three articles</strong> detailing the entire process.</p><ul><li>This tutorial covers the iOS integration of a Booster backend, and you can view the iOS code <a href="https://github.com/theam/livequestions-iOS">here</a>.</li><li>The tutorial on the Booster backend can be found <a href="https://medium.com/the-theam-journey/build-scalable-low-code-backends-with-booster-a32b9386dd27">here</a>, and the Booster code can be accessed <a href="https://github.com/theam/livequestions-booster">here</a>.</li><li>An optional tutorial on how to integrate a Booster Rocket for file storage can be found <a href="/the-theam-journey/cloud-file-management-with-booster-cf54c6b83ee2">here</a>.</li></ul><p>In addition, <strong>the iOS application built for this tutorial is </strong><a href="https://apps.apple.com/app/id1659446314"><strong>available on the App Store</strong></a>. The app, called Live Questions, is a tool for live events, keynotes, and Q&amp;A sessions that allows hosts to create a topic and gather questions from other users in real time.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/256/1*tP_bKhgYR6tLXnTYbDjHmg.png" /><figcaption>‘Live Questions’ app icon</figcaption></figure><p>To be transparent, Booster is actually a framework developed by another team within our company. <strong>Our backend and event-sourcing experts have been working on creating this high level of abstraction for years.</strong> As iOS developers, we have used Booster as if we were external clients of the tool, and have been extremely <strong>impressed with the developer experience and support</strong> we have received.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*JF58v4XJQi05FpudupdLeg.jpeg" /></figure><p>In this tutorial, we will guide you through the process of <strong>integrating a Booster backend with an iOS app.</strong> We assume that you already have a basic understanding of iOS development.</p><h3>WTF is Booster?</h3><p>The world, businesses, and modern software are <strong>all driven by events</strong>. As app developers, we understand this concept well, as our apps are designed to respond to user actions and various system and environment events. With Booster, you can build reactive backends that follow this <strong>event-driven model</strong>, while also enjoying a faster development process thanks to its high level of abstraction. <strong>In short, Booster allows you to create reactive cloud-based apps efficiently and effectively.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/245/1*Xu1xcN822WuBc638KlzoHg.gif" /></figure><p>A backend project using Booster is organized, on-rails, into the following components:</p><ul><li><strong>Commands:</strong> Actions that users can take within the system (e.g. create a topic).</li><li><strong>Events:</strong> Simple records of facts (e.g. user X reacted to question Y on topic Z). As Booster is an event-driven framework, events are central to the design of a Booster project.</li><li><strong>Entities:</strong> The source of truth, representing data about the subjects discussed within your company (e.g. topics, questions, users).</li><li><strong>ReadModels:</strong> Public projections of Entities. While Entities are private within the system, ReadModels are publicly accessible (e.g. get topics).</li><li><strong>Handlers:</strong> Code that processes commands, reacts to events to trigger other actions, or updates Entities based on new events.</li></ul><p>For more in-depth information about Booster and its architecture, we recommend checking out the <a href="https://docs.boosterframework.com/">official documentation</a>.</p><p><strong>Booster automatically generates a GraphQL API based on your Commands and ReadModels</strong>, which is how your app will communicate with the backend. This API also <strong>supports real-time updates</strong> through subscriptions using a web socket. Using a GraphQL API is easy and offers numerous benefits over traditional REST APIs, making it an excellent choice for app development!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KL8p3wYDDyIRXWgh_Q7DBg.png" /></figure><h3>How to use Booster from your iOS app</h3><p>To make requests to the GraphQL API exposed by our Booster backend, we need to use a GraphQL library. The best option for iOS is the <a href="https://github.com/apollographql/apollo-ios"><strong>Apollo client</strong></a><strong>.</strong></p><p>Once you have completed the process of creating a Booster backend application (we have a tutorial on this <a href="https://medium.com/the-theam-journey/build-scalable-low-code-backends-with-booster-a32b9386dd27">here</a>), you can follow these steps:</p><h4>1. <strong>Add the Apollo dependency to your Xcode project</strong></h4><ul><li>Open your Xcode project, go to the File tab in the macOS bar, and click “Add Packages”.</li><li>In the Add New Package window, search for “github.com/apollographql/apollo-ios.git” and select “Add Package”.</li><li>In the new window that appears, select “Apollo”, “ApolloAPI”, and “ApolloWebSocket” under “Package Products to add”.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aTMJj_guOp-UB2Xa3DqBFw.png" /></figure><p>You can check all the other options available to import Apollo into your project <a href="https://www.apollographql.com/docs/ios/get-started/">here</a>.</p><h4><strong>2. Set up GraphQL in your project</strong></h4><p><strong>The Apollo iOS client comes with a command-line interface (CLI) that makes it easy to run code generation</strong>, which simplifies the process of working with GraphQL. The CLI will download your Booster GraphQL schema and generate Swift code for your GraphQL queries, mutations, and subscriptions.</p><p>Here’s a brief guide on how to use the CLI:</p><ul><li><strong>Download the code generation CLI tool.</strong> Go to the list of Apollo iOS <a href="https://github.com/apollographql/apollo-ios/releases">releases on GitHub</a> and find the latest release.In the Assets list for each release, you’ll find a pre-built CLI binary called “apollo-ios-cli.tar.gz”. Download and unzip this file, then move the “apollo-ios-cli” binary file into the root directory of your project.</li><li><strong>Initialize the code generation CLI.</strong> Open a terminal window at the root folder of your project, and run the following command:</li></ul><blockquote><em>./apollo-ios-cli init — schema-name [SchemaName] — module-type embeddedInTarget — target-name [TargetName]</em></blockquote><p>Be sure to replace “[SchemaName]” with the namespace used to scope the generated schema types, and “[TargetName]” with the name of your iOS app as set in your Xcode project. This will create a new configuration file, “Apollo-codegen-config.json”, in your root folder.</p><ul><li><strong>Add the schema download method to the configuration file.</strong> You’ll need to include the “schemaDownloadConfiguration” dictionary in the config file and specify the URL of your schema, which is the Booster GraphQL endpoint:</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/585/1*Yli5JXBkvu-I9G3KBdl4zw.png" /><figcaption>Check other fields too. <a href="https://github.com/theam/livequestions-iOS/blob/main/LiveQuestions/apollo-codegen-config.json">Reference</a></figcaption></figure><ul><li><strong>Create GraphQL files with your queries, mutations, and subscriptions. </strong>These are the requests your app will make to the backend. The Apollo code generation tool will look for these files with the .graphql file extension to create the Swift API code.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/568/1*Ejb3XqSoSMarOw5Zm_lJOA.png" /><figcaption><a href="https://github.com/theam/livequestions-iOS/blob/main/LiveQuestions/graphql/Queries/GetTopic.graphql">Reference</a></figcaption></figure><p>The public interface of a Booster application consists of Commands and ReadModels. In GraphQL terms,<strong> you use mutations for Booster Commands, and queries and subscriptions for ReadModels.</strong></p><p>To see examples of <a href="https://github.com/theam/livequestions-iOS/tree/main/LiveQuestions/graphql/Queries">queries</a>, <a href="https://github.com/theam/livequestions-iOS/tree/main/LiveQuestions/graphql/Mutation">mutations</a>, and <a href="https://github.com/theam/livequestions-iOS/tree/main/LiveQuestions/graphql/Subscription">subscriptions</a> in action, you can check the iOS project. You’ll also find examples of how to <strong>filter</strong> ReadModels.</p><ul><li><strong>Run the Apollo Code Generation tool.</strong> Execute this command in the terminal. It will download your schema and generate the Swift code for the types defined in it.</li></ul><blockquote><strong>./apollo-ios-cli generate -f</strong></blockquote><ul><li><strong>Import the generated files to your Xcode project. </strong>Drag the updated “graphql” folder into your project (make sure to remove the reference first if you’re re-adding the folder). You should be able to compile your project and make successful GraphQL calls!</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*e5HQdpTCELVvsPAUX86lww.gif" /></figure><p><strong>It’s crucial to re-generate the files whenever you make changes to your Booster schema by adding or removing new Commands or ReadModels, or by adding new GraphQL files to your iOS project. This ensures that the frontend and backend are in sync and can communicate effectively.</strong></p><h4>3. Set up the Apollo client</h4><p>On this project, we needed to execute GraphQL queries and mutations and receive real-time updates via web socket using subscriptions. This way, we can update our UI instantly with any change to our read models. Additionally, we wanted to have an in-memory normalized cache to avoid making unnecessary queries.</p><p>Based on those requirements, here is how you could set up the Apollo Client in <a href="https://github.com/theam/livequestions-iOS/blob/main/LiveQuestions/LiveQuestions/Core/Network/NetworkClient.swift">NetworkClient.swift</a>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1001/1*usCUiC1c0E-3f618kwqYZw.png" /><figcaption><a href="https://github.com/theam/livequestions-iOS/blob/main/LiveQuestions/LiveQuestions/Core/Network/NetworkClient.swift">Reference</a></figcaption></figure><p>If you want to learn more details about Apollo configurations, you can check the <a href="https://www.apollographql.com/docs/ios/networking/client-creation">official documentation</a>.</p><p>The custom <em>NetworkInterceptorProvider</em> class created in step #2 can be found <a href="https://github.com/theam/livequestions-iOS/blob/main/LiveQuestions/LiveQuestions/Core/Network/NetworkInterceptorProvider.swift">here</a>. Depending on your application’s requirements, you may choose to implement a custom network transport or use Apollo’s <em>DefaultInterceptorProvider</em>. In this app, we needed to restrict access to Booster’s data to only authorized users, so we implemented a <a href="https://github.com/theam/livequestions-iOS/blob/main/LiveQuestions/LiveQuestions/Core/Network/UserManagementInterceptor.swift"><em>UserManagementInterceptor</em></a> that adds the user’s access token to the authorization header in each request. However, if your application has different security needs, you may not need to create a custom <em>NetworkInterceptorProvider</em> class.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*rf3lQ3KQZAdxHxrk-tu1kw.gif" /><figcaption>We are ready to execute those GraphQL operations!</figcaption></figure><h4>4. Execute a Query</h4><p>For example, if we try to use the <em>GetTopic</em> query to fetch a topic by id, we could do the following:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/815/1*S6ZiGyxEIqLGudBGJYPNew.png" /><figcaption>You can see more examples of this, for instance, in <a href="https://github.com/theam/livequestions-iOS/blob/main/LiveQuestions/LiveQuestions/Core/Manager/TopicsManager.swift"><em>TopicsManager.swift</em></a></figcaption></figure><p><em>GetTopicQuery</em> matches the query we defined in <a href="https://github.com/theam/livequestions-iOS/blob/main/LiveQuestions/graphql/Queries/GetTopic.graphql"><em>GetTopic.graphql</em></a>. Notice that we are taking advantage of the new <em>async/await</em> pattern supported in Swift. As it is not supported yet on Apollo 1.0 by default, we added an extension! You can check it out <a href="https://github.com/theam/livequestions-iOS/blob/main/LiveQuestions/LiveQuestions/Core/Network/ApolloClient.swift">here</a>.</p><h4>5. Execute a Mutation</h4><p>Remember that mutations are calls to our Booster Commands. The request is similar to the example above:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/643/1*hFGR6jKQv-EZH4uou5Qppg.png" /><figcaption><a href="https://github.com/theam/livequestions-iOS/blob/main/LiveQuestions/LiveQuestions/Core/Manager/TopicsManager.swift">Reference</a></figcaption></figure><h4>6. Subscriptions!</h4><p>Booster provides support for <strong>real-time updates using subscriptions</strong> via WebSocket. We are taking advantage of Swift’s asynchronous sequences for this scenario to receive ReadModels updates.</p><p>In this example, we subscribe to any question update that belongs to a specific topic:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/671/1*8V0LheAXXEZOLUCgaVu95w.png" /><figcaption>Check a complete example <a href="https://github.com/theam/livequestions-iOS/blob/main/LiveQuestions/LiveQuestions/Views/Topic/TopicVM.swift">here</a></figcaption></figure><h3>User authentication with Auth0</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/286/1*HmsKc6mTEPj1h8G2kGXxZA.gif" /><figcaption>Access denied</figcaption></figure><p>In our project, only authorized users are allowed to access and interact with the Booster backend. To ensure secure access, <strong>Booster uses the OAuth 2.0 protocol for authentication.</strong> This protocol involves the use of JSON Web Tokens (JWT) to identify and authorize users. These JWT tokens, also known as <strong>access tokens</strong>, are issued by an authentication provider such as <a href="https://auth0.com/"><strong>Auth0</strong></a>, which we are using in this project. Other popular providers that support OAuth 2.0 include Firebase and others.</p><p>You can create a free account with Auth0 for your experiments. In our <a href="https://medium.com/the-theam-journey/build-scalable-low-code-backends-with-booster-a32b9386dd27">article</a> on configuring the Booster backend, we provide detailed instructions on how to set up <strong>user roles and custom claims in the Auth0 token, which Booster uses to authorize operations.</strong> For the iOS counterpart, you just need to follow these steps:</p><ul><li>Create a new <strong>native application</strong> under Applications in your Auth0 account. Then, follow the<a href="https://auth0.com/docs/quickstart/native/ios-swift/interactive"> official steps</a> to configure the client and obtain the <em>Auth0.plist</em> file for your project. It’s important to note that we have a <strong>Build Script Phase </strong>called “Auth0 Plist Selection” in our Xcode project, under the LiveQuestions target. This script selects the appropriate <em>Auth0.plist</em> file based on the type of build (development or release). If you only have one environment, you can place the same <em>plist</em> in both folders, or simply remove the script and use a single <em>plist</em> file.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/226/1*Ca9eQhLwBCS9jFh2ajbocQ.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/894/1*kycvVQEx8tgjx1kLm7aAVA.png" /><figcaption>Build Script Phase for the Auth0.plist selection</figcaption></figure><ul><li>In <a href="https://github.com/theam/livequestions-iOS/blob/main/LiveQuestions/LiveQuestions/Core/Network/AuthService.swift"><em>AuthService.swift</em></a>, you can see how we have implemented easy sign in and sign out functionality using the Auth0 framework. <strong>It is crucial that you set the audience parameter when signing in</strong>, as a missing or incorrect value can result in an incomplete or malformed token. You can use a tool like <a href="https://jwt.io/">jwt.io</a> to check the contents of JWT tokens.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/624/1*ceQjJxn60KZ6lu0w6lR-7A.png" /></figure><p><strong>The audience parameter refers to the identifier of the custom Auth0 API that you will create for your backend.</strong> Don’t worry if you’re not sure what this means — we provide a detailed explanation of this step in the authentication section of our <a href="https://medium.com/the-theam-journey/build-scalable-low-code-backends-with-booster-a32b9386dd27">backend article</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/729/1*-iKigPcKmGLDet19NPNgtA.png" /></figure><h3>Environment Configuration</h3><p>Whenever you deploy your Booster development or production environments, you’ll see the <strong>backend’s endpoints URLs </strong>printed in the console. Populate the <a href="https://github.com/theam/livequestions-iOS/blob/main/LiveQuestions/LiveQuestions/Core/Network/EnvironmentConfiguration.swift">EnvironmentConfiguration.swift</a> file with these URLs:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/967/1*1JItGSXEhocMGdpDUO8YoA.png" /></figure><p>And that’s it! You can now easily interact with your Booster backend from iOS. You can find more details about this app and other Booster use cases by exploring the iOS code on Github.</p><h3>Conclusion</h3><p>By using Booster, it is possible to create an <strong>enterprise-grade, scalable application without needing extensive expertise in cloud technologies or event-sourcing.</strong> We found the reactive nature of Booster to be very intuitive and effective in boosting productivity, and we truly believe it has great potential as a solution for building modern, feature-rich mobile apps.</p><p>Booster enables mobile engineers to quickly <strong>become full-stack developers</strong> and manage the backend of their application, making them more versatile and efficient.</p><p><strong>Booster is constantly improving. The team is working on new features that will make our lives even easier in the near future.</strong> For instance, they are developing a native authentication solution, the ability to delete events and data permanently (currently only logical deletions are possible), and simpler storage options for file uploads. Stay tuned for updates!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/478/1*Qux8ptXAVqKpaSFk_1A2xg.gif" /></figure><p>If you have any questions or suggestions, don’t hesitate to reach out to us on <a href="https://discord.gg/bDY8MKx"><strong>Discord</strong></a>!</p><p><em>This article was co-authored by </em><a href="https://medium.com/u/fde5117cf177"><em>Damien Vieira</em></a><em> and </em><a href="https://medium.com/u/9264cd49404b"><em>Juan Sagasti</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f2eda6463c40" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-theam-journey/from-ios-dev-to-full-stack-in-no-time-with-booster-f2eda6463c40">From iOS Dev to full-stack in no time with Booster 🚀</a> was originally published in <a href="https://medium.com/the-theam-journey">The Agile Monkeys’ Journey</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Making and escalating decisions as a distributed team]]></title>
            <link>https://medium.com/the-theam-journey/making-and-escalating-decisions-as-a-distributed-team-762e6769db68?source=rss----f90e0a497750---4</link>
            <guid isPermaLink="false">https://medium.com/p/762e6769db68</guid>
            <category><![CDATA[distributed-teams]]></category>
            <category><![CDATA[remote-working]]></category>
            <category><![CDATA[decision-making]]></category>
            <category><![CDATA[leadership]]></category>
            <dc:creator><![CDATA[Javier Toledo]]></dc:creator>
            <pubDate>Mon, 01 Mar 2021 20:47:45 GMT</pubDate>
            <atom:updated>2021-03-01T20:48:22.044Z</atom:updated>
            <content:encoded><![CDATA[<h4>Learn to differentiate between one-way and two-way doors.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tZlHpYK8sKvpS3Rjn7ajGg.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@randomlies?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Ashim D’Silva</a> on <a href="https://unsplash.com/s/photos/wrong-door?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>As a distributed and manager-lesser team, we want to make sure that each of us has the autonomy to make decisions and execute them without needing to ask the <strong><em>boss™</em></strong> for permission.</p><blockquote>Read <strong><em>boss™</em></strong> here as a manager, lead engineer, VP, CEO, CTO, the Oracle of Apollo at Delphi, $DEITY, your cat, a couple of dice, flipping a coin, or any other authority figure of any kind.</blockquote><p>But this is easier to tell than to put into practice. Some decisions should be taken with extra care and involve other team members and <strong><em>bosses™</em></strong> to ensure that they match the overall project and company strategy.</p><p>It’s hard, especially for the less experienced people, to differentiate when they can just execute an idea or escalate it. Lack of confidence can lead you to become too conservative and end up asking your <strong><em>boss™</em></strong> about the smallest decisions, introducing an extra overhead that will slow things down. On the contrary, if you lean towards the other side and act in a lone-ranger-reckless way, you can become a potential threat to your project’s continuity or even your company.</p><p>Jeff Bezos coined the terms “One-way” and “Two-way” doors in his<a href="https://www.sec.gov/Archives/edgar/data/1018724/000119312516530910/d168744dex991.htm"> AMZN 2015 Letter to shareholders</a>. He was explaining that to make Amazon become an “invention machine,” they would need to avoid “one-size-fits-all” (conventional) decision making and learn to differentiate between two kinds of decisions:</p><ul><li><strong>One-way doors</strong>: decisions that are consequential and nearly irreversible; should be made methodically, carefully, slowly, with great deliberation and consultation.</li><li><strong>Two-way doors</strong>: decisions that are changeable and reversible; should be made quickly by high judgment individuals or small groups. If you’ve made a suboptimal decision, you can reopen the door and go back through.</li></ul><p>It’s easier to decide if you should escalate a decision by thinking about whether it’s a one-way or a two-way door. If you can undo an action with no consequences, it’s better to execute it. Otherwise, it’s better to make sure you’re doing the right thing and check with your team members and leaders.</p><p>Most decisions are two-way doors, so following this simple framework will make your team faster and more confident.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=762e6769db68" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-theam-journey/making-and-escalating-decisions-as-a-distributed-team-762e6769db68">Making and escalating decisions as a distributed team</a> was originally published in <a href="https://medium.com/the-theam-journey">The Agile Monkeys’ Journey</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Mayday Messaging is the first app using Booster]]></title>
            <link>https://medium.com/the-theam-journey/mayday-messaging-is-the-first-app-using-booster-d2d8fd28803b?source=rss----f90e0a497750---4</link>
            <guid isPermaLink="false">https://medium.com/p/d2d8fd28803b</guid>
            <category><![CDATA[firebase]]></category>
            <category><![CDATA[cloud-computing]]></category>
            <category><![CDATA[serverless]]></category>
            <category><![CDATA[event-sourcing]]></category>
            <category><![CDATA[app-development]]></category>
            <dc:creator><![CDATA[Juan Sagasti]]></dc:creator>
            <pubDate>Mon, 01 Feb 2021 17:49:46 GMT</pubDate>
            <atom:updated>2022-10-04T16:39:09.387Z</atom:updated>
            <content:encoded><![CDATA[<p>At The Agile Monkeys we have some very interesting initiatives and projects, two of which are <a href="https://booster.cloud/"><strong>Booster</strong></a> and <a href="https://www.maydaymessaging.com/"><strong>Mayday</strong></a>. Both projects share the philosophy of simplifying and helping you spend time on what matters.</p><p><strong>Things that matter</strong></p><p><a href="https://booster.cloud/"><strong>Booster</strong></a> is a highly innovative open-source framework for backend development with <strong>Event-Sourcing</strong> architecture that allows developers to focus on what really matters: the <strong>business logic</strong> that makes your application unique. Its high-level abstractions save you from dealing with the necessary serverless infrastructure and it deploys all the necessary resources for you on AWS (more providers coming soon). You don’t have to work directly with these resources at a low level (databases, connections, functions…) and it establishes a well-defined framework that is easy to understand and maintain through <em>Commands</em>, <em>Events</em>, <em>Entities</em> and <em>Read Models</em>. All this with an expressive and secure language like <em>TypeScript</em>.</p><p>Booster is like a serverless Ruby On Rails! The learning curve is simple: you no longer need to be an expert in cloud tools to be productive!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*UDA340tCzPJiaP1a" /></figure><p>In addition,<a href="https://www.maydaymessaging.com/"> <strong>Mayday</strong></a> is a free messaging app for iOS and Android that aims to be an <strong>exclusive communication channel</strong> for sending and receiving <strong>important or urgent messages</strong> while respecting your privacy and security. This means you can silence the chaos of other notifications that we are subjected to on a daily basis and that steal our attention so that you can focus on the important things in your life. Its philosophy and functionality are very different.If you want to learn more about it, check out this<a href="https://medium.com/the-theam-journey/mayday-mayday-acb333caf0f5"> <strong>article</strong></a> about the app or its<a href="https://www.maydaymessaging.com/"> <strong>official</strong></a><strong> website.</strong></p><p>You can download it now for<a href="https://apps.apple.com/app/id1509528878"> <strong>iOS</strong></a> and<a href="https://play.google.com/store/apps/details?id=com.theagilemonkeys.mayday"> <strong>Android</strong></a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/0*A5Cmsc47ePxD5YD1" /></figure><p><strong>From Firebase to Booster </strong>🚀</p><p>For the first beta version of Mayday we used Firebase’s mobile SDKs and Cloud Functions in order to create a working prototype that would validate certain hypotheses as soon as possible. Firebase is a fantastic platform that saves a lot of work in many aspects, but as the backend code became more complex and we lost some performance, we decided to migrate to a more mature and versatile platform like AWS. Booster made that task a lot easier for us:</p><ul><li><strong>Applications built with Booster are very fast</strong> as they benefit from the maturity, scaling, performance and potential of AWS.</li><li>By building your business logic using a very high-level abstraction through a series of well-defined and interconnected components (Commands, Events, Entities and Read Models), the <em>codebase</em> becomes convenient, predictable, expressive, secure (also thanks to TypeScript) and ultimately easy to understand and maintain; key aspects for any development team. Any programmer who joins your project can <strong>start being productive in a very short time</strong>, even if they have no previous serverless experience.</li><li><strong>We completely forget about infrastructure configuration</strong>, which usually requires dealing with YAML files or the AWS console.</li><li>The Booster team is very open and quick to add new functionality to the framework. They are always accessible on their <a href="https://discord.com/invite/bDY8MKx">Discord server</a>, and being <strong>open-source</strong> you can easily modify and extend the framework yourself and adapt it to your needs if necessary. Furthermore, it supports a <strong>system of plug-ins</strong> (<em>Rockets</em>) that allow you to expand functionality without much effort.</li><li>The creation of synergies and feedback between both of the company’s projects was another of our objectives. This allowed us to accelerate the development of Booster, which now supports functionality as a <strong>JWT token-based generic authentication system, time-scheduled commands, Read Model deletion…</strong></li><li>This Booster authentication system allowed us to continue to maintain Firebase for user login and save time. Firebase is still in charge of obtaining and renewing the token which is then used by Booster for all its operations. But Booster’s token system is generic and we could use any authentication provider that uses JWT tokens (Auth0, for example).</li><li>The <strong>GraphQL API</strong> that Booster exposes to apps makes it possible to deal with data in a very convenient way and to build real-time and reactive applications, such as Mayday’s mobile apps. Subscriptions are very easy to create and Mayday uses them, among other things, to keep the Mayday list updated in real time.</li><li><strong><em>Scheduled Commands</em></strong> allowed us to easily meet one of Mayday’s key requirements: deleting Read Models from Maydays that were resolved after 24 hours.</li><li>We have created a very fast contact detection system between the apps and Booster that checks from time to time if any of your contacts are already in Mayday. All this <strong>without ever storing</strong> the user’s address book on the server. <strong>Privacy</strong> is another key point.</li></ul><p>Thanks to all this, Mayday has been able to become the first <strong>production</strong> application to use Booster. The team is still working on new features for the framework, as well as on growing the Booster ecosystem with new applications and services.</p><p>Cloud application development has become very intimidating and it has a very complex learning curve. Booster was born during our team’s process of learning about the Serverless paradigm, which<a href="https://acloudguru.com/blog/engineering/whats-the-friction-with-serverless?utm_source=medium_blog&amp;utm_medium=redirect&amp;utm_campaign=medium_blog"> faced a number of frictions related to the learning curve of the Cloud world</a>.And it is an important step in that direction, proposing an event-driven and reactive future without gaining in complexity thanks to a higher level of abstraction.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d2d8fd28803b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/the-theam-journey/mayday-messaging-is-the-first-app-using-booster-d2d8fd28803b">Mayday Messaging is the first app using Booster</a> was originally published in <a href="https://medium.com/the-theam-journey">The Agile Monkeys’ Journey</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>