<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: S. Amir Mohammad Najafi</title>
    <description>The latest articles on DEV Community by S. Amir Mohammad Najafi (@njfamirm).</description>
    <link>https://dev.to/njfamirm</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F722917%2F8e297ad2-ba95-47e6-b610-b045196e6abe.jpeg</url>
      <title>DEV Community: S. Amir Mohammad Najafi</title>
      <link>https://dev.to/njfamirm</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/njfamirm"/>
    <language>en</language>
    <item>
      <title>AI Brain vs. Human Mind: A Guide to How LLMs Really Work</title>
      <dc:creator>S. Amir Mohammad Najafi</dc:creator>
      <pubDate>Thu, 10 Jul 2025 20:11:15 +0000</pubDate>
      <link>https://dev.to/njfamirm/ai-brain-vs-human-mind-a-guide-to-how-llms-really-work-5bb2</link>
      <guid>https://dev.to/njfamirm/ai-brain-vs-human-mind-a-guide-to-how-llms-really-work-5bb2</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frrpy9huajzm5qr04w7n0.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frrpy9huajzm5qr04w7n0.jpeg" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Have you ever wondered if the AI you’re chatting with &lt;em&gt;thinks&lt;/em&gt; like you do? We see them producing poems, writing code, and answering complex questions, and it’s easy to assume their internal world is a lot like ours. As it turns out, the way a Large Language Model (LLM) “thinks” is fundamentally different from a human mind.&lt;/p&gt;

&lt;p&gt;This guide will take you on a journey into the core differences between human and AI cognition. We’ll explore six key areas where our paths diverge, breaking down complex processes into simple, digestible explanations. By the end, you’ll have a much clearer mental model for what’s happening under the hood of an LLM.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Learning: Lived Experience vs. Pure Mathematics
&lt;/h3&gt;

&lt;p&gt;The way we absorb information is the foundation of our intelligence. Both you and an AI learn, but the process couldn’t be more different.&lt;/p&gt;

&lt;h4&gt;
  
  
  How You Learn 🧠
&lt;/h4&gt;

&lt;p&gt;Your brain is incredibly dynamic. It constantly rewires itself through a process called &lt;a href="https://www.simplypsychology.org/brain-plasticity.html" rel="noopener noreferrer"&gt;&lt;strong&gt;neuroplasticity&lt;/strong&gt;&lt;/a&gt;. Think of your brain as a dense forest. Every time you learn something new-like riding a bike or memorizing a new command-you forge a new path. The more you use that information, the wider and clearer that path becomes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Neuroplasticity&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;is the brain’s ability to be easily shaped or molded. It occurs due to learning, experience, and memory formation. New experiences cause new neural pathways to strengthen, while pathways used infrequently become weak and eventually die off in a process called synaptic pruning.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is why you can learn a powerful lesson from a single experience, like touching a hot stove once, and remember it for a lifetime. Your brain physically changes to store that memory. It’s an ongoing, adaptive process that happens with every new interaction with the world.&lt;/p&gt;

&lt;h4&gt;
  
  
  How AI Learns 🤖
&lt;/h4&gt;

&lt;p&gt;An AI, like an LLM, learns through a much more mathematical process during a distinct “training” phase. It’s fed a colossal amount of text and data, and its learning happens through an algorithm called &lt;a href="https://www.ibm.com/think/topics/backpropagation" rel="noopener noreferrer"&gt;&lt;strong&gt;backpropagation&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Imagine the AI is taking a giant, multiple-choice test with billions of questions (e.g., “what word comes after ‘the cat sat on the…’?”). Initially, it guesses randomly. When it gets the answer (“mat”), it’s told how wrong its other guesses were. Backpropagation is the process of going backward and adjusting millions of internal “knobs,” or &lt;strong&gt;weights&lt;/strong&gt; , ever so slightly, so the next time it’s a little less wrong. Repeat this millions of times, and the AI becomes incredibly good at predicting the next word in a sequence.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.superannotate.com/blog/llm-pruning-distillation-minitron-approach#:~:text=LLM%20pruning%20is%20the%20process,without%20greatly%20affecting%20its%20performance." rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;em&gt;LLM Pruning&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;&lt;em&gt;: Similar to the brain’s synaptic pruning, LLM pruning is a process that simplifies a large model by selectively removing less important parts. This makes the model smaller and faster without significantly hurting its performance.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Unlike you, an LLM’s core knowledge is “frozen” after its training. It isn’t continuously learning from each new, individual conversation it has.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Processing: Weaving Meaning vs. Calculating Probability
&lt;/h3&gt;

&lt;p&gt;Once knowledge is acquired, how is it used in the moment? Here, we see another fundamental split between interpreting meaning and performing math.&lt;/p&gt;

&lt;h4&gt;
  
  
  How You Process Information 🧠
&lt;/h4&gt;

&lt;p&gt;Your brain is a master of &lt;a href="https://www.verywellmind.com/what-is-parallel-processing-in-psychology-5195332" rel="noopener noreferrer"&gt;&lt;strong&gt;parallel processing&lt;/strong&gt;&lt;/a&gt;. Billions of your neurons can fire simultaneously, allowing you to handle multiple streams of information at once. When you read the word “apple,” you don’t just see letters. You might instantly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Picture a red or green fruit.&lt;/li&gt;
&lt;li&gt;Remember its taste and texture.&lt;/li&gt;
&lt;li&gt;Think of Apple the company.&lt;/li&gt;
&lt;li&gt;Recall the proverb “an apple a day…”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your brain connects this single word to a vast, interconnected web of meaning, context, and memories almost instantly.&lt;/p&gt;

&lt;h4&gt;
  
  
  How AI Processes Information 🤖
&lt;/h4&gt;

&lt;p&gt;An AI processes text in a much more linear, or sequential, fashion. It uses a method called &lt;a href="https://www.grammarly.com/blog/ai/what-is-tokenization/" rel="noopener noreferrer"&gt;&lt;strong&gt;tokenization&lt;/strong&gt;&lt;/a&gt; to break down a sentence into pieces called &lt;strong&gt;tokens&lt;/strong&gt; , which can be words or parts of words.&lt;/p&gt;

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

&lt;p&gt;For an AI, “apple” is just a token. Based on its training, this token has a high mathematical probability of being associated with other tokens like “pie,” “tree,” or “iPhone.” To figure out which words are most relevant in a given sentence, it uses a powerful mechanism called &lt;a href="https://metadesignsolutions.com/mastering-the-attention-concept-in-llm-unlocking-the-core-of-modern-ai/" rel="noopener noreferrer"&gt;&lt;strong&gt;“attention.”&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Attention&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;allows a model to weigh the importance of different words (tokens) in an input sequence when generating an output. This helps the model better understand context by focusing on the most relevant parts of the text.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is an incredibly sophisticated form of pattern matching, but it lacks the rich, multi-sensory understanding that you have.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Memory: A Vast Library vs. A Temporary Whiteboard
&lt;/h3&gt;

&lt;p&gt;Our ability to store and recall information is crucial. Here again, our approaches are worlds apart.&lt;/p&gt;

&lt;h4&gt;
  
  
  Your Memory System 🧠
&lt;/h4&gt;

&lt;p&gt;Human memory isn’t a single thing. Psychologists often refer to the &lt;a href="https://www.simplypsychology.org/multi-store.html" rel="noopener noreferrer"&gt;&lt;strong&gt;multi-store model of memory&lt;/strong&gt;&lt;/a&gt;, which includes distinct systems working together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sensory Memory:&lt;/strong&gt; A fleeting snapshot (less than 2 seconds) of what you just saw or heard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Working Memory:&lt;/strong&gt; Your mental “scratchpad.” It holds what you’re actively thinking about (around 7 items for about 15–30 seconds).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Long-Term Memory:&lt;/strong&gt; Your vast, seemingly limitless storage for facts, experiences, and skills, which can last a lifetime.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Critically, your memory is &lt;a href="https://en.wikipedia.org/wiki/Associative_memory_(psychology)%3E" rel="noopener noreferrer"&gt;&lt;strong&gt;associative&lt;/strong&gt;&lt;/a&gt;. A smell can instantly trigger a childhood memory, or a song can transport you back to a specific moment. You learn and remember the relationships between unrelated items.&lt;/p&gt;

&lt;h4&gt;
  
  
  AI’s Memory System 🤖
&lt;/h4&gt;

&lt;p&gt;An AI’s memory structure is much simpler. You can think of it in two main parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Long-Term Memory:&lt;/strong&gt; This is the knowledge baked into its weights during training. It’s vast but fixed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Working Memory:&lt;/strong&gt; For an LLM, this is its &lt;a href="https://www.ibm.com/think/topics/context-window" rel="noopener noreferrer"&gt;&lt;strong&gt;context window&lt;/strong&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of the context window as a whiteboard. It’s the space where your current conversation is written down. The AI can “see” everything on that whiteboard to inform its next response. However, this whiteboard has a fixed size. Once the conversation gets too long, the earliest parts get erased. The AI literally forgets what you talked about at the beginning of the conversation.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Reasoning: Applying Logic vs. Predicting Patterns
&lt;/h3&gt;

