<?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: Theoklitos Bampouris</title>
    <description>The latest articles on DEV Community by Theoklitos Bampouris (@theoklitosbam7).</description>
    <link>https://dev.to/theoklitosbam7</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%2F50616%2F78d21ba5-c30d-4f3a-8f43-1227512b8a8b.jpg</url>
      <title>DEV Community: Theoklitos Bampouris</title>
      <link>https://dev.to/theoklitosbam7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/theoklitosbam7"/>
    <language>en</language>
    <item>
      <title>Pi Coding Agent: A Self-Documenting, Extensible AI Partner</title>
      <dc:creator>Theoklitos Bampouris</dc:creator>
      <pubDate>Mon, 13 Apr 2026 11:40:30 +0000</pubDate>
      <link>https://dev.to/theoklitosbam7/pi-coding-agent-a-self-documenting-extensible-ai-partner-dn</link>
      <guid>https://dev.to/theoklitosbam7/pi-coding-agent-a-self-documenting-extensible-ai-partner-dn</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://www.bampouris.eu/blog/pi-self-documenting/" rel="noopener noreferrer"&gt;https://www.bampouris.eu/blog/pi-self-documenting/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Meta-lesson&lt;/strong&gt;: One of Pi's most powerful features is that you can ask it to explain itself. The agent can read its own documentation, investigate its codebase, and help you extend or modify its behavior—all through natural conversation.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Scenario: Renaming and Enhancing the "Agent" Tool
&lt;/h2&gt;

&lt;p&gt;In this session, I asked Pi to help rename the "subagent" tool to simply "Agent" and then enhance it with model configuration capabilities. What followed was a perfect demonstration of how Pi operates as a self-documenting system.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Initial Request
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;User&lt;/strong&gt;: &lt;em&gt;Configure the subagent extension of pi coding agent such as the tool which "Delegate tasks to specialized subagents with isolated context" to be renamed: "Agent" (including all its references and calls etc.).&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Phase 1: Pi Investigates Its Own Structure
&lt;/h2&gt;

&lt;p&gt;Instead of requiring me to know where files are located, Pi immediately began exploring its own codebase:&lt;/p&gt;

&lt;h3&gt;
  
  
  Reading the Documentation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;📖 Reading: /Users/.../.nvm/.../pi-coding-agent/README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pi accessed its own README to understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How extensions are structured&lt;/li&gt;
&lt;li&gt;Where tools are registered&lt;/li&gt;
&lt;li&gt;How the agent system works&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Finding the Extension Files
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find ~/.pi/agent &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.ts"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s2"&gt;"*.js"&lt;/span&gt; 2&amp;gt;/dev/null | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-30&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/Users/.../.pi/agent/extensions/list-agents.ts&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/Users/.../.pi/agent/extensions/subagent/agents.ts&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/Users/.../.pi/agent/extensions/subagent/index.ts&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Reading Extension Documentation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;📖 Reading: /Users/.../pi-coding-agent/docs/extensions.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This document explained:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Extensions are TypeScript modules that extend pi's behavior. They can subscribe to lifecycle events, register custom tools callable by the LLM, add commands, and more."&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Phase 2: Understanding the Implementation
&lt;/h2&gt;

&lt;p&gt;Pi read its own extension source code to understand the current implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="err"&gt;📖&lt;/span&gt; &lt;span class="nx"&gt;Reading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;/.pi/&lt;/span&gt;&lt;span class="nx"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;extensions&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;subagent&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;
&lt;span class="err"&gt;📖&lt;/span&gt; &lt;span class="nx"&gt;Reading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;/.pi/&lt;/span&gt;&lt;span class="nx"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;extensions&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;subagent&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;agents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;
&lt;span class="err"&gt;📖&lt;/span&gt; &lt;span class="nx"&gt;Reading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;/.pi/&lt;/span&gt;&lt;span class="nx"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;extensions&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;agents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From these files, Pi learned:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Tool Registration&lt;/strong&gt;: The tool was registered with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;name: "subagent"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;label: "Subagent"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;A description mentioning "subagents"&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Three Operation Modes&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single&lt;/strong&gt;: One agent + task&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parallel&lt;/strong&gt;: Multiple tasks array&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chain&lt;/strong&gt;: Sequential with &lt;code&gt;{previous}&lt;/code&gt; placeholder&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;UI Rendering&lt;/strong&gt;: Display text using &lt;code&gt;theme.bold("subagent ")&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Error Messages&lt;/strong&gt;: &lt;code&gt;"Subagent was aborted"&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Phase 3: Executing the Changes
&lt;/h2&gt;

&lt;p&gt;Pi systematically updated all references:&lt;/p&gt;

&lt;h3&gt;
  
  
  Tool Registration Changes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;name: "subagent"&lt;/code&gt; → &lt;code&gt;name: "agent"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;label: "Subagent"&lt;/code&gt; → &lt;code&gt;label: "Agent"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Description updated from "subagents" to "agents"&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  UI Display Updates
&lt;/h3&gt;

&lt;p&gt;All &lt;code&gt;theme.bold("subagent ")&lt;/code&gt; references changed to &lt;code&gt;theme.bold("agent ")&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chain mode display&lt;/li&gt;
&lt;li&gt;Parallel mode display&lt;/li&gt;
&lt;li&gt;Single agent mode display&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Error Message Update
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;"Subagent was aborted"&lt;/code&gt; → &lt;code&gt;"Agent was aborted"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Documentation Updates
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;list-agents.ts&lt;/code&gt; description updated&lt;/li&gt;
&lt;li&gt;File header comments updated&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Phase 4: Debugging (When Things Go Wrong)
&lt;/h2&gt;

&lt;p&gt;After reloading, an error appeared:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;User&lt;/strong&gt;: &lt;em&gt;After reload we get the following issue: [Extension issues] ParseError: Unexpected token&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pi's response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="err"&gt;📖&lt;/span&gt; &lt;span class="nx"&gt;Reading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;Users&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pi&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;extensions&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;subagent&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Found: &lt;em&gt;"The edit accidentally duplicated the description lines"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix applied&lt;/strong&gt; - duplicate lines removed, file now parses correctly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Phase 5: Enhancing the Tool (Feature Addition)
&lt;/h2&gt;

&lt;p&gt;Next request:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;User&lt;/strong&gt;: &lt;em&gt;Investigate if the agent tool can accept model configuration as input via prompt... If it cannot in the current configuration, then adjust it so that it can. The model from input should have priority.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Investigation Phase
&lt;/h3&gt;

&lt;p&gt;Pi investigated how models are handled:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"ctx.model&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;modelRegistry"&lt;/span&gt; ~/.pi/agent/extensions/subagent/index.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"model"&lt;/span&gt; ~/.pi/agent/extensions/subagent/index.ts | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-30&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Found that the current implementation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read model from agent markdown file frontmatter&lt;/li&gt;
&lt;li&gt;Had no input parameter for model override&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Enhancement
&lt;/h3&gt;