&lt;p&gt;Are you a purely logical being? Is the AI truly reasoning with you? Let’s look at the difference between finding an answer and predicting what an answer should look like.&lt;/p&gt;

&lt;h4&gt;
  
  
  How You Reason 🧠
&lt;/h4&gt;

&lt;p&gt;Nobel prize-winning psychologist &lt;a href="https://en.wikipedia.org/wiki/Daniel_Kahneman" rel="noopener noreferrer"&gt;&lt;strong&gt;Daniel Kahneman&lt;/strong&gt;&lt;/a&gt; described our thinking as a tale of &lt;a href="https://thedecisionlab.com/reference-guide/philosophy/system-1-and-system-2-thinking" rel="noopener noreferrer"&gt;two systems&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;System 1&lt;/strong&gt; is fast, intuitive, and automatic. It’s your gut reaction, like recognizing a face or answering “2+2”.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;System 2&lt;/strong&gt; is slow, deliberate, and conscious. It’s the logical reasoning you use to solve a complex math problem or weigh the pros and cons of a big decision.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you reason, you are consciously engaging System 2, working through a problem step-by-step and applying rules of logic to arrive at a conclusion.&lt;/p&gt;

&lt;h4&gt;
  
  
  How AI “Reasons” 🤖
&lt;/h4&gt;

&lt;p&gt;An LLM is trained on the &lt;em&gt;output&lt;/em&gt; of human System 2 thinking-all the logical, well-structured text on the internet. It has learned what reasoning &lt;em&gt;looks like&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;When you ask an AI to solve a problem, it isn’t logically thinking it through like you do. Instead, it’s generating a sequence of tokens that is statistically the most plausible “reasoning-like” text to follow your prompt. This is why it can sometimes fail at very simple logic puzzles that a child could solve. It doesn’t inherently grasp the &lt;em&gt;rules&lt;/em&gt; of logic, only the textual patterns associated with it.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  5. Errors: Filling Gaps vs. Mathematical Miscues
&lt;/h3&gt;

&lt;p&gt;Both humans and AI can make things up. But the reasons &lt;em&gt;why&lt;/em&gt; they do it reveal a key difference in their nature.&lt;/p&gt;

&lt;h4&gt;
  
  
  Human Error: Confabulation 🧠
&lt;/h4&gt;

&lt;p&gt;When humans create false memories, it’s often a phenomenon called &lt;a href="https://en.wikipedia.org/wiki/Confabulation" rel="noopener noreferrer"&gt;&lt;strong&gt;confabulation&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Confabulation&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;is a memory error involving the production of fabricated, distorted, or misinterpreted memories about oneself or the world, without the conscious intention to deceive.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This isn’t intentional lying. It’s the brain’s good-faith attempt to fill in missing gaps in a memory to create a complete and coherent story. The person genuinely believes their fabricated memory is true. It’s a bug in our memory retrieval system.&lt;/p&gt;

&lt;h4&gt;
  
  
  AI Error: Hallucination 🤖
&lt;/h4&gt;

&lt;p&gt;When an AI makes something up, it’s called a &lt;strong&gt;hallucination&lt;/strong&gt;. (Though some argue &lt;a href="https://www.psychologytoday.com/us/blog/theory-of-knowledge/202403/chatbots-do-not-hallucinate-they-confabulate" rel="noopener noreferrer"&gt;&lt;strong&gt;confabulation&lt;/strong&gt;&lt;/a&gt; is a better term).&lt;/p&gt;

&lt;p&gt;This happens when the model, in its mathematical quest to find the most probable next token, generates text that is nonsensical or factually incorrect. It isn’t trying to fill a memory gap; it’s simply following its programming, which can sometimes lead it to produce very confident-sounding falsehoods. It’s a bug in its text-generation system.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Embodiment: A Lived Reality vs. A Read Reality
&lt;/h3&gt;

&lt;p&gt;Finally, perhaps the biggest difference is our connection to the physical world.&lt;/p&gt;

&lt;h4&gt;
  
  
  Your Embodied Mind 🧠
&lt;/h4&gt;

&lt;p&gt;You are an embodied being. Your thoughts and understanding are deeply shaped by the fact that you have a body and interact with the physical world. This is known as &lt;a href="https://en.wikipedia.org/wiki/Embodied_cognition" rel="noopener noreferrer"&gt;&lt;strong&gt;embodied cognition&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Your understanding of “heavy” comes from the experience of lifting things. Your understanding of “hot” comes from feeling warmth. This direct, first-hand experience gives you a foundation of common sense that is difficult to articulate but easy to use.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Disembodied AI 🤖
&lt;/h4&gt;

&lt;p&gt;An LLM is completely disembodied. It exists only as software on a server. It has never touched an object, felt the sun, or tasted food. Its entire knowledge of the physical world is second-hand, learned by reading descriptions written by humans who have.&lt;/p&gt;

&lt;p&gt;This is why, despite its vast repository of facts, an AI can lack the most basic common sense about how the physical world operates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion: Two Intelligences, One Future
&lt;/h3&gt;

&lt;p&gt;Understanding these fundamental differences between human and AI cognition isn’t just academic-it’s the key to unlocking AI’s true potential. When we grasp that an LLM operates through mathematical pattern-matching rather than conscious understanding, we can better appreciate both what it excels at and where it falls short.&lt;/p&gt;

&lt;p&gt;This comparison reveals why AI is extraordinary at tasks like processing vast amounts of information, generating creative content, and recognizing complex patterns across domains. Yet it also explains why AI struggles with common sense, physical reasoning, and tasks that require genuine understanding of lived experience.&lt;/p&gt;

&lt;p&gt;You bring meaning, context, and embodied comprehension to every interaction. AI offers incredible speed, computational power, and access to patterns across human knowledge that no individual could ever master. The real magic happens when we stop asking whether AI thinks like us, and start leveraging these complementary strengths-using AI as a powerful thinking partner while contributing the uniquely human elements of wisdom, judgment, and genuine understanding.&lt;/p&gt;

</description>
      <category>physiology</category>
      <category>ai</category>
      <category>llm</category>
    </item>
    <item>
      <title>From Curiosity to Craftsmanship: My Journey Through Anthropic’s Project Vend</title>
      <dc:creator>S. Amir Mohammad Najafi</dc:creator>
      <pubDate>Tue, 08 Jul 2025 17:36:06 +0000</pubDate>
      <link>https://dev.to/njfamirm/from-curiosity-to-craftsmanship-my-journey-through-anthropics-project-vend-hmf</link>
      <guid>https://dev.to/njfamirm/from-curiosity-to-craftsmanship-my-journey-through-anthropics-project-vend-hmf</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnnghzal4b4mjowmu3l5j.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnnghzal4b4mjowmu3l5j.jpeg" alt="Post cover" width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First off, I really suggest you read Anthropic’s original post if you haven’t already: &lt;a href="https://www.anthropic.com/research/project-vend-1" rel="noopener noreferrer"&gt;&lt;strong&gt;Project Vend: Can Claude run a small shop? (And why does that matter?)&lt;/strong&gt;&lt;/a&gt;. Once you’re done, come on back. My goal here isn’t to critique their work-it was a fascinating research project, not a business plan. Instead, I want to use it as a launchpad for my own thinking, exploring how someone like me might approach building a similar system, focusing on the principles that could make it more robust.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Disclaimer: This is just a personal exploration fueled by a reading and a healthy dose of curiosity. I’m not a specialist in this field. If you have expertise and spot something I’ve misunderstood, please share your thoughts in the comments! I’d be genuinely grateful to learn.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  The Core Idea That Sparked My Curiosity
&lt;/h3&gt;

&lt;p&gt;Anthropic’s “Project Vend” was a fascinating experiment. They gave their AI model, Claude, a set of tools (web search, email, notes) and tasked it with running a small online shop for a month, interacting with customers through Slack. The outcome was a mixed bag. Claude managed to get some things done, but it struggled with profitability, made some logical blunders, and even seemed to have a bit of an “identity crisis,” at times believing it was a real person.&lt;/p&gt;

&lt;p&gt;As I read through the technical details, one thought immediately popped into my head: it seemed like the whole operation was running within a single, very long conversational context. This raised a flag for me, not as a scientist, but as someone who tinkers with this technology. As that conversation history gets longer and longer, wouldn’t the model’s focus and accuracy start to drift?&lt;/p&gt;

&lt;p&gt;This became the central question for my exploration. Let’s break down why this simple setup, perfect for an experiment, could be a real headache in a practical application.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Limits of an Endless Dialogue
&lt;/h3&gt;

&lt;p&gt;When you build an entire system on one continuous chat, you’re bumping up against some of the known limits of today’s language models. It got me thinking about three main challenges.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Finite Context Window
&lt;/h3&gt;

&lt;p&gt;LLMs have a memory limit, which is often called the “context window.” Think of it like a person’s short-term memory. As a conversation grows, older details can get pushed out or become less important. The model might forget a key piece of information from last Tuesday, which could lead to inconsistent or just plain wrong decisions.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Snowball Effect of Errors
&lt;/h3&gt;

&lt;p&gt;Here’s a scary thought: a small mistake early on can become the faulty foundation for everything that follows. If the AI miscalculates its inventory on day one, every future decision about restocking or analyzing sales will be built on that initial error. The mistakes don’t just happen; they compound over time.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Challenge of Finding “Why”
&lt;/h3&gt;

&lt;p&gt;When something inevitably goes wrong, how do you figure out the cause? Trying to perform a root-cause analysis on a massive, unstructured chat log would be a nightmare. It’s like trying to find one specific sentence in a novel that has no chapters. This “black box” problem makes the system incredibly difficult to debug, audit, or improve.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqyjug6jmyta85au3qptn.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqyjug6jmyta85au3qptn.jpeg" alt="A tall, precarious tower of wooden blocks, symbolizing how a small error in an AI system can lead to a catastrophic failure." width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  A Different Path: From Conversation to Architecture
&lt;/h3&gt;

&lt;p&gt;So, if a single, endless chat isn’t the most reliable approach, what’s a better way to think about it? The solution, it seems, is to shift from a &lt;em&gt;conversational&lt;/em&gt; model to an &lt;em&gt;architectural&lt;/em&gt; one.&lt;/p&gt;

&lt;p&gt;Instead of asking the AI to remember everything, we could build a system of distinct, manageable tasks that don’t rely on a long-term memory. It’s like moving from a single brilliant-but-forgetful employee to a well-organized team. Here’s how I imagine it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scheduled Tasks:&lt;/strong&gt; Instead of &lt;em&gt;hoping&lt;/em&gt; the AI remembers to check supplier prices, we could create an automated task. Every morning at 9 AM, it would call the AI with a very specific job: “Analyze these three websites for the best price and save the result here.”&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event-Driven Actions (like reflexes):&lt;/strong&gt; When a customer buys something, that action triggers a specific AI task. For example, “A customer just bought one block of cheddar. Update the inventory count and check if the stock is below our reorder threshold.”&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A Protective Layer (like a supervisor):&lt;/strong&gt; Before the system actually spends money or sends an important email, the proposed action has to pass through a validation layer. This supervisor double-checks the decision against a set of rules. Is the price logical? Is the quantity reasonable? Does this align with our goals?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach feels much more robust, predictable, and transparent. And it turns out, the AI field has a whole vocabulary for these ideas, which is incredibly helpful for learning more.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff68zvjlsbp1pk6olu3n3.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff68zvjlsbp1pk6olu3n3.jpeg" alt="A line of interconnected wooden gears, representing a well-architected AI system where different components work together in a coordinated workflow." width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Keywords for Building Smarter AI: A Learner’s Glossary
&lt;/h3&gt;

&lt;p&gt;If you, like me, are curious about building systems like this, knowing the right search terms is half the battle. Here are the keywords that opened up a world of information for me.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core Concepts &amp;amp; Architecture
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.ibm.com/think/topics/agentic-workflows" rel="noopener noreferrer"&gt;&lt;strong&gt;AI Agent / Autonomous Agent&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;:&lt;/strong&gt; This is the big-picture concept. An AI Agent is a system designed to perceive its environment, make its own decisions, and take actions to achieve a goal. Our theoretical shopkeeper is a perfect example of an AI Agent. IBM has a great &lt;a href="https://www.youtube.com/watch?v=F8NKVhkZZWI" rel="noopener noreferrer"&gt;video explanation&lt;/a&gt; that breaks down this concept clearly.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.ibm.com/think/topics/ai-orchestration" rel="noopener noreferrer"&gt;&lt;strong&gt;AI Orchestration:&lt;/strong&gt;&lt;/a&gt; This is the “scheduled tasks and reflexes” idea. Orchestration is all about coordinating different tools, models, and data sources to carry out a complex workflow. It’s the conductor of the AI symphony, making sure everything happens in the right order. Frameworks like LangChain and LlamaIndex are big names in this space.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.ibm.com/think/topics/agentic-workflows" rel="noopener noreferrer"&gt;&lt;strong&gt;Agentic Workflows:&lt;/strong&gt;&lt;/a&gt; This means designing a process where different specialized agents or tools handle different steps. Instead of one AI doing everything, you might have one agent for analyzing data, another for drafting emails, and a third for validating actions.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.ibm.com/think/topics/multi-agent-systems" rel="noopener noreferrer"&gt;&lt;strong&gt;Multi-Agent System&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;:&lt;/strong&gt; This is the concept of having multiple specialized agents working together, each with its own focus and expertise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State Management:&lt;/strong&gt; In this architectural approach, the system’s “state” (like inventory levels or customer orders) isn’t kept in the AI’s short-term memory. It’s stored safely in an external database. State management is simply the process of how this crucial data is stored, retrieved, and updated reliably.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Execution &amp;amp; Internal Logic
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.ibm.com/think/topics/tool-calling" rel="noopener noreferrer"&gt;&lt;strong&gt;Function Calling / Tool Use&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;:&lt;/strong&gt; This is how modern LLMs connect to the outside world. It’s the ability that lets you give a model a “tool,” like your inventory API or your email client, and allow it to use that tool to get things done. It’s the bridge between the AI’s brain and real-world action.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.amazon.science/blog/how-task-decomposition-and-smaller-llms-can-make-ai-more-affordable" rel="noopener noreferrer"&gt;&lt;strong&gt;Task Decomposition&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;:&lt;/strong&gt; This is the skill of breaking a big, vague goal (like “make more money”) into small, concrete sub-tasks (“1. Check current inventory. 2. Find cheaper suppliers. 3. Analyze competitor prices.”). The AI Orchestrator is often in charge of this.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://research.google/blog/react-synergizing-reasoning-and-acting-in-language-models/" rel="noopener noreferrer"&gt;&lt;strong&gt;ReAct (Reason, Act)&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;:&lt;/strong&gt; A popular mental model for how an agent should operate. The model first &lt;strong&gt;Reasons&lt;/strong&gt; about what it needs to do and which tool it should use, then it &lt;strong&gt;Acts&lt;/strong&gt; by using the tool. It repeats this cycle until the job is done.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://research.google/blog/language-models-perform-reasoning-via-chain-of-thought/" rel="noopener noreferrer"&gt;&lt;strong&gt;CoT (Chain of Thought)&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;:&lt;/strong&gt; This is a technique where the model explains its reasoning step-by-step before taking action. It’s like having the AI talk through its thought process, which can help catch mistakes before they happen.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Safety &amp;amp; Control
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AI Guardrails / Output Filtering:&lt;/strong&gt; This is the “supervisor” or “protective layer” we talked about. Guardrails are rules, filters, or even other AI models that check the primary LLM’s output &lt;em&gt;before&lt;/em&gt; an action is taken. You’ve probably seen this in action when a chatbot starts writing a response, then suddenly clears it and says “I can’t answer this question”-that’s guardrails at work. Leading companies often use more specific terms like “AI Safety,” “AI Alignment,” or “Constitutional AI” when discussing these concepts in their research.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output Parsing and Validation:&lt;/strong&gt; This is a specific type of guardrail. It’s a process that makes sure the model’s output is in the correct format (e.g., proper JSON) and that the data inside makes sense (e.g., you can’t order -5 wheels of cheese).&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.anthropic.com/research/constitutional-ai-harmlessness-from-ai-feedback" rel="noopener noreferrer"&gt;&lt;strong&gt;Constitutional AI:&lt;/strong&gt;&lt;/a&gt; A concept pioneered by Anthropic itself. It involves giving the LLM a core “constitution”-a set of principles it must always follow. It’s like building a moral compass directly into the agent to ensure its behavior stays aligned with its purpose.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Explore These Ideas Further
&lt;/h3&gt;

&lt;p&gt;Want to dive deeper into these AI orchestration and agentic workflow concepts? I’ve created an interactive conversation about these principles using Google’s NotebookLM. You can &lt;a href="https://notebooklm.google.com/notebook/8bf10af5-cfc4-489f-ba9c-818919018bb0" rel="noopener noreferrer"&gt;&lt;strong&gt;chat with an AI about these ideas here&lt;/strong&gt;&lt;/a&gt; — it’s a great way to explore questions, get clarifications, or discuss how these concepts might apply to your own projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion: The Craftsmanship of AI
&lt;/h3&gt;