&lt;p&gt;Pi added a &lt;code&gt;model&lt;/code&gt; parameter to the tool schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Model to use (e.g., 'anthropic/claude-sonnet-4-20250514'). Overrides agent's frontmatter model.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then implemented the priority logic:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;First priority&lt;/strong&gt;: Model from input parameters&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fallback&lt;/strong&gt;: Model from agent markdown frontmatter&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Final fallback&lt;/strong&gt;: Main agent's running model&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The implementation involved:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adding &lt;code&gt;model?: string&lt;/code&gt; to &lt;code&gt;SingleAgentTask&lt;/code&gt; type&lt;/li&gt;
&lt;li&gt;Modifying &lt;code&gt;runSingleAgent()&lt;/code&gt; to accept and use the model parameter&lt;/li&gt;
&lt;li&gt;Updating all three execution modes (single, parallel, chain) to pass the model&lt;/li&gt;
&lt;li&gt;Updating the tool description to document the new parameter&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Key Insights: Pi as a Self-Documenting System
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Documentation is Always Available&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Pi has built-in knowledge of its own documentation locations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Pi documentation (read only when the user asks about pi itself):
&lt;span class="p"&gt;
-&lt;/span&gt; Main documentation: ~/.nvm/.../pi-coding-agent/README.md
&lt;span class="p"&gt;-&lt;/span&gt; Additional docs: ~/.nvm/.../pi-coding-agent/docs
&lt;span class="p"&gt;-&lt;/span&gt; Examples: ~/.nvm/.../pi-coding-agent/examples
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. &lt;strong&gt;Extension System is First-Class&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;From the docs:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Pi ships with powerful defaults but skips features like sub agents and plan mode. Instead, you can ask pi to build what you want or install a third party pi package that matches your workflow."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Three-Level Model Fallback System&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The implemented enhancement shows a robust pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input model → Frontmatter model → Main agent model
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This graceful degradation ensures the tool always works while respecting user preferences.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Skills System for Specialized Knowledge&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Pi can load skills from &lt;code&gt;~/.pi/agent/skills/&lt;/code&gt; that provide specialized instructions. The session shows skills for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;autofix (CodeRabbit integration)&lt;/li&gt;
&lt;li&gt;changeset-pr (versioning)&lt;/li&gt;
&lt;li&gt;code-review&lt;/li&gt;
&lt;li&gt;frontend-design&lt;/li&gt;
&lt;li&gt;git operations&lt;/li&gt;
&lt;li&gt;and many more...&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What This Demonstrates
&lt;/h2&gt;

&lt;h3&gt;
  
  
  You Can Ask Pi About Itself
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;"How do I configure extensions?"&lt;/li&gt;
&lt;li&gt;"Where is the documentation for themes?"&lt;/li&gt;
&lt;li&gt;"How do I add a custom tool?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pi will read its own docs and explain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pi Can Modify Its Own Code
&lt;/h3&gt;

&lt;p&gt;The agent can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find its own extension files&lt;/li&gt;
&lt;li&gt;Read and understand the code&lt;/li&gt;
&lt;li&gt;Make precise edits&lt;/li&gt;
&lt;li&gt;Fix errors when they occur&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Extensions Are Powerful
&lt;/h3&gt;

&lt;p&gt;The subagent → Agent tool demonstrates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Custom tool registration&lt;/li&gt;
&lt;li&gt;Type-safe parameter schemas (using TypeBox)&lt;/li&gt;
&lt;li&gt;Multiple execution modes (single, parallel, chain)&lt;/li&gt;
&lt;li&gt;UI rendering customization&lt;/li&gt;
&lt;li&gt;Error handling&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Philosophical Point
&lt;/h2&gt;

&lt;p&gt;Pi embodies a different approach to AI tooling. As the documentation states:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"Pi is aggressively extensible so it doesn't have to dictate your workflow. Features that other tools bake in can be built with extensions, skills, or installed from third-party pi packages. This keeps the core minimal while letting you shape pi to fit how you work."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The fact that Pi can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Explain its own architecture&lt;/li&gt;
&lt;li&gt;Read and modify its own extensions&lt;/li&gt;
&lt;li&gt;Help you build new capabilities&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;...makes it a genuinely &lt;strong&gt;self-improving system&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;Want to explore Pi's self-documenting capabilities? Try asking:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;em&gt;"Show me how extensions work"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"How do I create a custom skill?"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"What tools are currently available and what do they do?"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Help me modify the theme/colors"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Read the documentation about sessions and explain branching"&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Pi will demonstrate the same pattern: read docs → investigate code → explain → implement if requested.&lt;/p&gt;




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

&lt;p&gt;This session demonstrates something profound: &lt;strong&gt;Pi is an AI system that can understand and modify its own behavior.&lt;/strong&gt; It's not a black box—it's a transparent, extensible platform that invites exploration and customization.&lt;/p&gt;

&lt;p&gt;The ability to ask "How do I extend you?" and receive a working implementation is a glimpse into a future where AI systems are not just tools, but &lt;strong&gt;collaborative partners&lt;/strong&gt; in building the exact workflow you need.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Info about the above described pi session&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Session date: 2026-04-12&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Pi: @mariozechner/pi-coding-agent&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Model: mimo-v2-omni via opencode-go&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>agentskills</category>
    </item>
    <item>
      <title>Revolutionizing Git Workflows: The MCP Git Commit Generator</title>
      <dc:creator>Theoklitos Bampouris</dc:creator>
      <pubDate>Sat, 09 Aug 2025 10:32:10 +0000</pubDate>
      <link>https://dev.to/theoklitosbam7/revolutionizing-git-workflows-the-mcp-git-commit-generator-530m</link>
      <guid>https://dev.to/theoklitosbam7/revolutionizing-git-workflows-the-mcp-git-commit-generator-530m</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://www.bampouris.eu/blog/mcp-git-commit-generator" rel="noopener noreferrer"&gt;https://www.bampouris.eu/blog/mcp-git-commit-generator&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the world of software development, writing clear, consistent commit messages is both an art and a necessity. Good commit messages tell a story, help teammates understand changes, and make code history navigable. Yet, many developers struggle with crafting meaningful commit messages that follow established conventions like &lt;a href="https://www.conventionalcommits.org/" rel="noopener noreferrer"&gt;Conventional Commits&lt;/a&gt;. Enter the &lt;strong&gt;MCP Git Commit Generator&lt;/strong&gt; – a revolutionary tool that leverages the Model Context Protocol (MCP) to automatically generate conventional commit messages from your staged git changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the MCP Git Commit Generator?
&lt;/h2&gt;

&lt;p&gt;The MCP Git Commit Generator is an intelligent MCP server that analyzes your staged git changes and automatically generates conventional commit messages. Built with Python and leveraging the power of AI through the Model Context Protocol, this tool bridges the gap between your code changes and descriptive, standardized commit messages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features at a Glance
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;🤖 AI-Driven Analysis&lt;/strong&gt;: Automatically analyzes staged git diffs to understand the nature of your changes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;📝 Conventional Commits Support&lt;/strong&gt;: Generates messages following the widely-adopted Conventional Commits specification&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🔧 Flexible Integration&lt;/strong&gt;: Works with VS Code, Cursor, Windsurf, Claude Desktop, and other MCP-compatible clients&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🐳 Docker-Ready&lt;/strong&gt;: Ships as a lightweight Docker container for easy deployment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🔍 Inspector UI&lt;/strong&gt;: Includes a debugging interface for testing and development&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;⚡ Multiple Transport Options&lt;/strong&gt;: Supports both stdio (default) and Server-Sent Events (SSE) transports&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Problem It Solves
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Before: The Commit Message Struggle
&lt;/h3&gt;

&lt;p&gt;Every developer has been there – you've made significant changes to your codebase, staged your files, and now you're staring at the commit message prompt. Questions flood your mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Should this be a &lt;code&gt;feat&lt;/code&gt;, &lt;code&gt;fix&lt;/code&gt;, or &lt;code&gt;refactor&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;What scope should I use?&lt;/li&gt;
&lt;li&gt;How do I summarize these complex changes concisely?&lt;/li&gt;
&lt;li&gt;Am I following the team's commit message conventions?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result? Either rushed, uninformative messages like "fix stuff" or spending precious development time crafting the perfect commit message.&lt;/p&gt;

&lt;h3&gt;
  
  
  After: Intelligent Automation
&lt;/h3&gt;