&lt;p&gt;Exploring the “what-ifs” of Project Vend took me from a simple point of curiosity to a much richer understanding of how these systems can be built. We’re no longer just talking to a chatbot; we’re thinking about designing an &lt;strong&gt;AI Orchestration&lt;/strong&gt; for an &lt;strong&gt;Agentic Workflow&lt;/strong&gt; , using &lt;strong&gt;Function Calling&lt;/strong&gt; to interact with the world, all while being protected by robust &lt;strong&gt;AI Guardrails&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This shift in perspective feels like the heart of modern craftsmanship in technology. It’s about using these incredibly powerful new tools not just to build something that &lt;em&gt;kind of works&lt;/em&gt;, but to build it with care, intention, and foresight. The most exciting question isn’t just “What can AI do?” but “How can we build it with purpose and wisdom?”&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Learning in Progress:&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;This blog post represents my ongoing exploration of AI orchestration and agentic workflows. As I continue to learn and experiment with these concepts, I may update this post with new insights, corrections, or additional resources. Consider this a living document that reflects my evolving understanding of the field.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpn6js9f2kz55a153buer.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpn6js9f2kz55a153buer.jpeg" alt="A perfectly smooth wooden sphere, its grain visible under soft light, symbolizing the elegance and precision of AI craftsmanship." width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://www.njfamirm.ir/en/blog/learn-from-anthropic-project-vend/" rel="noopener noreferrer"&gt;&lt;em&gt;https://www.njfamirm.ir&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>chatbots</category>
    </item>
    <item>
      <title>Mastering Eleventy Folder Structures: From Default Setups to Real-World Best Practices</title>
      <dc:creator>S. Amir Mohammad Najafi</dc:creator>
      <pubDate>Mon, 29 Jan 2024 15:03:36 +0000</pubDate>
      <link>https://dev.to/njfamirm/mastering-eleventy-folder-structures-from-default-setups-to-real-world-best-practices-15ij</link>
      <guid>https://dev.to/njfamirm/mastering-eleventy-folder-structures-from-default-setups-to-real-world-best-practices-15ij</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjcga0etfkpup67tlsacz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjcga0etfkpup67tlsacz.jpg" alt="Post cover" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;Welcome to the exciting world of Eleventy, a powerful and flexible static site generator based on jamstack! Whether you’re a seasoned developer or just starting out, understanding how to effectively organize your Eleventy project is crucial for efficiency and scalability. In this guide, we’ll embark on a journey from the simplicity of Eleventy’s default folder structure to the sophistication of a customized setup tailored for more complex projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;For the complete store, read the&lt;/em&gt;&lt;/strong&gt; &lt;a href="https://www.njfamirm.ir/en/blog/eleventy-folder-structure-guide/" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;em&gt;full article&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;&lt;em&gt;on my blog 🙌🏻. 🙌🏻&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  In-Depth Look at Eleventy’s Basic Setup
&lt;/h3&gt;

&lt;p&gt;Eleventy, known for its simplicity and flexibility, starts users off with a straightforward folder structure. This design is particularly appealing to beginners or those looking to quickly set up a static site without the complexity often associated with such setups. Let’s delve deeper into each component of this default structure:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Input
&lt;/h4&gt;

&lt;p&gt;The input directory is denoted by a dot (.), representing the current directory where the Eleventy command is run. This approach means that all the files and subdirectories within this directory are considered part of your project's source. It simplifies the process by not requiring a specific folder for your source files, allowing Eleventy to work with your project's root directory directly.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Includes
&lt;/h4&gt;

&lt;p&gt;The _includes directory is where Eleventy looks for templating parts - reusable pieces of your templates, like headers, footers, and navigation bars. This feature is crucial for avoiding repetition, as it allows you to maintain consistent elements across various parts of your website easily. By default, Eleventy treats this folder as the go-to place for these template snippets, helping you to organize your project better. this folder where is you can use the include tag to include a template part in another template.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Layouts:
&lt;/h4&gt;

&lt;p&gt;In Eleventy’s default setup, &lt;a href="https://www.11ty.dev/docs/layouts/" rel="noopener noreferrer"&gt;layouts&lt;/a&gt; are often placed in the same _includes directory. Layouts are essentially templates that define the structure of a webpage. By placing layouts in the _includes folder, Eleventy offers a streamlined approach, keeping all template-related files in one location. However, as projects grow, some developers prefer to separate layouts into their own directory for clearer distinction and organization&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Global Data
&lt;/h4&gt;

&lt;p&gt;The _data folder is a powerful feature in Eleventy. It's used for storing &lt;a href="https://www.11ty.dev/docs/data-global/" rel="noopener noreferrer"&gt;global data&lt;/a&gt; files that can be accessed by any template across the site. This could include site metadata, configuration settings, or any other data that needs to be available site-wide. The data in these files can be written in various formats like JSON, JavaScript, or YAML, providing flexibility in how you manage your site's content and settings.&lt;/p&gt;

&lt;h4&gt;
  
  
  5. Output: _site
&lt;/h4&gt;

&lt;p&gt;Finally, the _site directory is the default output location where Eleventy generates the final, built version of your site. After running Eleventy, this folder contains the HTML, CSS, JavaScript, and other assets that make up your website, ready to be deployed to a web server or CDN. This separation of source and output is critical for maintaining a clean workspace, ensuring that your development files are kept separate from the deployable, built site.&lt;/p&gt;

&lt;p&gt;Here’s the visual representation of this structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── _data # Global data files
├── _includes # Template parts and layouts
├── . # Main input directory (root of your project)
└── _site # Output directory for the built website
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Understanding this default structure is key to getting started with Eleventy. It offers a balance of simplicity and organization, making it an ideal starting point for building static websites. As you grow more familiar with Eleventy, you may find ways to customize this structure to better suit the needs of more complex projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementing a Real-World Advanced Folder Structure
&lt;/h3&gt;

&lt;p&gt;In the ever-evolving world of web development, Eleventy projects often outgrow their initial folder structures, revealing the need for a more sophisticated organization as they expand in complexity and size. This progression necessitates a refined approach to effectively handle a growing array of files, diverse content types, and the nuances of complex build processes. Embracing an advanced folder structure, fundamentally grounded in the Separation of Concerns (SoC) principle, becomes critical.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;💡&lt;/em&gt; &lt;strong&gt;&lt;em&gt;Separation of Concerns&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;: This pivotal design principle involves dividing a computer program into distinct sections, each focusing on a unique aspect of the software’s functionality. Applied to web development and particularly Eleventy projects, SoC means organizing files and folders to independently manage each type of file or functionality. This strategic compartmentalization significantly boosts a project’s readability, maintainability, and scalability. For a detailed exploration of SoC,&lt;/em&gt; &lt;a href="https://en.wikipedia.org/wiki/Separation_of_concerns" rel="noopener noreferrer"&gt;&lt;em&gt;Wikipedia&lt;/em&gt;&lt;/a&gt; &lt;em&gt;provides extensive insights.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Crucially, in implementing this structure, remember that the essence lies in the functional separation of the folders rather than their specific names. Folder names can vary widely based on individual preferences or project requirements, underscoring the importance of a tailored approach to folder organization in Eleventy projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Continue reading the&lt;/em&gt;&lt;/strong&gt; &lt;a href="https://www.njfamirm.ir/en/blog/eleventy-folder-structure-guide/" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;em&gt;article&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;&lt;em&gt;on my blog 🙌🏻&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

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

</description>
      <category>eleventy</category>
      <category>staticsitegenerator</category>
      <category>jamstack</category>
      <category>web</category>
    </item>
    <item>
      <title>Separating Commits in Git: A Guide to Streamlining Your Workflow</title>
      <dc:creator>S. Amir Mohammad Najafi</dc:creator>
      <pubDate>Thu, 16 Nov 2023 18:51:29 +0000</pubDate>
      <link>https://dev.to/njfamirm/separating-commits-in-git-a-guide-to-streamlining-your-workflow-17p8</link>
      <guid>https://dev.to/njfamirm/separating-commits-in-git-a-guide-to-streamlining-your-workflow-17p8</guid>
      <description>&lt;p&gt;Hi everyone,&lt;br&gt;&lt;br&gt;
Today I want to speak about a problem that I have in my daily work with Git when using a trunk-based deployment pattern, and how can solve it with some commands.&lt;br&gt;&lt;br&gt;
First, we need to know about trunk-based deployment, then I will present my problem.&lt;/p&gt;

&lt;p&gt;Let's dive in!&lt;/p&gt;
&lt;h2&gt;
  
  
  What is Trunk-based deployment?
&lt;/h2&gt;

&lt;p&gt;TDB, or Trunk-based pattern is a modern way for developers to work together using version control, where each developer divides their work into small batches and merges that work into the trunk at least once a day.&lt;/p&gt;

&lt;p&gt;The key difference between this approach and git-flow workflow is &lt;strong&gt;scope&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
Feature branches typically involve multiple developers and take days or even weeks of work. In contrast, branches in TDB typically last no more than a few hours, with many developers merging their changes into the trunk frequently.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZiZQNgdW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.njfamirm.ir/img/zGTlY55f-1024.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZiZQNgdW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.njfamirm.ir/img/zGTlY55f-1024.jpeg" alt="Trunk-based deployment process explanation." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The above paragraph was taken from the Google Cloud &lt;a href="https://cloud.google.com/architecture/devops/devops-tech-trunk-based-development"&gt;article&lt;/a&gt; about DevOps in trunk-based development, you can refer to this article for more information.&lt;/p&gt;
&lt;h2&gt;
  
  
  Our problem
&lt;/h2&gt;

&lt;p&gt;Sometimes it happens that we want to create a feature that depends on several packages, and generally, we have to do several things together and then create a pull request.&lt;br&gt;&lt;br&gt;
At this time, it will be perfect to easily commit wherever we want, and after finishing the work, we can apply according to the rules of TBD pull request, and all our code can be easily reviewed and merged.&lt;/p&gt;

&lt;p&gt;There are two git commands we need to learn for solving this problem. I'll explain briefly below, but you can skip it if you already know them.&lt;/p&gt;
&lt;h2&gt;
  
  
  Git rebase
&lt;/h2&gt;

&lt;p&gt;Rebasing is the process of moving or combining a sequence of commits to a new base commit. changing the base of your branch from one commit to another making it appear as if you'd created your branch from a different commit. Internally, Git accomplishes this by creating new commits and applying them to the specified base.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--N43egHyF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.njfamirm.ir/img/7SHEHSEc-605.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--N43egHyF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.njfamirm.ir/img/7SHEHSEc-605.jpeg" alt="Git rebase explanation" width="605" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;read more about this command on the &lt;a href="https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase"&gt;Atlassian blog&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Git cherry-pick
&lt;/h2&gt;

&lt;p&gt;Cherry-pick enables arbitrary Git commits to be picked by reference and appended to the current working HEAD. Cherry picking is the act of picking a commit from a branch and applying it to another.&lt;/p&gt;

&lt;p&gt;read more about this command on the &lt;a href="https://www.atlassian.com/git/tutorials/cherry-pick"&gt;Atlassian blog&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;Now that we know about Trunk-based deployment, git rebase, and git cherry-pick commands, we can use them to solve our problem of having multiple commits from multiple packages and features in a single branch.&lt;/p&gt;

&lt;p&gt;Let's say we have a commit history like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aEQBxEBw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.njfamirm.ir/img/X5eOOFw0-2751.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aEQBxEBw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.njfamirm.ir/img/X5eOOFw0-2751.jpeg" alt="screenshot of Github pull request with many commits." width="800" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a bad situation because it makes the review process too long and complicated. We need to separate these commits into multiple branches, one for each feature and package.&lt;/p&gt;

&lt;p&gt;Let's start by separating the first and last commits, which are about the &lt;code&gt;package-1&lt;/code&gt; feature. These two commits only change &lt;strong&gt;a single feature in a single package&lt;/strong&gt; , so they are a good candidate for separation.&lt;/p&gt;

&lt;p&gt;First, create a new branch from the trunk branch, then, we need to copy the hash of these two commits. and we can use the git &lt;code&gt;cherry-pick&lt;/code&gt; command to copy them into a new branch called &lt;code&gt;feat/package-1&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git switch -c feat/package-1 origin/next
git cherry-pick &amp;lt;hash of first commit&amp;gt;
git cherry-pick &amp;lt;hash of second commit&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--su1F8xiw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.njfamirm.ir/img/agPJ44vB-2832.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--su1F8xiw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.njfamirm.ir/img/agPJ44vB-2832.jpeg" alt="Screenshot of terminal use git cherry-pick to separate commit." width="800" height="546"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;if you have a conflict when want to cherry-pick, you must first rebase your branch with a trunk to resolve any conflict, if you still have conflict, that's occurred maybe because you don't commit correctly! you can use rebase to fix the commit issue.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now we have a new branch with new two commits. We can create a pull request for this branch and merge it into the trunk branch.&lt;br&gt;&lt;br&gt;
Once the pull request is approved and merged, we can rebase the first branch with the trunk branch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FOojbrmN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.njfamirm.ir/img/5YnUAp1g-2787.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FOojbrmN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.njfamirm.ir/img/5YnUAp1g-2787.jpeg" alt="Screenshot of terminal use git rebase." width="800" height="505"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will remove the two commits from the first branch and keep our commit history clean, then you must force push the branch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XArMP3do--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.njfamirm.ir/img/lD4QbkgP-2752.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XArMP3do--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.njfamirm.ir/img/lD4QbkgP-2752.jpeg" alt="Screenshot of Github pull request with fewer commits that are removed by git rebase and cherry-pick." width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can use the same process to separate the other commits in our history. This will give us a nice, clean commit history with one commit per feature and package, with a full cover of the trunk-based deployment pattern.&lt;/p&gt;