&lt;p&gt;With the MCP Git Commit Generator, this friction disappears. The tool:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Analyzes your staged changes&lt;/strong&gt; using git diff&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Understands the context&lt;/strong&gt; of modified files and their relationships&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Determines the appropriate commit type&lt;/strong&gt; (feat, fix, docs, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Suggests relevant scopes&lt;/strong&gt; based on changed files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generates a complete conventional commit message&lt;/strong&gt; ready for use&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Technical Architecture
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Core Components
&lt;/h3&gt;

&lt;p&gt;The MCP Git Commit Generator is built with a clean, modular architecture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/mcp_git_commit_generator/
├── __init__.py     # CLI entrypoint using Click
├── __main__.py     # Module launcher
└── server.py       # MCP tools implementation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  MCP Tools Exposed
&lt;/h3&gt;

&lt;p&gt;The server exposes two primary MCP tools:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. &lt;code&gt;generate_commit_message&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;This is the star of the show. The tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@mcp.tool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_commit_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;repo_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;commit_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Parameters:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;repo_path&lt;/code&gt;: Optional path to git repository (defaults to current directory)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;commit_type&lt;/code&gt;: Optional commit type override (auto-detected if not provided)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scope&lt;/code&gt;: Optional scope override (auto-detected if not provided)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Process:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Validates the git repository&lt;/li&gt;
&lt;li&gt;Retrieves staged changes using &lt;code&gt;git diff --cached&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Analyzes file status and change patterns&lt;/li&gt;
&lt;li&gt;Generates contextual analysis for AI processing&lt;/li&gt;
&lt;li&gt;Returns a conventional commit message suggestion&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  2. &lt;code&gt;check_git_status&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;A utility tool that provides comprehensive repository status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@mcp.tool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check_git_status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repo_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This tool reports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Staged files ready for commit&lt;/li&gt;
&lt;li&gt;Unstaged modifications&lt;/li&gt;
&lt;li&gt;Untracked files&lt;/li&gt;
&lt;li&gt;Current branch information&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Transport Flexibility
&lt;/h3&gt;

&lt;p&gt;The tool supports two transport mechanisms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;stdio (default)&lt;/strong&gt;: Perfect for CLI integration and MCP clients&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SSE (Server-Sent Events)&lt;/strong&gt;: Ideal for web-based interfaces and the Inspector UI&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Integration Ecosystem
&lt;/h2&gt;

&lt;h3&gt;
  
  
  MCP Client Support
&lt;/h3&gt;

&lt;p&gt;The tool seamlessly integrates with popular development environments:&lt;/p&gt;

&lt;h4&gt;
  
  
  VS Code Integration
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"servers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"mcp-git-commit-generator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"docker"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"run"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"-i"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"--rm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"--mount"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"type=bind,src=${userHome},dst=${userHome}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"ghcr.io/theoklitosbam7/mcp-git-commit-generator:latest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Claude Desktop, Cursor, and Windsurf
&lt;/h4&gt;

&lt;p&gt;Similar JSON configurations enable the tool across different AI-powered development environments, making it accessible regardless of your preferred IDE.&lt;/p&gt;

&lt;h3&gt;
  
  
  Docker-First Approach
&lt;/h3&gt;

&lt;p&gt;The tool ships as a Docker container, providing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consistent Environment&lt;/strong&gt;: Same behavior across different systems&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy Installation&lt;/strong&gt;: No Python environment setup required&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt;: Runs as non-root user with minimal permissions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portability&lt;/strong&gt;: Works on any system with Docker&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real-World Usage Scenarios
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Scenario 1: Feature Development
&lt;/h3&gt;

&lt;p&gt;You've just implemented a new user authentication system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Stage your changes&lt;/span&gt;
git add src/auth/ tests/auth/ docs/authentication.md

&lt;span class="c"&gt;# Use the MCP tool (through your IDE)&lt;/span&gt;
&lt;span class="c"&gt;# Generates: "feat(auth): implement OAuth2 authentication with JWT tokens"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Scenario 2: Bug Fixes
&lt;/h3&gt;

&lt;p&gt;You've fixed a critical performance issue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add src/database/query.py tests/test_query.py

&lt;span class="c"&gt;# Generates: "fix(database): optimize N+1 query in user profile loading"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Scenario 3: Documentation Updates
&lt;/h3&gt;

&lt;p&gt;You've updated project documentation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add README.md docs/api.md

&lt;span class="c"&gt;# Generates: "docs: update API documentation and installation guide"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Development and Debugging
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Inspector UI
&lt;/h3&gt;

&lt;p&gt;The included Inspector UI provides a powerful debugging interface:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interactive Tool Testing&lt;/strong&gt;: Test tools with different parameters&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time Debugging&lt;/strong&gt;: Set breakpoints in tool implementation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parameter Validation&lt;/strong&gt;: Verify tool arguments before execution&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Development Workflow
&lt;/h3&gt;

&lt;p&gt;The project includes VS Code tasks for streamlined development:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Start MCP Server&lt;/strong&gt;: Launches server with debugging support&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start MCP Inspector&lt;/strong&gt;: Opens the Inspector UI for testing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexible Environment&lt;/strong&gt;: Supports both &lt;code&gt;uv&lt;/code&gt; and traditional &lt;code&gt;pip&lt;/code&gt; workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Technical Innovation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  AI-Powered Analysis
&lt;/h3&gt;

&lt;p&gt;The tool doesn't just parse file names – it performs intelligent analysis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Analyzes diff content, file patterns, and change types
&lt;/span&gt;&lt;span class="n"&gt;analysis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
## Git Change Analysis for Conventional Commit Message

### Changed Files:
&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;files_result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

### Diff Preview:
&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;diff_result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

### User Preferences:
- Commit Type: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;commit_type&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;auto-detect&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
- Scope: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;auto-detect&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This rich context enables AI models to make informed decisions about commit message generation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conventional Commits Compliance
&lt;/h3&gt;

&lt;p&gt;The tool strictly follows the Conventional Commits specification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;type&amp;gt;[optional scope]: &amp;lt;description&amp;gt;

[optional body]

[optional footer(s)]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Supporting all standard types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;feat&lt;/code&gt;: New features&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fix&lt;/code&gt;: Bug fixes&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docs&lt;/code&gt;: Documentation changes&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;style&lt;/code&gt;: Code style changes&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;refactor&lt;/code&gt;: Code refactoring&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;perf&lt;/code&gt;: Performance improvements&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;test&lt;/code&gt;: Test additions/modifications&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;build&lt;/code&gt;: Build system changes&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ci&lt;/code&gt;: CI/CD changes&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chore&lt;/code&gt;: Maintenance tasks&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;revert&lt;/code&gt;: Commit reverts&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Performance and Reliability
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Lightweight Design
&lt;/h3&gt;

&lt;p&gt;The tool is designed for speed and efficiency:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fast Git Operations&lt;/strong&gt;: Direct git command execution&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimal Dependencies&lt;/strong&gt;: Only essential packages included&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker Optimization&lt;/strong&gt;: Multi-stage builds for smaller images&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Error Handling
&lt;/h3&gt;

&lt;p&gt;Robust error handling ensures reliability:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_valid_repo_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repo_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Validate git repository path with proper error handling&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repo_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repo_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.git&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;repo_path&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;The MCP Git Commit Generator represents more than just a commit message tool – it's a glimpse into the future of AI-assisted development workflows. By leveraging the Model Context Protocol, it demonstrates how AI can seamlessly integrate into existing development tools and processes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Potential Enhancements
&lt;/h3&gt;

&lt;p&gt;Future versions could include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Custom Convention Support&lt;/strong&gt;: Beyond Conventional Commits&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team-Specific Rules&lt;/strong&gt;: Organization-specific commit patterns&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multilingual Support&lt;/strong&gt;: Commit messages in different languages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration Metrics&lt;/strong&gt;: Track commit message quality over time&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advanced Scope Detection&lt;/strong&gt;: ML-powered scope suggestion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Quick Setup
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install Docker&lt;/strong&gt; (if not already installed)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure your MCP client&lt;/strong&gt; with the provided JSON configuration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start committing smarter&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add your-changes
&lt;span class="c"&gt;# Use the MCP tool through your IDE&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"generated message"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  For Developers
&lt;/h3&gt;

&lt;p&gt;The project welcomes contributions and provides comprehensive development guidelines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/theoklitosBam7/mcp-git-commit-generator.git
&lt;span class="nb"&gt;cd &lt;/span&gt;mcp-git-commit-generator
uv venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; uv pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;The MCP Git Commit Generator transforms one of the most mundane yet important aspects of software development – writing commit messages. By combining the power of AI with the flexibility of the Model Context Protocol, it eliminates friction while maintaining consistency and quality.&lt;/p&gt;

&lt;p&gt;Whether you're a solo developer looking to improve your git history or part of a team striving for better collaboration through clear commit messages, this tool offers a compelling solution. Its Docker-based approach ensures easy adoption, while its MCP foundation provides a glimpse into the future of AI-integrated development tools.&lt;/p&gt;

&lt;p&gt;The era of "fix stuff" commit messages is over. Welcome to the age of intelligent, automated, and meaningful git history.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Try it today&lt;/strong&gt;: The MCP Git Commit Generator is available as a Docker image at &lt;code&gt;ghcr.io/theoklitosbam7/mcp-git-commit-generator:latest&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Learn more&lt;/strong&gt;: Visit the &lt;a href="https://github.com/theoklitosBam7/mcp-git-commit-generator" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; for detailed documentation and configuration examples.&lt;/p&gt;

&lt;p&gt;Happy committing! 🚀&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>git</category>
      <category>python</category>
    </item>
    <item>
      <title>Setup Unit Testing Tools in Angular CLI Project</title>
      <dc:creator>Theoklitos Bampouris</dc:creator>
      <pubDate>Fri, 21 Jan 2022 21:04:00 +0000</pubDate>
      <link>https://dev.to/theoklitosbam7/setup-unit-testing-tools-in-angular-cli-project-2k4f</link>
      <guid>https://dev.to/theoklitosbam7/setup-unit-testing-tools-in-angular-cli-project-2k4f</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://www.bampouris.eu/blog/setup-unit-testing-angular" rel="noopener noreferrer"&gt;https://www.bampouris.eu/blog/setup-unit-testing-angular&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Every developer have to ensure that his/her application is working as expected. A safeguard to that purpose are unit tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Defaults of an Angular CLI Generated Project
&lt;/h2&gt;

&lt;p&gt;An Angular CLI generated project comes by default with &lt;a href="https://karma-runner.github.io/latest/index.html" rel="noopener noreferrer"&gt;Karma&lt;/a&gt; and &lt;a href="https://jasmine.github.io/" rel="noopener noreferrer"&gt;Jasmine&lt;/a&gt; for unit testing. However, there are people who prefer other tools such as &lt;a href="https://jestjs.io/" rel="noopener noreferrer"&gt;Jest&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'm not going, in this post, to compare or choose the one over the other. I will only show you the steps to move from Karma/Jasmine to Jest. At the end, it's just a case of taste.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remove Karma &amp;amp; Jasmine Related Packages
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Uninstall the &lt;code&gt;npm&lt;/code&gt; packages:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm uninstall karma karma-chrome-launcher karma-coverage karma-jasmine karma-jasmine-html-reporter jasmine-core @types/jasmine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Delete the no more needed Karma configuration files:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; ./karma.conf.js ./src/test.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Install Jest
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; jest @types/jest jest-preset-angular @angular-builders/jest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@types/jest&lt;/code&gt;: This package contains type definitions for Jest.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;jest-preset-angular&lt;/code&gt;: It is Jest preset configuration and TypeScript preprocessor with source map support for Jest that lets you use Jest to test Angular projects.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@angular-builders/jest&lt;/code&gt;: Allows running &lt;code&gt;ng test&lt;/code&gt; with Jest instead of Karma &amp;amp; Jasmine. The builder comes to provide zero configuration setup for Jest while keeping the workspace clear of boilerplate code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To make use of &lt;code&gt;@angular-builders/jest&lt;/code&gt;, the only we need to do is to change our &lt;code&gt;angular.json&lt;/code&gt; file as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;  }
},
"test": {
&lt;span class="gd"&gt;-  "builder": "@angular-devkit/build-angular:karma",
&lt;/span&gt;&lt;span class="gi"&gt;+  "builder": "@angular-builders/jest:run",
&lt;/span&gt;  "options": {
&lt;span class="gd"&gt;-    "main": "src/test.ts",
-    "polyfills": "src/polyfills.ts",
-    "tsConfig": "tsconfig.spec.json",
-    "karmaConfig": "karma.conf.js",
-    "inlineStyleLanguage": "scss",
-    "assets": ["src/favicon.ico", "src/assets"],
-    "styles": ["src/styles.scss"],
-    "scripts": []
&lt;/span&gt;&lt;span class="gi"&gt;+    "no-cache": true
&lt;/span&gt;  },
  "lint": {
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may find details how to change the builder options &lt;a href="https://www.npmjs.com/package/@angular-builders/jest" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup Jest in our Project
&lt;/h2&gt;

&lt;p&gt;We create a config file in project's root directory with the name &lt;code&gt;jest.config.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="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;preset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jest-preset-angular&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;setupFilesAfterEnv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;rootDir&amp;gt;/setup-jest.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you guess from the above configuration, we will now create &lt;code&gt;setup-jest.ts&lt;/code&gt; in root directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jest-preset-angular/setup-jest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./jest-global-mocks&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second &lt;code&gt;import&lt;/code&gt; above is optional at first. Because &lt;code&gt;jest-preset-angular&lt;/code&gt; uses &lt;code&gt;JSDOM&lt;/code&gt;, which is different from normal browsers, we might need some global browser mocks to simulate the behaviors of real browsers in &lt;code&gt;JSDOM&lt;/code&gt;. To add global mocks, we can create &lt;code&gt;jest-global-mocks.ts&lt;/code&gt; and use it in our Jest setup.&lt;/p&gt;

&lt;p&gt;You may find more information about &lt;code&gt;jest-preset-angular&lt;/code&gt; in official &lt;a href="https://thymikee.github.io/jest-preset-angular/" rel="noopener noreferrer"&gt;docs&lt;/a&gt; and about Jest and JSDOM in this &lt;a href="https://freecontent.manning.com/testing-with-node-jest-and-jsdom/" rel="noopener noreferrer"&gt;article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is an example of &lt;code&gt;jest-global-mocks.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CSS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;doctype&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;getComputedStyle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;appearance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-webkit-appearance&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;defineProperty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;transform&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;enumerable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;configurable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, in &lt;code&gt;tsconfig.spec.json&lt;/code&gt; file, we have to take care of at least two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Replace &lt;code&gt;jasmine&lt;/code&gt; in types array with &lt;code&gt;jest&lt;/code&gt;, as we want our tests to be type-checked against Jest typings and not Jasmine.&lt;/li&gt;
&lt;li&gt;Remove &lt;code&gt;test.ts&lt;/code&gt; entry from files array. This file was responsible for Karma setup, we don't need it here anymore.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;"compilerOptions": {
  "outDir": "./out-tsc/spec",
  "types": [
&lt;span class="gd"&gt;-    "jasmine"
-  ]
&lt;/span&gt;&lt;span class="gi"&gt;+    "jest",
+    "node"
+  ],
+  "esModuleInterop": true,
+  "emitDecoratorMetadata": true,
&lt;/span&gt;},
"files": [
&lt;span class="gd"&gt;-  "src/test.ts",
&lt;/span&gt;  "src/polyfills.ts"
],
"include": [
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For other options you may check &lt;a href="https://www.typescriptlang.org/tsconfig" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Last But Not Least
&lt;/h2&gt;

&lt;p&gt;A nice and powerful tool to simplify our Angular unit tests is &lt;a href="https://ngneat.github.io/spectator/" rel="noopener noreferrer"&gt;Spectator&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Helps you get rid of all the boilerplate grunt work, leaving you with readable, sleek and streamlined unit tests.&lt;/li&gt;
&lt;li&gt;Write tests for components, directives, services, and more, without having to learn TestBed, ComponentFixture, and DebugElement APIs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can install it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; @ngneat/spectator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope in a future post to show a few examples of how we can use it and take advantage of its features.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>testing</category>
      <category>jest</category>
    </item>
    <item>
      <title>Avoid Memory Leaks in Angular</title>
      <dc:creator>Theoklitos Bampouris</dc:creator>
      <pubDate>Thu, 25 Mar 2021 13:33:16 +0000</pubDate>
      <link>https://dev.to/theoklitosbam7/avoid-memory-leaks-in-angular-5gla</link>
      <guid>https://dev.to/theoklitosbam7/avoid-memory-leaks-in-angular-5gla</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://www.bampouris.eu/blog/avoid-memory-leaks-angular" rel="noopener noreferrer"&gt;https://www.bampouris.eu/blog/avoid-memory-leaks-angular&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Almost five years ago, Ben Lesh wrote a nice article with title: &lt;a href="https://medium.com/@benlesh/rxjs-dont-unsubscribe-6753ed4fda87" rel="noopener noreferrer"&gt;RxJS: Don’t Unsubscribe&lt;/a&gt;. The author of course doesn't tell us to never care about our &lt;code&gt;Subscription&lt;/code&gt;. He means that we must find a way that we don't have to perform &lt;code&gt;.unsubscribe()&lt;/code&gt; manually in each one. Let's start our mission!&lt;/p&gt;

&lt;h2&gt;
  
  
  Our Road Map
&lt;/h2&gt;

&lt;p&gt;The lifetime of some global components, such as AppComponent, is the same as the lifetime of the app itself. If we know that we're dealing with such a case it is acceptable to &lt;code&gt;.subscribe()&lt;/code&gt; to an Observable without providing any memory leak guard step. However, handle memory leaks during the implementation of an Angular application is a critical task for every developer. We'll begin our quest with showing what we mean with &lt;strong&gt;memory leak&lt;/strong&gt; and we'll proceed solving the problem at first with the "traditional" way of &lt;code&gt;.unsubscribe()&lt;/code&gt;, until we explore our preferable pattern.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Bad Open Subscriptions&lt;/li&gt;
&lt;li&gt;Unsubscribe the Old Way&lt;/li&gt;
&lt;li&gt;The Async Pipe&lt;/li&gt;
&lt;li&gt;The RxJS Operators&lt;/li&gt;
&lt;li&gt;The DestroyService&lt;/li&gt;
&lt;li&gt;Conclusions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Bad Open Subscriptions
&lt;/h2&gt;

&lt;p&gt;We have a simple demo app with two routing components: &lt;code&gt;FirstComponent&lt;/code&gt; and &lt;code&gt;SecondComponent&lt;/code&gt; (&lt;strong&gt;First Cmp&lt;/strong&gt; and &lt;strong&gt;Second Cmp&lt;/strong&gt; nav link buttons respectively). The &lt;code&gt;FirstComponent&lt;/code&gt; (corresponding to path &lt;code&gt;/first&lt;/code&gt;) subscribes to a &lt;code&gt;timer1$&lt;/code&gt; observable and sends messages to a &lt;code&gt;ScreenMessagesComponent&lt;/code&gt; via a &lt;code&gt;MessageService&lt;/code&gt;. The messages are displayed at the bottom of the screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stackblitz.com/github/theoklitosBam7/ng-unsubscribe-examples/tree/1-show-memory-leak" rel="noopener noreferrer"&gt;Live Example&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FirstComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;timer1$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;messageService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MessageService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timer1$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messageService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`FirstComponent timer1$: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we navigate to &lt;code&gt;/second&lt;/code&gt; path, &lt;code&gt;FirstComponent&lt;/code&gt; has been destroyed. However, we still see outgoing messages from the above subscription. This is happening because we forgot to "close the door behind us": our app has an open &lt;code&gt;Subscription&lt;/code&gt;. As we go back and forth we add more and more subscriptions which will close only when the app is closed. We have to deal with &lt;strong&gt;Memory Leaks!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftb-projphotos.netlify.app%2Favoid-memory-leaks-angular%2Fmemory-leaks-1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftb-projphotos.netlify.app%2Favoid-memory-leaks-angular%2Fmemory-leaks-1.gif" alt="memory-leaks-1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Unsubscribe the Old Way
&lt;/h2&gt;

&lt;p&gt;A straightforward way to solve to above problem is to implement the &lt;a href="https://angular.io/guide/lifecycle-hooks" rel="noopener noreferrer"&gt;lifecycle hook&lt;/a&gt; method &lt;code&gt;ngOnDestroy()&lt;/code&gt;. As we read from the official documentation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;...Unsubscribe Observables and detach event handlers to avoid memory leaks...&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FirstComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;timer1$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Subscription&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;messageService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MessageService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timer1$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messageService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`FirstComponent timer1$: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftb-projphotos.netlify.app%2Favoid-memory-leaks-angular%2Fmemory-leaks-2.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftb-projphotos.netlify.app%2Favoid-memory-leaks-angular%2Fmemory-leaks-2.gif" alt="memory-leaks-2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Furthermore, if we have more than one &lt;code&gt;Subscription&lt;/code&gt;, we have to do the same job for each of them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FirstComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;timer1$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;timer2$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;subscription1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Subscription&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;subscription2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Subscription&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;messageService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MessageService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscription1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timer1$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messageService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`FirstComponent timer1$: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscription2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timer2$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messageService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`FirstComponent timer2$: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscription1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscription2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In case we don't have only one or two subscriptions and we want to reduce the number of &lt;code&gt;.unsubscribe()&lt;/code&gt; calls, we can create a parent &lt;code&gt;Subscription&lt;/code&gt; and add to it the child ones. When a parent subscription is unsubscribed, any child subscriptions that were added to it are also unsubscribed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stackblitz.com/github/theoklitosBam7/ng-unsubscribe-examples/tree/2-unsubscribe-old-way" rel="noopener noreferrer"&gt;Live Example&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FirstComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;timer1$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;timer2$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Subscription&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;messageService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MessageService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timer1$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messageService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`FirstComponent timer1$: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timer2$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messageService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`FirstComponent timer2$: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using a parent &lt;code&gt;Subscription&lt;/code&gt; we don't have to care about plenty of properties and we also perform only one &lt;code&gt;.unsubscribe()&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Async Pipe
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://angular.io/api/common/AsyncPipe" rel="noopener noreferrer"&gt;AsyncPipe&lt;/a&gt; kick ass! It has no rival when we want to display data "reactively" in our component's template.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The async pipe subscribes to an Observable or Promise and returns the latest value it has emitted. When a new value is emitted, the async pipe marks the component to be checked for changes. When the component gets destroyed, the async pipe unsubscribes automatically to avoid potential memory leaks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://stackblitz.com/github/theoklitosBam7/ng-unsubscribe-examples/tree/3-async-pipe" rel="noopener noreferrer"&gt;Live Example&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-first&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;p&amp;gt;first component works!&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;{{ timer3$ | async }}&amp;lt;/p&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FirstComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;

  &lt;span class="nx"&gt;timer3$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Using the &lt;code&gt;AsyncPipe&lt;/code&gt; there is no need neither to &lt;code&gt;.subscribe()&lt;/code&gt; nor to &lt;code&gt;.unsubscribe()&lt;/code&gt; manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  The RxJS Operators
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://rxjs-dev.firebaseapp.com/guide/overview" rel="noopener noreferrer"&gt;RxJS&lt;/a&gt; is a library for composing asynchronous and event-based programs by using observable sequences. It has some great operators such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://rxjs-dev.firebaseapp.com/api/operators/take" rel="noopener noreferrer"&gt;take&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rxjs-dev.firebaseapp.com/api/operators/takeWhile" rel="noopener noreferrer"&gt;takeWhile&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rxjs-dev.firebaseapp.com/api/operators/first" rel="noopener noreferrer"&gt;first&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rxjs-dev.firebaseapp.com/api/operators/last" rel="noopener noreferrer"&gt;last&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We won't stand in each of them. We'll see only the usage of &lt;a href="https://rxjs-dev.firebaseapp.com/api/operators/takeUntil" rel="noopener noreferrer"&gt;takeUntil&lt;/a&gt; operator.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lets values pass until a second Observable, notifier, emits a value. Then, it completes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At first, I'd like to mention the dangers as described in this article: &lt;a href="https://ncjamieson.com/avoiding-takeuntil-leaks/" rel="noopener noreferrer"&gt;RxJS: Avoiding takeUntil Leaks&lt;/a&gt;. &lt;code&gt;takeUntil&lt;/code&gt; operator has to be (usually) the last operator in the &lt;code&gt;pipe&lt;/code&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the &lt;code&gt;takeUntil&lt;/code&gt; operator is placed before an operator that involves a subscription to another observable source, the subscription to that source might not be unsubscribed when &lt;code&gt;takeUntil&lt;/code&gt; receives its notification.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://stackblitz.com/github/theoklitosBam7/ng-unsubscribe-examples/tree/4-takeuntil" rel="noopener noreferrer"&gt;Live Example&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FirstComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;destroy$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Subject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;messageService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MessageService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timer1$&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;takeUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroy$&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messageService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`FirstComponent timer1$: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messageService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;gt;&amp;gt;&amp;gt; FirstComponent timer1$ completed`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timer2$&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;takeUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroy$&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messageService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`FirstComponent timer2$: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messageService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&amp;gt;&amp;gt;&amp;gt; FirstComponent timer2$ completed`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroy$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroy$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;destroy$&lt;/code&gt; is our second &lt;code&gt;Observable&lt;/code&gt; (notifier), which emits inside &lt;code&gt;ngOnDestroy()&lt;/code&gt; lifecycle hook, triggered that way the completion of our data streams. An advantage to this approach is it actually completes the observable and so the &lt;code&gt;complete()&lt;/code&gt; callback is called. When we call &lt;code&gt;.unsubscribe()&lt;/code&gt; there’s no way we’ll be notified that the unsubscription happened.&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%2Ftb-projphotos.netlify.app%2Favoid-memory-leaks-angular%2Fmemory-leaks-3.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftb-projphotos.netlify.app%2Favoid-memory-leaks-angular%2Fmemory-leaks-3.gif" alt="memory-leaks-3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Drawback
&lt;/h3&gt;

&lt;p&gt;All the above solutions actually solve our problem, however they all have at least one drawback: we have to repeat ourselves in each component by implementing &lt;code&gt;ngOnDestroy()&lt;/code&gt; for our purpose. Is there any better way to reduce boilerplate furthermore? Yes, we'll take advantage of &lt;code&gt;takeUntil&lt;/code&gt; and &lt;a href="https://angular.io/guide/dependency-injection" rel="noopener noreferrer"&gt;Angular's DI mechanism&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The DestroyService
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://stackblitz.com/github/theoklitosBam7/ng-unsubscribe-examples/tree/5-destroy-service" rel="noopener noreferrer"&gt;Live Example&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, we'll move the &lt;code&gt;ngOnDestroy()&lt;/code&gt; into a service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt; &lt;span class="p"&gt;}&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;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Subject&lt;/span&gt; &lt;span class="p"&gt;}&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;rxjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DestroyService&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Subject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;FirstComponent&lt;/code&gt; both provides the instance of the service (through the providers metadata array) and injects that instance into itself through its constructor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-first&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;p&amp;gt;first component works!&amp;lt;/p&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;DestroyService&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FirstComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;messageService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MessageService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;destroy$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DestroyService&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have the exact same result as the previous one! We can provide an instance of &lt;code&gt;DestroyService&lt;/code&gt; in any component that needs it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;Eventually, I think that the preferable way to manage our RxJS subscriptions is by using &lt;code&gt;takeUntil&lt;/code&gt; operator via an Angular service. Some benefits are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Less code&lt;/li&gt;
&lt;li&gt;Fires a completion event when we kill our stream&lt;/li&gt;
&lt;li&gt;Less chance to forget &lt;code&gt;.unsubscribe()&lt;/code&gt; or &lt;code&gt;.next()&lt;/code&gt;, &lt;code&gt;.complete()&lt;/code&gt; methods in the &lt;code&gt;ngOnDestroy()&lt;/code&gt; implementation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GitHub repo with the examples is available &lt;a href="https://github.com/theoklitosBam7/ng-unsubscribe-examples" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>rxjs</category>
    </item>
    <item>
      <title>SQL: Copy Tables and Massive Update</title>
      <dc:creator>Theoklitos Bampouris</dc:creator>
      <pubDate>Sat, 06 Apr 2019 18:59:46 +0000</pubDate>
      <link>https://dev.to/theoklitosbam7/sql-copy-tables-and-massive-update-31ke</link>
      <guid>https://dev.to/theoklitosbam7/sql-copy-tables-and-massive-update-31ke</guid>
      <description>&lt;h2&gt;
  
  
  The road map
&lt;/h2&gt;

&lt;p&gt;There are a lot of times during development where we make a mistake and all or part of our data are gone. Even worse when we lose them due to a bug in our production version.&lt;/p&gt;

&lt;p&gt;In this post, we'll see how to create a database table as a backup from an existing one, copy the data, and make a massive update joining these two tables. We'll quote the corresponding SQL statements from different RDBMSs: MariaDB, PostgreSQL, MS SQL Server, IBM DB2, SQLite.&lt;/p&gt;

&lt;h2&gt;
  
  
  MariaDB
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create the table
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;tbl2&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="n"&gt;tbl1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;tbl2&lt;/code&gt; table will inhert all the attributes from &lt;code&gt;tbl1&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Copy the data
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;tbl2&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;tbl1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We may use the &lt;code&gt;WHERE&lt;/code&gt; clause to insert only a part of tbl1's data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Massive update
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;tbl1&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="k"&gt;INNER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;tbl2&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;key&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  PostgreSQL
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create the table
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;tbl2&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="n"&gt;tbl1&lt;/span&gt; &lt;span class="k"&gt;INCLUDING&lt;/span&gt; &lt;span class="k"&gt;ALL&lt;/span&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Copy the data
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;tbl2&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;tbl1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Massive update
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;tbl1&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column1&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;tbl2&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;key&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  MS SQL Server
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create the table and copy all data
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;tbl2&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;tbl1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create the table ONLY
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;tbl2&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;tbl1&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Massive update
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column1&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;tbl1&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="k"&gt;INNER&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;tbl2&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;key&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  IBM DB2
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create the table
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;tbl2&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="n"&gt;tbl1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Copy the data
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;tbl2&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;tbl1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Massive update
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;tbl1&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column1&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;tbl2&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;key&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  SQLite
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create the table only
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;tbl2&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;tbl1&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Copy the data only
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;tbl2&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;tbl1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create the table and the data at the same time
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;tbl2&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;tbl1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Massive update
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;tbl1&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt;
&lt;span class="n"&gt;column1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column1&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;tbl2&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tbl1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;tbl1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;key&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;key&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;tbl2&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In SQLite we may take advantage of the &lt;a href="https://www.sqlite.org/rowvalue.html" rel="noopener noreferrer"&gt;Row Values Method&lt;/a&gt;, in the case we want to use more than one key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;tbl1&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt;
&lt;span class="n"&gt;column1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column1&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;tbl2&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
    &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tbl1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tbl1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tbl1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tbl1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;key2&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;tbl2&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://www.codingnotebook.eu/sql-copy-tables-and-massive-update/" rel="noopener noreferrer"&gt;https://www.codingnotebook.eu/sql-copy-tables-and-massive-update/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>sql</category>
      <category>rdbms</category>
      <category>database</category>
    </item>
    <item>
      <title>How to reset your forgotten password in PostgreSQL</title>
      <dc:creator>Theoklitos Bampouris</dc:creator>
      <pubDate>Sat, 12 Jan 2019 14:53:58 +0000</pubDate>
      <link>https://dev.to/theoklitosbam7/how-to-reset-your-forgotten-password-in-postgresql-4a7g</link>
      <guid>https://dev.to/theoklitosbam7/how-to-reset-your-forgotten-password-in-postgresql-4a7g</guid>
      <description>&lt;h2&gt;
  
  
  The moment you realize the problem
&lt;/h2&gt;

&lt;p&gt;It's a good practice even for your local DB server to provide a password for each user. PostgreSQL's default user (who is also an admin) is &lt;code&gt;postgres&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;A standard method to get access to our DB is using &lt;code&gt;psql&lt;/code&gt; command via terminal (I'm running &lt;a href="https://manjaro.org/" rel="noopener noreferrer"&gt;Manjaro Linux&lt;/a&gt;). So, we type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We enter our password and we get the message&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3lyr3doofffn97wkby2r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3lyr3doofffn97wkby2r.png" alt="Password Authentication Failed" width="800" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't Panic!
&lt;/h2&gt;

&lt;p&gt;First of all, we must find the "PostgreSQL Client Authentication Configuration File", which has the name &lt;code&gt;pg_hba.conf&lt;/code&gt;. In Manjaro, it lives in path &lt;code&gt;/var/lib/postgres/data/pg_hba.conf&lt;/code&gt;. Be careful that it is required to have root permissions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /var/lib/postgres/data/pg_hba.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbox9i3bsah17dmt3lqpn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbox9i3bsah17dmt3lqpn.png" alt="PostgreSQL Client Authentication Configuration File" width="800" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We change the &lt;code&gt;md5&lt;/code&gt; authentication in "local" connection to &lt;code&gt;trust&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;local   all             all                                     trust
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and we restart our server&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart postgresql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now PostgreSQL doesn't ask a password and we are allowed to connent with user &lt;code&gt;postgres&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F65n2bff79bz4giod74xm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F65n2bff79bz4giod74xm.png" alt="Trusted Connection" width="800" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next step is to reset the password&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8n6zhiy8t9s7vjeqho3c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8n6zhiy8t9s7vjeqho3c.png" alt="Reset Password" width="800" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We exit &lt;code&gt;psql&lt;/code&gt;, we turn back &lt;code&gt;pg_hba.conf&lt;/code&gt; to it's previous state (&lt;code&gt;md5&lt;/code&gt; authentication) and we restart the server. We are able to connent using our new password for user &lt;code&gt;postgres&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flz2wk3lpj2iav05w7wur.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flz2wk3lpj2iav05w7wur.png" alt="Successful Authentication" width="800" height="576"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://www.codingnotebook.eu/postgresql-reset-password/" rel="noopener noreferrer"&gt;https://www.codingnotebook.eu/postgresql-reset-password/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>postgres</category>
    </item>
    <item>
      <title>DSPPGM: Display Program</title>
      <dc:creator>Theoklitos Bampouris</dc:creator>
      <pubDate>Sat, 12 Jan 2019 14:47:57 +0000</pubDate>
      <link>https://dev.to/theoklitosbam7/dsppgm-display-program-3288</link>
      <guid>https://dev.to/theoklitosbam7/dsppgm-display-program-3288</guid>
      <description>&lt;h2&gt;
  
  
  A little bit encyclopedic intro
&lt;/h2&gt;

&lt;p&gt;IBM's iSeries operating system (formely AS/400) is a legacy computer system which is mainly used in Financial Services industry (Banking, Insurance). It supports application development in many programming languages, yet the most famous are COBOL, RPG, CL.&lt;/p&gt;

&lt;p&gt;In Feb 1993, IBM first introduced ILE (Integrated Language Environment) for ILE C and in May 1994 COBOL, RPG, CL join the party. ILE is anenvironment in which code from many languages can be compiled, bound together, and run.&lt;/p&gt;

&lt;p&gt;So we can see PGMs with attributes CBL (for COBOL/400) and also with CBLLE (for ILE COBOL).&lt;/p&gt;

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

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

&lt;p&gt;COBOL/400 is the standard COBOL adopted by IBM for the AS/400 system. It differentiates in the sense that the file handling for reports and subfiles, indicator usage and any other feature specific to AS/400 have been incorporated in it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;You, as a developer, often have to find the source code from which a pgm object was compiled. Someone tells you: "Try the DSPOBJD (Display Object Description) command". Let's do it! Go to command line, write &lt;code&gt;DSPOBJD&lt;/code&gt;, press &lt;strong&gt;F4&lt;/strong&gt; button, fill in the required fields and press &lt;strong&gt;ENTER&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;Select option &lt;strong&gt;8&lt;/strong&gt; and notice the displayed information.&lt;/p&gt;

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

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

&lt;p&gt;Voilà! The source code is in Library &lt;strong&gt;USER04441&lt;/strong&gt;, in Source file &lt;strong&gt;MYFILE&lt;/strong&gt;, in member &lt;strong&gt;EMPCBL&lt;/strong&gt;. Our problem is solved! Now let's find &lt;strong&gt;EF1MAIN&lt;/strong&gt;'s source code. Following the same process:&lt;/p&gt;

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

&lt;p&gt;Wait! What's going on? Where is our information? We have to remember that &lt;strong&gt;EF1MAIN&lt;/strong&gt; is a CBLLE program. When it was compiled it didn't produced directly the executable object, but an intermediate &lt;strong&gt;MODULE&lt;/strong&gt; and from this the &lt;strong&gt;PGM&lt;/strong&gt; was created.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;There is another command which is more generic: &lt;code&gt;DSPPGM&lt;/code&gt; (Display Program). The Display Program Information for a CBLLE program has a lot of screen, so we have to press &lt;strong&gt;ENTER&lt;/strong&gt; until we see:&lt;/p&gt;

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

&lt;p&gt;With &lt;strong&gt;5&lt;/strong&gt; option we get:&lt;/p&gt;

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

&lt;p&gt;The source code is in Library &lt;strong&gt;USER04441&lt;/strong&gt;, in Source file &lt;strong&gt;SUSANA&lt;/strong&gt;, in member &lt;strong&gt;EF1MAIN&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now, we really solved our problem!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://www.codingnotebook.eu/dsppgm/" rel="noopener noreferrer"&gt;https://www.codingnotebook.eu/dsppgm/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ibm</category>
      <category>as400</category>
    </item>
  </channel>
</rss>