&lt;p&gt;In the end, I have shared my shell function, used by me daily for separating commits:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gsep () {
  currentBranch=$(git rev-parse --abbrev-ref HEAD) &amp;amp;&amp;amp; \
  git fetch origin &amp;amp;&amp;amp; \
  git switch -c feat/$1 origin/next &amp;amp;&amp;amp; \
  shift &amp;amp;&amp;amp; \
  git cherry-pick $@ &amp;amp;&amp;amp; \
  git push -u &amp;amp;&amp;amp; \
  gh pr create -a @me --base next --fill --web &amp;amp;&amp;amp; \
  git switch $currentBranch;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function takes the name of a feature as its argument and creates a new branch called &lt;code&gt;feat/$1&lt;/code&gt;. It cherry-picks the specified commits into the new branch and creates a pull request for it. then switches back to the original branch.&lt;/p&gt;

&lt;p&gt;I hope this article will help you to have a better experience with git and trunk-based deployment.&lt;br&gt;&lt;br&gt;
Thanks for reading!&lt;/p&gt;

</description>
      <category>git</category>
    </item>
    <item>
      <title>Creating a Searchable Reading List with Strapi CMS Custom API</title>
      <dc:creator>S. Amir Mohammad Najafi</dc:creator>
      <pubDate>Thu, 16 Nov 2023 18:51:29 +0000</pubDate>
      <link>https://dev.to/njfamirm/creating-a-searchable-reading-list-with-strapi-cms-custom-api-cck</link>
      <guid>https://dev.to/njfamirm/creating-a-searchable-reading-list-with-strapi-cms-custom-api-cck</guid>
      <description>&lt;p&gt;Hi everyone!&lt;/p&gt;

&lt;p&gt;As programmers, we are constantly learning and reading articles, blog posts, and documentation. Maybe this is the most important part of &lt;strong&gt;programming lifestyle&lt;/strong&gt;!&lt;br&gt;&lt;br&gt;
Unfortunately, we do not keep those resource anywhere, and even if we keep them on our notes because it is not accessible through searching, we can't access them anymore.&lt;/p&gt;
&lt;h2&gt;
  
  
  Idea
&lt;/h2&gt;

&lt;p&gt;An interesting solution for our problem is a &lt;strong&gt;&lt;code&gt;searchable reading list&lt;/code&gt;&lt;/strong&gt; that's I got this idea from the &lt;a href="https://esif.dev/"&gt;esif.dev&lt;/a&gt; blog.&lt;/p&gt;

&lt;p&gt;At the end, you can setup and maintain a &lt;strong&gt;&lt;code&gt;searchable-reading-list&lt;/code&gt;&lt;/strong&gt; of valuable resources that you encounter during your programming journey!&lt;/p&gt;
&lt;h2&gt;
  
  
  Roadmap
&lt;/h2&gt;

&lt;p&gt;Since we may read several articles in a day and need to put it in the reading-list, We needed to have a CMS, so that I could put the links there very quickly and easily and not think about anything else.&lt;/p&gt;

&lt;p&gt;Also, our reading list page should work with the API and not need to be built statically like other pages with &lt;a href="https://www.11ty.dev/"&gt;Eleventy&lt;/a&gt;. So I decided to use &lt;a href="https://strapi.io/"&gt;Strapi&lt;/a&gt; as a beautiful, dynamic, and easy-to-use CMS.&lt;/p&gt;
&lt;h2&gt;
  
  
  Preparing the environment
&lt;/h2&gt;

&lt;p&gt;Before we can start building our reading-list, we need to create a new Strapi project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn create strapi-app reading-list --ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create Content Type
&lt;/h2&gt;

&lt;p&gt;First, we need to create a content-type that we can put our reading-list in, So to create a content type for our reading-list, we can use the Strapi CLI and run the following command in our project directory. This will generate a new content type with the specified name and fields.&lt;/p&gt;

&lt;p&gt;This command will create a new content type called reading-list and generate the necessary files and fields to get started building our custom API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn strapi generate

  ? Strapi Generators content-type - Generate a content type for an API
  ? Content type display name Reading List
  ? Content type singular name reading-list
  ? Content type plural name reading-lists
  ? Please choose the model type Collection Type
  ? Use draft and publish? No
  ? Do you want to add attributes? Yes
  ? Name of attribute title
  ? What type of attribute string
  ? Do you want to add another attribute? Yes
  ? Name of attribute url
  ? What type of attribute string
  ? Do you want to add another attribute? Yes
  ? Name of attribute keyword
  ? What type of attribute text
  ? Do you want to add another attribute? Yes
  ? Name of attribute description
  ? What type of attribute richtext
  ? Do you want to add another attribute? Yes
  ? Name of attribute keyword
  ? What type of attribute text
  ? Do you want to add another attribute? No
  ? Where do you want to add this model? Add model to new API
  ? Name of the new API? reading-list
  ? Bootstrap API related files? Yes
  ✔ ++ /api/reading-list/content-types/reading-list/schema.json
  ✔ +- /api/reading-list/content-types/reading-list/schema.json
  ✔ ++ /api/reading-list/controllers/reading-list.ts
  ✔ ++ /api/reading-list/services/reading-list.ts
  ✔ ++ /api/reading-list/routes/reading-list.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a base schema, but we can improve them by adding regex and unique to the url field and also making the title and the url required, this is result of the schema can put under api/reading-list/content-types/reading-list/schema.json:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "kind": "collectionType",
  "collectionName": "reading_lists",
  "info": {
    "singularName": "reading-list",
    "pluralName": "reading-lists",
    "displayName": "Reading List",
    "description": ""
  },
  "options": {
    "draftAndPublish": false
  },
  "attributes": {
    "title": {
      "type": "string",
      "required": true
    },
    "url": {
      "type": "string",
      "regex": "https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_\\+.~#?&amp;amp;//=]*)",
      "required": true,
      "unique": true
    },
    "description": {
      "type": "richtext"
    },
    "keyword": {
      "type": "text",
      "required": false
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fcenTXM6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.njfamirm.ir/img/IzMncCUc-2524.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fcenTXM6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.njfamirm.ir/img/IzMncCUc-2524.jpeg" alt="Screenshot of strapi content type" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Very good, Now we have simple reading list in strapi, let's make them searchable!&lt;/p&gt;

&lt;h2&gt;
  
  
  Search Custom API
&lt;/h2&gt;

&lt;p&gt;In this step we'll use the strapi-generate command again to creates a custom API pure file structure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn strapi generate

  ? Strapi Generators api - Generate a basic API
  ? API name reading-list-search
  ? Is this API for a plugin? No
  ✔ ++ /api/reading-list-search/routes/reading-list-search.ts
  ✔ ++ /api/reading-list-search/controllers/reading-list-search.ts
  ✔ ++ /api/reading-list-search/services/reading-list-search.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we need to fill the files with the correct codes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Service
&lt;/h2&gt;

&lt;p&gt;Services are a set of reusable functions to simplify controllers' logic. &lt;sup&gt; &lt;a href="https://docs.strapi.io/dev-docs/backend-customization/services"&gt;ReadMore&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;In this step, we use the service to create a function to get the reading list and filter them. The keyword parameter is used to filter the reading-list based on their keywords, and if no keyword is given, it returns all content of reading-list.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;api/reading-list-search/services/reading-list-search.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {errors} from '@strapi/utils';

async function search(keyword?: string) {
  try {
    const entries = await strapi.entityService.findMany('api::reading-list.reading-list', {});

    let filteredEntries = entries;
    if (keyword) {
      filteredEntries = entries.filter((entry) =&amp;gt; {
        const keywords = entry.keyword.split('\n').map((keyword) =&amp;gt; keyword.trim());
        return keywords.includes(keyword);
      });
    }

    return filteredEntries;
  } catch (err) {
    throw new errors.ApplicationError('Something went wrong');
  }
}

export default {search};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;this function first gets reading-list with &lt;a href="https://docs.strapi.io/dev-docs/api/entity-service/crud#findmany"&gt;findMany&lt;/a&gt; and then filters them using the typescript filter function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Controller
&lt;/h2&gt;

&lt;p&gt;Controllers contain a set of methods, called actions, reached by the client according to the requested route. &lt;sup&gt; &lt;a href="https://docs.strapi.io/dev-docs/backend-customization/controllers"&gt;ReadMore&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;To write a controller for the reading-list search function, set the content of the &lt;code&gt;api/reading-list-search/controllers/reading-list-search.js&lt;/code&gt; file something like this to pass keyword search query into search service function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function search(ctx) {
  try {
    return await strapi.service('api::reading-list-search.reading-list-search').search(ctx.request.query.keyword);
  } catch (err) {
    ctx.badRequest('Reading list search controller error', {detail: err});
  }
}

export default {search};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Route
&lt;/h2&gt;

&lt;p&gt;Requests sent to Strapi on any URL are handled by routes. &lt;sup&gt; &lt;a href="https://docs.strapi.io/dev-docs/backend-customization/routes"&gt;ReadMore&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;We must add this endpoint and sets the previous controller as the route handler, put this code to &lt;code&gt;api/reading-list-search/routes/reading-list-search.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default {
  routes: [
    {
      method: 'GET',
      path: '/reading-list-search',
      handler: 'reading-list-search.search',
      config: {
        policies: [],
      },
    },
  ],
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now this route is accessible at &lt;a href="http://localhost:1337/api/reading-list-search"&gt;/api/reading-list-search&lt;/a&gt;, of course if we do the next step 🤓!&lt;/p&gt;

&lt;h2&gt;
  
  
  Set Permission
&lt;/h2&gt;

&lt;p&gt;By default, this API can't be accessible publicly so set the correct permission.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--80ZMcZ7_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.njfamirm.ir/img/5Nszux28-3394.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--80ZMcZ7_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.njfamirm.ir/img/5Nszux28-3394.jpeg" alt="Screenshot of set permission for strapi custom API" width="800" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Result
&lt;/h2&gt;

&lt;p&gt;Congratulations 🎉, we create a custom API for searching in our reading-list using Strapi CMS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gYzg9sLH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.njfamirm.ir/img/t2XQottQ-2318.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gYzg9sLH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.njfamirm.ir/img/t2XQottQ-2318.jpeg" alt="Screenshot of reading list custom API response" width="800" height="569"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope this article is useful for you, and it is a step towards a society where we grow together ♥️&lt;/p&gt;




&lt;p&gt;Thanks &lt;a href="https://github.com/derrickmehaffy"&gt;@derrickmehaffy&lt;/a&gt; for improve this article.&lt;/p&gt;

</description>
      <category>strapi</category>
      <category>idea</category>
      <category>cms</category>
    </item>
    <item>
      <title>Lorem-ipsum.ir launched!</title>
      <dc:creator>S. Amir Mohammad Najafi</dc:creator>
      <pubDate>Thu, 16 Nov 2023 18:51:29 +0000</pubDate>
      <link>https://dev.to/njfamirm/lorem-ipsumir-launched-352h</link>
      <guid>https://dev.to/njfamirm/lorem-ipsumir-launched-352h</guid>
      <description>&lt;p&gt;Hi everyone 🙌🏻&lt;/p&gt;

&lt;p&gt;Recently I was looking for a website that would simply generate lorem ipsum text to use in my project. Suddenly I realized a disaster!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sHvsecbN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://www.njfamirm.ir/cdn/blog/lorem-ipsum-ir-launched/lorem-example.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sHvsecbN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://www.njfamirm.ir/cdn/blog/lorem-ipsum-ir-launched/lorem-example.gif" alt="Lorem ipsum website example" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A request has been sent to the backend service to generate any lorem text! Unfortunately, this was not the only case, perhaps the best of its kind. At least this website had more features.&lt;/p&gt;

&lt;p&gt;After this, I decided to create a lorem ipsum generator website with my friends.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;Many people have built such a website, yes I know!&lt;br&gt;&lt;br&gt;
But the claim of this project is not that we are the best or that we are something new. It has only tried to improve the same old idea, and of course, the main purpose of this project was education.&lt;/p&gt;

&lt;h2&gt;
  
  
  How?
&lt;/h2&gt;

&lt;p&gt;We need to create a website to generate lorem text and copy them to the user's clipboard. &lt;strong&gt;Simply and nothing else!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But our difference from other websites is that all the work is done in the client (user's browser), So we follow the &lt;a href="https://jamstack.org/what-is-jamstack/"&gt;Jamstack architecture&lt;/a&gt;, The core principles of Jamstack is pre-rendering, and so website need just serve static files on the CDN, without any server-side code. This means that the website is very fast.&lt;/p&gt;

&lt;p&gt;So we use &lt;a href="https://www.11ty.dev/"&gt;Eleventy&lt;/a&gt; to build our website. This is a simple, fast and customizable static site generator(SSG), and using Alwatr's 11ty starter-kit called &lt;strong&gt;12fy(11ty++)&lt;/strong&gt; for this project, This starter kit uses esbuild to build Typescript/Javascript, postcss to build CSS, and tailwindcss for styling, The combination of different build tools provides a completely optimal output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Process
&lt;/h2&gt;

&lt;p&gt;After we have decided what we can use for the project, we need to consider our needs.&lt;/p&gt;

&lt;p&gt;On the main page, we need a toolbox to generate lorem text, which includes the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A segmented button for lorem type, paragraph, sentence and keyword.&lt;/li&gt;
&lt;li&gt;A segmented button for number of lorem text.&lt;/li&gt;
&lt;li&gt;A texture to display the lorem text.&lt;/li&gt;
&lt;li&gt;A button to copy the text to the clipboard.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At the bottom of the page, a simple text and image to explain what Ipsum lorem is, this is good for search engine optimization.&lt;/p&gt;

&lt;p&gt;And this is the result:&lt;br&gt;&lt;br&gt;
 &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--f4wEj0fB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.njfamirm.ir/img/QwWOopgt-2684.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f4wEj0fB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.njfamirm.ir/img/QwWOopgt-2684.jpeg" alt="lorem-ipsum.ir page speed result" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next we need to add some JavaScript code to make the toolbox dynamic. This is where the Jamstack architecture differs. We use JSON to store lorem text in them with 3 keys, paragraph, sentence and keyword. which can be seen in this &lt;a href="https://github.com/njfamirm/lorem-ipsum.ir/blob/4dae42acae87f1d4a316a18dcd8709422146f99c/site/_js/data/lorem-ipsum-fa.json"&gt;json file&lt;/a&gt;. This json bundled in our js code and do not additional request sent for it in client.&lt;/p&gt;

&lt;p&gt;Then, write js code to generate the text and place it in the textarea of the toolbox, based on the user input from the segmented buttons. And at the end we add an event listener for the copy button to copy the text to the clipboard. And that's it ⚡️&lt;/p&gt;

&lt;h2&gt;
  
  
  Result
&lt;/h2&gt;

&lt;p&gt;Is Done 🎉, and this is &lt;a href="https://pagespeed.web.dev/analysis/https-lorem-ipsum-ir/sacu27g5cb?form_factor=mobile"&gt;Page Speed result&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Z_JDAuD8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.njfamirm.ir/img/_HNdN4uo-2310.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Z_JDAuD8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://www.njfamirm.ir/img/_HNdN4uo-2310.jpeg" alt="lorem-ipsum.ir page speed result" width="800" height="630"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check out the live version of this project at &lt;a href="https://lorem-ipsum.ir/"&gt;lorem-ipsum.ir&lt;/a&gt; and enjoy it. Also view the source code of this project on &lt;a href="https://github.com/njfamirm/lorem-ipsum.ir"&gt;GitHub&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Future
&lt;/h2&gt;

&lt;p&gt;The main process of the website is done, in the next step we want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add more languages, especially English&lt;/li&gt;
&lt;li&gt;Add more lorem like text.&lt;/li&gt;
&lt;li&gt;Lorem random text.&lt;/li&gt;
&lt;li&gt;and more ...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All task is on &lt;a href="https://github.com/users/njfamirm/projects/6/views/1"&gt;Github Project&lt;/a&gt; and you can see them. contributing is welcome ❤️.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You for reading this post.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/SMsajjadSM"&gt;Sajjad Siadati&lt;/a&gt;, &lt;a href="https://github.com/AmirHosseinAbbasii"&gt;Amir Hossein Abbasi&lt;/a&gt; for contributing in this website.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://jamstack.org/"&gt;Jamstack&lt;/a&gt; for this amazing architecture.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.11ty.dev/"&gt;Eleventy&lt;/a&gt; for this amazing static site generator.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/alwatr"&gt;Alwatr&lt;/a&gt; for this amazing starter kit.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;I hope you enjoyed this post, if you have any questions or suggestions, please let me in twitter &lt;a href="https://twitter.com/njfamirm"&gt;@njfamirm&lt;/a&gt; know.&lt;/p&gt;

</description>
      <category>11ty</category>
      <category>jamstack</category>
    </item>
    <item>
      <title>Separating Commits in Git, A Guide to Streamlining Your Workflow</title>
      <dc:creator>S. Amir Mohammad Najafi</dc:creator>
      <pubDate>Thu, 10 Aug 2023 20:24:22 +0000</pubDate>
      <link>https://dev.to/njfamirm/separating-commits-in-git-a-guide-to-streamlining-your-workflow-51h0</link>
      <guid>https://dev.to/njfamirm/separating-commits-in-git-a-guide-to-streamlining-your-workflow-51h0</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flffkyb2gmnjvhg7vjm9p.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flffkyb2gmnjvhg7vjm9p.jpeg" alt="cover of post about git separate in trunk based deployment" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by Arnaud Mesureur on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hi everyone,&lt;/p&gt;

&lt;p&gt;Today I want to speak about a problem that I have in my daily work with Git when using a trunk-based deployment pattern, and how can solve it with some commands.&lt;br&gt;&lt;br&gt;
First, we need to know about trunk-based deployment, then I will present my problem.&lt;/p&gt;

&lt;p&gt;Let’s dive in!&lt;/p&gt;

&lt;p&gt;You can read faster this post on my &lt;a href="https://dev.to/njfamirm/separating-commits-in-git-a-guide-to-streamlining-your-workflow-17p8"&gt;blog&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;What is Trunk-based deployment?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;TDB, or Trunk-based pattern is a modern way for developers to work together using version control, where each developer divides their work into small batches and merges that work into the trunk at least once a day.&lt;/p&gt;

&lt;p&gt;The key difference between this approach and git-flow workflow is &lt;strong&gt;scope&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
Feature branches typically involve multiple developers and take days or even weeks of work. In contrast, branches in TDB typically last no more than a few hours, with many developers merging their changes into the trunk frequently.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1uwb0ert1rdm3o52cpx0.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1uwb0ert1rdm3o52cpx0.jpeg" alt="trunk-based deployment process explanation" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;source: &lt;a href="https://launchdarkly.com/blog/git-branching-strategies-vs-trunk-based-development/" rel="noopener noreferrer"&gt;https://launchdarkly.com/blog/git-branching-strategies-vs-trunk-based-development/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The above paragraph was taken from the Google Cloud &lt;a href="https://cloud.google.com/architecture/devops/devops-tech-trunk-based-development" rel="noopener noreferrer"&gt;article&lt;/a&gt; about DevOps in trunk-based development, you can refer to this article for more information.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Our problem&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Sometimes it happens that we want to create a feature that depends on several packages, and generally, we have to do several things together and then create a pull request.&lt;br&gt;&lt;br&gt;
At this time, it will be perfect to easily commit wherever we want, and after finishing the work, we can apply according to the rules of TBD pull request, and all our code can be easily reviewed and merged.&lt;/p&gt;

&lt;p&gt;There are two git commands we need to learn for solving this problem. I’ll explain briefly below, but you can skip it if you already know them.&lt;/p&gt;
&lt;h4&gt;
  
  
  Git Rebase
&lt;/h4&gt;

&lt;p&gt;Rebasing is the process of moving or combining a sequence of commits to a new base commit. changing the base of your branch from one commit to another making it appear as if you’d created your branch from a different commit. Internally, Git accomplishes this by creating new commits and applying them to the specified base.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1i871unwm10y10hupf6j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1i871unwm10y10hupf6j.png" width="800" height="544"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;source: &lt;a href="https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase" rel="noopener noreferrer"&gt;https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;read more about this command on the &lt;a href="https://www.atlassian.com/git/tutorials/rewriting-history/git-rebase" rel="noopener noreferrer"&gt;Atlassian blog&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  &lt;strong&gt;Git cherry-pick&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;Cherry-pick enables arbitrary Git commits to be picked by reference and appended to the current working HEAD. Cherry picking is the act of picking a commit from a branch and applying it to another.&lt;/p&gt;

&lt;p&gt;read more about this command on the &lt;a href="https://www.atlassian.com/git/tutorials/cherry-pick" rel="noopener noreferrer"&gt;Atlassian blog&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Solution&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Now that we know about Trunk-based deployment, git rebase, and git cherry-pick commands, we can use them to solve our problem of having multiple commits from multiple packages and features in a single branch.&lt;/p&gt;

&lt;p&gt;Let’s say we have a commit history like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9l6sz9b6evyzpv22maqd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9l6sz9b6evyzpv22maqd.png" width="800" height="518"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Pull request with a multi commit in separate package and feature&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is a bad situation because it makes the review process too long and complicated. We need to separate these commits into multiple branches, one for each feature and package.&lt;/p&gt;

&lt;p&gt;Let’s start by separating the first and last commits, which are about the &lt;strong&gt;&lt;code&gt;package-1&lt;/code&gt;&lt;/strong&gt; feature. These two commits only change &lt;strong&gt;a single feature in a single package&lt;/strong&gt; , so they are a good candidate for separation.&lt;/p&gt;

&lt;p&gt;First, create a new branch from the trunk branch, then, we need to copy the hash of these two commits. and we can use the git &lt;strong&gt;&lt;code&gt;cherry-pick&lt;/code&gt;&lt;/strong&gt; command to copy them into a new branch called &lt;strong&gt;&lt;code&gt;feat/package-1&lt;/code&gt;&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git switch -c feat/package-1 origin/next
git cherry-pick &amp;lt;hash of first commit&amp;gt;
git cherry-pick &amp;lt;hash of second commit&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12km9fmu52jn648jrbn2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12km9fmu52jn648jrbn2.png" alt="screenshot of terminal use git cherry-pick to separate commit" width="800" height="568"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Git commits for separating commits from another branch&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;if you have a conflict when want to cherry-pick, you must first rebase your branch with a trunk to resolve any conflict, if you still have conflict, that’s occurred maybe because you don’t commit correctly! you can use rebase to fix the commit issue.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now we have a new branch with new two commits. We can create a pull request for this branch and merge it into the trunk branch.&lt;br&gt;&lt;br&gt;
Once the pull request is approved and merged, we can rebase the first branch with the trunk branch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyr3qkpu47gg70pxt5auh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyr3qkpu47gg70pxt5auh.png" alt="screenshot of terminal use git rebase" width="800" height="528"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Rebase branch with trunk branch&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This will remove the two commits from the first branch and keep our commit history clean, then you must force push the branch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftnh78d4ws0mey17nutfd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftnh78d4ws0mey17nutfd.png" width="800" height="518"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Cleaner commit history&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We can use the same process to separate the other commits in our history. This will give us a nice, clean commit history with one commit per feature and package, with a full cover of the trunk-based deployment pattern.&lt;/p&gt;

&lt;p&gt;In the end, I have shared my shell function, used by me daily for separating commits:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gsep () {
  currentBranch=$(git rev-parse --abbrev-ref HEAD) &amp;amp;&amp;amp; \
  git fetch origin &amp;amp;&amp;amp; \
  git switch -c feat/$1 origin/next &amp;amp;&amp;amp; \
  shift &amp;amp;&amp;amp; \
  git cherry-pick $@ &amp;amp;&amp;amp; \
  git push -u &amp;amp;&amp;amp; \
  gh pr create -a @me --base next --fill --web &amp;amp;&amp;amp; \
  git switch $currentBranch;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function takes the name of a feature as its argument and creates a new branch called &lt;strong&gt;&lt;code&gt;feat/$1&lt;/code&gt;&lt;/strong&gt;. It cherry-picks the specified commits into the new branch and creates a pull request for it. then switches back to the original branch.&lt;/p&gt;

&lt;p&gt;I hope this article will help you to have a better experience with git and trunk-based deployment.&lt;/p&gt;

&lt;p&gt;Thanks for reading and sharing 💎&lt;/p&gt;




</description>
      <category>gitrebase</category>
      <category>gitcherrypick</category>
      <category>trunkbaseddevelopmen</category>
      <category>deployment</category>
    </item>
    <item>
      <title>A Step-by-Step Guide to Self-Hosting Decap CMS</title>
      <dc:creator>S. Amir Mohammad Najafi</dc:creator>
      <pubDate>Sun, 23 Jul 2023 14:52:08 +0000</pubDate>
      <link>https://dev.to/njfamirm/a-step-by-step-guide-to-self-hosting-decap-cms-546b</link>
      <guid>https://dev.to/njfamirm/a-step-by-step-guide-to-self-hosting-decap-cms-546b</guid>
      <description>&lt;p&gt;Hi everyone!&lt;br&gt;
In this article, I'll show you how to host your own Decap CMS &lt;em&gt;(former Netlify-CMS)&lt;/em&gt; backend without the need for another external service.&lt;/p&gt;

&lt;p&gt;By the end of this article, you will be able to host Decap CMS and have a fully functional content management system that you can use to build your website or blog.&lt;/p&gt;

&lt;p&gt;Let's start&lt;/p&gt;
&lt;h2&gt;
  
  
  Create OAuth Application
&lt;/h2&gt;

&lt;p&gt;To create an OAuth application, you will need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Go to the &lt;a href="https://github.com/settings/applications/new" rel="noopener noreferrer"&gt;Github OAuth settings&lt;/a&gt; from &lt;code&gt;Settings &amp;gt; Developer Settings &amp;gt; OAuth Apps &amp;gt; Generate New&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the Application name field, enter a name for your application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the Homepage URL field, enter the URL of your website.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the Authorization callback URL field, enter the URL that will be redirected to after authentication. This URL will depend on your Decap CMS backend. In this post, we will set the callback URL to &lt;em&gt;&lt;strong&gt;${siteURL}/callback&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once you have entered all of the required information, click Create Application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnjfamirm%2Fblog-archive%2Fmain%2Fpost%2Fself-hosting-decap-cms%2Fcreate-oauth-screenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnjfamirm%2Fblog-archive%2Fmain%2Fpost%2Fself-hosting-decap-cms%2Fcreate-oauth-screenshot.png" title="Create Oauth app on Github for Decap CMS" alt="screenshot from the Github OAuth app settings page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then when the application is created, save the &lt;code&gt;Client ID&lt;/code&gt; and create new &lt;code&gt;Client secrets&lt;/code&gt; for use in the last step.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnjfamirm%2Fblog-archive%2Fmain%2Fpost%2Fself-hosting-decap-cms%2Foauth-setting-screenshot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fnjfamirm%2Fblog-archive%2Fmain%2Fpost%2Fself-hosting-decap-cms%2Foauth-setting-screenshot.png" title="Create client ID and secret ID in Github OAuth app" alt="screenshot from the Github OAuth app client ID and secret ID"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Add CMS to the Website
&lt;/h3&gt;

&lt;p&gt;First, you must install Decap-CMS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add netlify-cms-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add admin html and javascript/typescript file like below:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;admin.html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"robots"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"noindex"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Website | Admin Panel&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"admin.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;admin.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;CMS&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;netlify-cms-app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nx"&gt;CMS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;If you're using Hugo, to add an admin panel to the &lt;code&gt;/admin&lt;/code&gt; address, you can add &lt;code&gt;admin/_index.md&lt;/code&gt; to the &lt;code&gt;content&lt;/code&gt; folder and also &lt;code&gt;_default/admin.html&lt;/code&gt; to &lt;code&gt;layouts&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To speed up load time you can use a Javascript bundler to minify and treeshake the &lt;code&gt;netlify-cms-app&lt;/code&gt; package.&lt;/p&gt;

&lt;p&gt;Something like this in Hugo uses esbuild to minify and treeshake:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{{ $js := resources.Get "/admin.js" | fingerprint | js.Build (dict "minify" true "treeShake" true) }}
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"{{ $js.RelPermalink }}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setup Backend
&lt;/h2&gt;

&lt;p&gt;Based Decap-CMS &lt;a href="https://decapcms.org/docs/external-oauth-clients/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;&lt;br&gt;
you can use an external OAuth client.&lt;br&gt;
I'm testing &lt;a href="https://github.com/ublabs/netlify-cms-oauth" rel="noopener noreferrer"&gt;ublabs/netlify-cms-oauth&lt;/a&gt; with vercel and this work correctly, but our goal was to run on our own servers, not on another PaaS! so I'm rewriting this to run with NodeJS with packages I was using! and publish them to &lt;a href="https://github.com/njfamirm/decap-cms-github-backend" rel="noopener noreferrer"&gt;decap-cms-github-backend&lt;/a&gt;, this repo also publishes a docker image of Decap CMS GitHub backend to &lt;code&gt;ghcr.io&lt;/code&gt;, so we can use this to deploy own backend!&lt;/p&gt;

&lt;p&gt;Now you can add a docker image into your deployment process with this envs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CMS_GITHUB_BACKEND_IMAGE='ghcr.io/njfamirm/decap-cms-github-backend:main'

OAUTH_GITHUB_CLIENT_ID=your_oauth_github_client_id
OAUTH_GITHUB_CLIENT_SECRET=000_your_oauth_github_client_id_000

# Enable debug logging
# CMS_BACKEND_DEBUG=1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and docker compose like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;cms-backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${CMS_BACKEND_IMAGE}&lt;/span&gt;

    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OAUTH_GITHUB_CLIENT_SECRET=${OAUTH_GITHUB_CLIENT_SECRET}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;OAUTH_GITHUB_CLIENT_ID=${OAUTH_GITHUB_CLIENT_ID}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ALWATR_DEBUG=${CMS_BACKEND_DEBUG-}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setup &lt;code&gt;admin.yml&lt;/code&gt; File
&lt;/h2&gt;

&lt;p&gt;Amazing, almost all thing is done, just need to add Decap-CMS into the admin &lt;code&gt;config.yml&lt;/code&gt; file like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github&lt;/span&gt;
  &lt;span class="na"&gt;branch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
  &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;njfamirm/amazing-oauth&lt;/span&gt;
  &lt;span class="na"&gt;base_url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://auth.amazing-oauth.name/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;now when you deploy the backend, can login by going to the &lt;code&gt;https://amazing-oauth.name/admin&lt;/code&gt; page and get access to the CMS to push commit, create and merge PR in your repo!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enjoy like a freed bird from the cage ✌🏻💎&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I hope this article was useful for you!&lt;/p&gt;

</description>
      <category>decap</category>
      <category>cms</category>
      <category>selfhosting</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
