<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Art of coding]]></title><description><![CDATA[A technical leader and software engineer with 20+ years experience designing enterprise platforms. If you are interested in software development and architectur]]></description><link>https://artofcoding.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1750591027648/53800bbb-bf89-4a47-8507-f4c13e5d13bb.png</url><title>Art of coding</title><link>https://artofcoding.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Thu, 16 Apr 2026 19:44:55 GMT</lastBuildDate><atom:link href="https://artofcoding.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Building a Context-Aware Gemini CLI Workflow]]></title><description><![CDATA[Have you ever wished you could have the same project-based context management in Gemini CLI that you get with Claude Projects or ChatGPT's custom instructions? After some experimentation, I've built a workflow that gives you exactly that - automated ...]]></description><link>https://artofcoding.dev/building-a-context-aware-gemini-cli-workflow</link><guid isPermaLink="true">https://artofcoding.dev/building-a-context-aware-gemini-cli-workflow</guid><category><![CDATA[ai cli]]></category><category><![CDATA[gemini]]></category><category><![CDATA[geminiai ]]></category><category><![CDATA[GeminiCLI]]></category><category><![CDATA[gemini cli]]></category><category><![CDATA[context-manager]]></category><category><![CDATA[Context Management]]></category><category><![CDATA[AI Assistants ]]></category><category><![CDATA[AI assistant]]></category><category><![CDATA[google gemini]]></category><category><![CDATA[Google Gemini AI]]></category><category><![CDATA[Terminal AI]]></category><category><![CDATA[Developer Tools]]></category><dc:creator><![CDATA[Febin Joy]]></dc:creator><pubDate>Sat, 26 Jul 2025 17:32:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1753550617260/fba4ea4d-0238-4449-8501-454af4b5cba4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Have you ever wished you could have the same project-based context management in Gemini CLI that you get with Claude Projects or ChatGPT's custom instructions? After some experimentation, I've built a workflow that gives you exactly that - automated project selection, context management, and intelligent file loading for Gemini CLI.</p>
<h2 id="heading-the-problem-context-switching-overhead">The Problem: Context Switching Overhead</h2>
<p>When working with AI assistants across multiple projects, you constantly face the same frustrations:</p>
<ul>
<li><p><strong>Manual context setup</strong> every time you start a new session</p>
</li>
<li><p><strong>Forgetting to include</strong> project-specific instructions or context</p>
</li>
<li><p><strong>Inconsistent AI behaviour</strong> due to missing context</p>
</li>
<li><p><strong>Time wasted</strong> navigating directories and copying instructions</p>
</li>
</ul>
<p>ChatGPT offers custom GPTs, Claude provides Projects, and Perplexity has collections to handle project-specific context, but Gemini CLI lacks built-in project management features. This means you're stuck with manual setup every time.</p>
<p>Imagine you're a developer working on three different projects: a Go research project, a personal writing blog, and a technical documentation site. Each needs different context, tone, and specific instructions. Without proper setup, you'd spend the first few minutes of every Gemini CLI session explaining what you're working on.</p>
<h2 id="heading-the-solution-step-by-step-setup">The Solution: Step-by-Step Setup</h2>
<h2 id="heading-step-1-create-your-gemini-root-folder">Step 1: Create Your Gemini Root Folder</h2>
<p>First, create a dedicated directory structure for your Gemini projects:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Choose a location that works for you</span>
mkdir -p ~/Dev/AI_Tools/Gemini
<span class="hljs-built_in">cd</span> ~/Dev/AI_Tools/Gemini

<span class="hljs-comment"># Create your global instructions file</span>
touch instructions.md
</code></pre>
<p>Edit <a target="_blank" href="http://instructions.md"><code>instructions.md</code></a> with your personal Gemini preferences:</p>
<pre><code class="lang-markdown"><span class="hljs-section"># Global Gemini Instructions</span>

<span class="hljs-bullet">-</span> Communicate in a friendly, professional, and straightforward manner
<span class="hljs-bullet">-</span> Provide actionable advice that is direct and avoids generic or weak phrasing
<span class="hljs-bullet">-</span> Use UK English for all spelling, punctuation, and grammar
<span class="hljs-bullet">-</span> Be specific and avoid vague responses
<span class="hljs-bullet">-</span> When coding, prioritise readability and best practices
</code></pre>
<p>These are common instructions you want to provide to Gemini, irrespective of the project (folder) you are working on.</p>
<h2 id="heading-step-2-create-the-mygeminishhttpmygeminish-script">Step 2: Create the <a target="_blank" href="http://mygemini.sh">mygemini.sh</a> Script</h2>
<p>Create the automation script that will handle project management:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Create the script file</span>
touch mygemini.sh
chmod +x mygemini.sh
</code></pre>
<p>Here's the complete script (compatible with both bash and zsh on Mac/Linux):</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/usr/bin/env bash</span>

<span class="hljs-comment"># mygemini.sh - Context-aware Gemini CLI project manager</span>
<span class="hljs-built_in">set</span> -e

<span class="hljs-comment"># Configuration - Update this path to match your setup</span>
GEMINI_ROOT=<span class="hljs-string">"<span class="hljs-variable">$HOME</span>/Dev/AI_Tools/Gemini"</span>
INSTRUCTIONS_FILE=<span class="hljs-string">"<span class="hljs-variable">$GEMINI_ROOT</span>/instructions.md"</span>

<span class="hljs-comment"># Colors for better UX (works on both Mac and Linux)</span>
<span class="hljs-keyword">if</span> [[ -t 1 ]]; <span class="hljs-keyword">then</span>
    RED=<span class="hljs-string">'\033[0;31m'</span>
    GREEN=<span class="hljs-string">'\033[0;32m'</span>
    YELLOW=<span class="hljs-string">'\033[1;33m'</span>
    BLUE=<span class="hljs-string">'\033[0;34m'</span>
    CYAN=<span class="hljs-string">'\033[0;36m'</span>
    NC=<span class="hljs-string">'\033[0m'</span>
<span class="hljs-keyword">else</span>
    RED=<span class="hljs-string">''</span> GREEN=<span class="hljs-string">''</span> YELLOW=<span class="hljs-string">''</span> BLUE=<span class="hljs-string">''</span> CYAN=<span class="hljs-string">''</span> NC=<span class="hljs-string">''</span>
<span class="hljs-keyword">fi</span>

<span class="hljs-function"><span class="hljs-title">print_color</span></span>() {
    <span class="hljs-built_in">local</span> color=<span class="hljs-variable">$1</span>
    <span class="hljs-built_in">shift</span>
    <span class="hljs-built_in">echo</span> -e <span class="hljs-string">"<span class="hljs-variable">${color}</span>$*<span class="hljs-variable">${NC}</span>"</span>
}

<span class="hljs-comment"># Check prerequisites</span>
<span class="hljs-keyword">if</span> ! <span class="hljs-built_in">command</span> -v gemini &amp;&gt; /dev/null; <span class="hljs-keyword">then</span>
    print_color <span class="hljs-variable">$RED</span> <span class="hljs-string">"Error: 'gemini' command not found. Please install Gemini CLI first."</span>
    <span class="hljs-built_in">exit</span> 1
<span class="hljs-keyword">fi</span>

<span class="hljs-keyword">if</span> [[ ! -f <span class="hljs-string">"<span class="hljs-variable">$INSTRUCTIONS_FILE</span>"</span> ]]; <span class="hljs-keyword">then</span>
    print_color <span class="hljs-variable">$RED</span> <span class="hljs-string">"Error: instructions.md not found: <span class="hljs-variable">$INSTRUCTIONS_FILE</span>"</span>
    print_color <span class="hljs-variable">$YELLOW</span> <span class="hljs-string">"Please create your global instructions file first."</span>
    <span class="hljs-built_in">exit</span> 1
<span class="hljs-keyword">fi</span>

print_color <span class="hljs-variable">$CYAN</span> <span class="hljs-string">"🔮 MyGemini - Context-Aware Gemini"</span>

<span class="hljs-comment"># List all available projects</span>
print_color <span class="hljs-variable">$CYAN</span> <span class="hljs-string">"\n=== Available Projects ==="</span>
projects=()
counter=1

<span class="hljs-comment"># Use shell-agnostic directory iteration</span>
<span class="hljs-keyword">for</span> item <span class="hljs-keyword">in</span> <span class="hljs-string">"<span class="hljs-variable">$GEMINI_ROOT</span>"</span>/*; <span class="hljs-keyword">do</span>
    <span class="hljs-keyword">if</span> [[ -d <span class="hljs-string">"<span class="hljs-variable">$item</span>"</span> &amp;&amp; <span class="hljs-string">"<span class="hljs-subst">$(basename <span class="hljs-string">"<span class="hljs-variable">$item</span>"</span>)</span>"</span> != <span class="hljs-string">".*"</span> ]]; <span class="hljs-keyword">then</span>
        project_name=$(basename <span class="hljs-string">"<span class="hljs-variable">$item</span>"</span>)
        projects+=(<span class="hljs-string">"<span class="hljs-variable">$project_name</span>"</span>)
        print_color <span class="hljs-variable">$BLUE</span> <span class="hljs-string">"[<span class="hljs-variable">$counter</span>] <span class="hljs-variable">$project_name</span>"</span>
        ((counter++))
    <span class="hljs-keyword">fi</span>
<span class="hljs-keyword">done</span>

print_color <span class="hljs-variable">$GREEN</span> <span class="hljs-string">"[<span class="hljs-variable">$counter</span>] Create New Project"</span>
max_option=<span class="hljs-variable">$counter</span>

<span class="hljs-comment"># Get user selection with validation</span>
<span class="hljs-keyword">while</span> <span class="hljs-literal">true</span>; <span class="hljs-keyword">do</span>
    print_color <span class="hljs-variable">$YELLOW</span> <span class="hljs-string">"\nSelect a project (1-<span class="hljs-variable">$max_option</span>):"</span>
    <span class="hljs-built_in">read</span> -r selection

    <span class="hljs-keyword">if</span> [[ <span class="hljs-string">"<span class="hljs-variable">$selection</span>"</span> =~ ^[0-9]+$ ]] &amp;&amp; [[ <span class="hljs-string">"<span class="hljs-variable">$selection</span>"</span> -ge 1 ]] &amp;&amp; [[ <span class="hljs-string">"<span class="hljs-variable">$selection</span>"</span> -le <span class="hljs-string">"<span class="hljs-variable">$max_option</span>"</span> ]]; <span class="hljs-keyword">then</span>
        <span class="hljs-keyword">if</span> [[ <span class="hljs-string">"<span class="hljs-variable">$selection</span>"</span> -eq <span class="hljs-string">"<span class="hljs-variable">$max_option</span>"</span> ]]; <span class="hljs-keyword">then</span>
            <span class="hljs-comment"># Create new project</span>
            <span class="hljs-keyword">while</span> <span class="hljs-literal">true</span>; <span class="hljs-keyword">do</span>
                print_color <span class="hljs-variable">$YELLOW</span> <span class="hljs-string">"Enter new project name (no spaces or special characters):"</span>
                <span class="hljs-built_in">read</span> -r project_name

                <span class="hljs-comment"># Validate project name</span>
                <span class="hljs-keyword">if</span> [[ -z <span class="hljs-string">"<span class="hljs-variable">$project_name</span>"</span> ]]; <span class="hljs-keyword">then</span>
                    print_color <span class="hljs-variable">$RED</span> <span class="hljs-string">"Project name cannot be empty."</span>
                    <span class="hljs-built_in">continue</span>
                <span class="hljs-keyword">elif</span> [[ <span class="hljs-string">"<span class="hljs-variable">$project_name</span>"</span> =~ [^a-zA-Z0-9_-] ]]; <span class="hljs-keyword">then</span>
                    print_color <span class="hljs-variable">$RED</span> <span class="hljs-string">"Project name can only contain letters, numbers, underscores, and hyphens."</span>
                    <span class="hljs-built_in">continue</span>
                <span class="hljs-keyword">elif</span> [[ -d <span class="hljs-string">"<span class="hljs-variable">$GEMINI_ROOT</span>/<span class="hljs-variable">$project_name</span>"</span> ]]; <span class="hljs-keyword">then</span>
                    print_color <span class="hljs-variable">$RED</span> <span class="hljs-string">"Project '<span class="hljs-variable">$project_name</span>' already exists."</span>
                    <span class="hljs-built_in">continue</span>
                <span class="hljs-keyword">else</span>
                    mkdir -p <span class="hljs-string">"<span class="hljs-variable">$GEMINI_ROOT</span>/<span class="hljs-variable">$project_name</span>"</span>
                    selected_project=<span class="hljs-string">"<span class="hljs-variable">$project_name</span>"</span>
                    <span class="hljs-built_in">break</span>
                <span class="hljs-keyword">fi</span>
            <span class="hljs-keyword">done</span>
        <span class="hljs-keyword">else</span>
            selected_project=<span class="hljs-string">"<span class="hljs-variable">${projects[$((selection-1))]}</span>"</span>
        <span class="hljs-keyword">fi</span>
        <span class="hljs-built_in">break</span>
    <span class="hljs-keyword">else</span>
        print_color <span class="hljs-variable">$RED</span> <span class="hljs-string">"Invalid selection. Please enter a number between 1 and <span class="hljs-variable">$max_option</span>."</span>
    <span class="hljs-keyword">fi</span>
<span class="hljs-keyword">done</span>

project_path=<span class="hljs-string">"<span class="hljs-variable">$GEMINI_ROOT</span>/<span class="hljs-variable">$selected_project</span>"</span>
context_file=<span class="hljs-string">"<span class="hljs-variable">$project_path</span>/context.md"</span>

print_color <span class="hljs-variable">$GREEN</span> <span class="hljs-string">"✓ Selected: <span class="hljs-variable">$selected_project</span>"</span>

<span class="hljs-comment"># Handle project context</span>
<span class="hljs-keyword">if</span> [[ -f <span class="hljs-string">"<span class="hljs-variable">$context_file</span>"</span> ]]; <span class="hljs-keyword">then</span>
    print_color <span class="hljs-variable">$GREEN</span> <span class="hljs-string">"✓ Found existing context.md"</span>
<span class="hljs-keyword">else</span>
    print_color <span class="hljs-variable">$YELLOW</span> <span class="hljs-string">"No context.md found for this project."</span>
    print_color <span class="hljs-variable">$CYAN</span> <span class="hljs-string">"Please provide project context (type 'END' on a new line when finished):"</span>

    context_content=<span class="hljs-string">""</span>
    <span class="hljs-keyword">while</span> IFS= <span class="hljs-built_in">read</span> -r line; <span class="hljs-keyword">do</span>
        <span class="hljs-keyword">if</span> [[ <span class="hljs-string">"<span class="hljs-variable">$line</span>"</span> == <span class="hljs-string">"END"</span> ]]; <span class="hljs-keyword">then</span>
            <span class="hljs-built_in">break</span>
        <span class="hljs-keyword">fi</span>
        context_content+=<span class="hljs-string">"<span class="hljs-variable">$line</span>"</span>$<span class="hljs-string">'\n'</span>
    <span class="hljs-keyword">done</span>

    <span class="hljs-keyword">if</span> [[ -n <span class="hljs-string">"<span class="hljs-variable">$context_content</span>"</span> ]]; <span class="hljs-keyword">then</span>
        <span class="hljs-built_in">printf</span> <span class="hljs-string">"%s"</span> <span class="hljs-string">"<span class="hljs-variable">$context_content</span>"</span> &gt; <span class="hljs-string">"<span class="hljs-variable">$context_file</span>"</span>
        print_color <span class="hljs-variable">$GREEN</span> <span class="hljs-string">"✓ Context saved to <span class="hljs-variable">$context_file</span>"</span>
    <span class="hljs-keyword">else</span>
        <span class="hljs-built_in">printf</span> <span class="hljs-string">"# Context for %s\n\nAdd your project-specific context here."</span> <span class="hljs-string">"<span class="hljs-variable">$selected_project</span>"</span> &gt; <span class="hljs-string">"<span class="hljs-variable">$context_file</span>"</span>
        print_color <span class="hljs-variable">$YELLOW</span> <span class="hljs-string">"✓ Created placeholder context file"</span>
    <span class="hljs-keyword">fi</span>
<span class="hljs-keyword">fi</span>

<span class="hljs-comment"># Copy global instructions to project folder (always get latest version)</span>
cp <span class="hljs-string">"<span class="hljs-variable">$INSTRUCTIONS_FILE</span>"</span> <span class="hljs-string">"<span class="hljs-variable">$project_path</span>/instructions.md"</span>
print_color <span class="hljs-variable">$YELLOW</span> <span class="hljs-string">"✓ Global instructions copied to project"</span>

<span class="hljs-comment"># Launch Gemini in project directory</span>
<span class="hljs-built_in">cd</span> <span class="hljs-string">"<span class="hljs-variable">$project_path</span>"</span>
print_color <span class="hljs-variable">$CYAN</span> <span class="hljs-string">"Working directory: <span class="hljs-variable">$project_path</span>"</span>
print_color <span class="hljs-variable">$GREEN</span> <span class="hljs-string">"\nLaunching Gemini CLI with project context...\n"</span>

<span class="hljs-built_in">exec</span> gemini
</code></pre>
<h2 id="heading-step-3-add-shell-alias">Step 3: Add Shell Alias</h2>
<p>Add an alias to your shell configuration file for easy access:</p>
<p><strong>For Zsh users (~/.zshrc):</strong></p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">'alias mygemini="~/Dev/AI_Tools/Gemini/mygemini.sh"'</span> &gt;&gt; ~/.zshrc
<span class="hljs-built_in">source</span> ~/.zshrc
</code></pre>
<p><strong>For Bash users (~/.bashrc or ~/.bash_profile):</strong></p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">'alias mygemini="~/Dev/AI_Tools/Gemini/mygemini.sh"'</span> &gt;&gt; ~/.bashrc
<span class="hljs-built_in">source</span> ~/.bashrc
</code></pre>
<h2 id="heading-step-4-configure-geminis-memory-system">Step 4: Configure Gemini's Memory System</h2>
<p>Navigate to your Gemini root directory and set up automatic file loading:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> ~/Dev/AI_Tools/Gemini
gemini
</code></pre>
<p>In the Gemini CLI, run these commands once:</p>
<pre><code class="lang-bash">/memory add instructions.md
/memory add context.md
</code></pre>
<p>These commands tell Gemini to automatically load these files whenever they exist in the current working directory. This is the key that makes the entire workflow seamless.</p>
<h2 id="heading-step-5-how-it-works">Step 5: How It Works</h2>
<p>Instead of running <code>gemini</code>, use the command you added as alias <code>mygemini</code>.</p>
<p>Here's the magic behind the workflow:</p>
<ol>
<li><p>The alias in your <strong>bashrc/zshrc</strong> will trigger the <code>mygemini.sh</code> script.</p>
</li>
<li><p><strong>Script launches</strong> and presents your project menu</p>
</li>
<li><p><strong>You select</strong> an existing project or create a new one</p>
</li>
<li><p><strong>Context handling</strong> occurs automatically:</p>
<ul>
<li><p>Existing projects: Loads saved context</p>
<ul>
<li>If no context.md is found, it asks for context and creates it</li>
</ul>
</li>
<li><p>New projects: Prompts you to create context</p>
</li>
</ul>
</li>
<li><p><strong>Global instructions</strong> are copied to the project folder</p>
</li>
<li><p><strong>Gemini launches</strong> in the project directory</p>
</li>
<li><p><strong>Automatic loading</strong> happens thanks to the <code>/memory add</code> commands</p>
</li>
<li><p><strong>Gemini is ready</strong> with full context and your preferences</p>
</li>
</ol>
<p>The beauty is that steps 7-8 happen automatically every time, with no manual intervention required.</p>
<h2 id="heading-step-6-verify-its-working">Step 6: Verify It's Working</h2>
<p>To confirm everything is working correctly, try this verification process:</p>
<ol>
<li><p><strong>Create a test project:</strong></p>
<pre><code class="lang-bash"> mygemini
 <span class="hljs-comment"># Select "Create New Project"</span>
 <span class="hljs-comment"># Name it "Test_Project"</span>
 <span class="hljs-comment"># Add context: "This is a test project for verification"</span>
</code></pre>
</li>
<li><p><strong>In the Gemini CLI that opens, ask:</strong></p>
<pre><code class="lang-plaintext"> What are your instructions and context for this session?
</code></pre>
</li>
<li><p><strong>Expected response should include:</strong></p>
<ul>
<li><p>Your global instructions (UK English, professional tone, etc.)</p>
</li>
<li><p>The project context ("This is a test project for verification")</p>
</li>
<li><p>Confirmation that both files were loaded automatically</p>
</li>
</ul>
</li>
<li><p><strong>Test with different projects</strong> to ensure context switches correctly</p>
</li>
</ol>
<h2 id="heading-step-7-sample-directory-structure">Step 7: Sample Directory Structure</h2>
<p>After setting up a few projects, your directory structure should look like this:</p>
<pre><code class="lang-plaintext">~/Dev/AI_Tools/Gemini/
├── instructions.md              # Global Gemini instructions
├── mygemini.sh                  # The automation script
├── Blogs/
│   ├── context.md              # "Help me write engaging blog posts..."
│   └── instructions.md         # (copied automatically)
├── Personal_Writing/
│   ├── context.md              # "Assist with creative writing projects..."
│   └── instructions.md         # (copied automatically)
├── Research_Programming_Go/
│   ├── context.md              # "Go programming research and code review..."
│   └── instructions.md         # (copied automatically)
├── Client_ProjectX/
│   ├── context.md              # "Web development project using React..."
│   └── instructions.md         # (copied automatically)
└── Documentation/
    ├── context.md              # "Technical documentation and API guides..."
    └── instructions.md         # (copied automatically)
</code></pre>
<h2 id="heading-key-advantages">Key Advantages</h2>
<p>This workflow provides several powerful benefits:</p>
<h3 id="heading-zero-setup-time"><strong>🚀 Zero Setup Time</strong></h3>
<p>No more typing "Act as a..." or explaining your preferences every session. Gemini is immediately ready with your context.</p>
<h3 id="heading-project-specific-intelligence"><strong>🎯 Project-Specific Intelligence</strong></h3>
<p>Each project gets tailored context while maintaining your global preferences for tone, style, and language.</p>
<h3 id="heading-consistent-behaviour"><strong>🔄 Consistent Behaviour</strong></h3>
<p>Global instructions ensure Gemini behaves consistently across all projects, while adapting to specific contexts.</p>
<h3 id="heading-scalable-organisation"><strong>📁 Scalable Organisation</strong></h3>
<p>Easy to add new projects as your work evolves. Each project maintains its own context while sharing global settings.</p>
<h3 id="heading-automatic-updates"><strong>⚡ Automatic Updates</strong></h3>
<p>Changes to global instructions automatically propagate to all projects on next launch.</p>
<h3 id="heading-context-persistence"><strong>🔍 Context Persistence</strong></h3>
<p>Project contexts are saved and automatically reloaded, building a knowledge base over time.</p>
<h2 id="heading-extended-use-cases">Extended Use Cases</h2>
<p>This workflow adapts to numerous scenarios:</p>
<h3 id="heading-software-development"><strong>Software Development</strong></h3>
<ul>
<li><p><strong>Frontend Projects</strong>: Context about specific frameworks, design systems, coding standards</p>
</li>
<li><p><strong>Backend Services</strong>: API specifications, database schemas, architectural decisions</p>
</li>
<li><p><strong>DevOps Tasks</strong>: Infrastructure details, deployment procedures, monitoring requirements</p>
</li>
</ul>
<h3 id="heading-content-creation"><strong>Content Creation</strong></h3>
<ul>
<li><p><strong>Blog Writing</strong>: Target audience, brand voice, content guidelines</p>
</li>
<li><p><strong>Technical Documentation</strong>: Product specifications, user personas, complexity levels</p>
</li>
<li><p><strong>Marketing Copy</strong>: Brand guidelines, campaign objectives, target demographics</p>
</li>
</ul>
<h3 id="heading-research-amp-analysis"><strong>Research &amp; Analysis</strong></h3>
<ul>
<li><p><strong>Academic Research</strong>: Research questions, methodology, literature review status</p>
</li>
<li><p><strong>Market Research</strong>: Industry focus, competitor analysis, data sources</p>
</li>
<li><p><strong>Code Reviews</strong>: Project standards, security requirements, performance criteria</p>
</li>
</ul>
<h3 id="heading-personal-projects"><strong>Personal Projects</strong></h3>
<ul>
<li><p><strong>Learning New Technologies</strong>: Current skill level, learning objectives, preferred resources</p>
</li>
<li><p><strong>Side Projects</strong>: Project goals, technology stack, timeline constraints</p>
</li>
<li><p><strong>Creative Writing</strong>: Genre preferences, character development, plot outlines</p>
</li>
</ul>
<h3 id="heading-client-work"><strong>Client Work</strong></h3>
<ul>
<li><p><strong>Project Alpha</strong>: Client requirements, technical constraints, delivery timeline</p>
</li>
<li><p><strong>Project Beta</strong>: Different tech stack, coding standards, communication preferences</p>
</li>
<li><p><strong>Maintenance Work</strong>: Legacy codebase context, known issues, update procedures</p>
</li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>By combining a simple shell script with Gemini's built-in memory system, we've created a CLI workflow that rivals the project management features of web-based AI interfaces. This approach eliminates the friction of context switching while maintaining the power and flexibility of command-line tools.</p>
<p>The key insights that make this work are:</p>
<ol>
<li><p><strong>Separation of concerns</strong>: Global preferences vs. project-specific context</p>
</li>
<li><p><strong>Automation</strong>: Eliminate manual setup through scripting</p>
</li>
<li><p><strong>Leveraging built-in features</strong>: Using Gemini's memory system rather than fighting it</p>
</li>
<li><p><strong>Consistent structure</strong>: Predictable file organisation that scales</p>
</li>
</ol>
<p>This workflow transforms Gemini from a generic tool into a context-aware partner that understands your work, your preferences, and your current focus. Whether you're switching between client projects, exploring new technologies, or working on personal creative endeavours, Gemini is immediately ready to help with the right context and tone.</p>
<p>The next time you need AI assistance using Gemini, you won't waste time explaining your situation or setting preferences. Instead, you'll jump straight into productive conversations with Gemini with preloaded context of your project, your standards, and your goals.</p>
<p><em>Please don't hesitate to leave a comment on how you are using this in your workflows.</em></p>
]]></content:encoded></item><item><title><![CDATA[Part 6: Nginx Reverse Proxy for Clean URLs]]></title><description><![CDATA[Welcome to Part 6 of the Ubuntu home lab series. Now that we have several apps running on different ports, it’s time to simplify access using Nginx as a reverse proxy. This lets us use URLs like http://jellyfin.myserver.home instead of IP:port combos...]]></description><link>https://artofcoding.dev/part-6-nginx-reverse-proxy-for-clean-urls</link><guid isPermaLink="true">https://artofcoding.dev/part-6-nginx-reverse-proxy-for-clean-urls</guid><category><![CDATA[clean-urls]]></category><category><![CDATA[nginx]]></category><category><![CDATA[Reverse Proxy]]></category><category><![CDATA[self hosting]]></category><category><![CDATA[dns]]></category><dc:creator><![CDATA[Febin Joy]]></dc:creator><pubDate>Sun, 06 Jul 2025 14:00:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1748867162942/b5ab10fa-50fd-41d8-84ad-a19a97b360a8.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Welcome to Part 6 of the Ubuntu home lab series. Now that we have several apps running on different ports, it’s time to simplify access using <strong>Nginx</strong> as a reverse proxy. This lets us use URLs like <code>http://jellyfin.myserver.home</code> instead of IP:port combos.</p>
<blockquote>
<p>🧠 Tip: Use your router or hosts file to map custom domains (e.g., <code>myserver.home</code>) to your server’s IP.</p>
</blockquote>
<hr />
<h2 id="heading-step-1-install-nginx">🌐 Step 1: Install Nginx</h2>
<pre><code class="lang-bash">sudo apt update
sudo apt install -y nginx
</code></pre>
<p>Check if it’s running:</p>
<pre><code class="lang-bash">sudo systemctl status nginx
</code></pre>
<p>I decided to install Nginx locally on the server as it would be able to access port 80 of my server and route traffic to various apps/containers.</p>
<hr />
<h2 id="heading-step-2-set-up-config-directory">📁 Step 2: Set Up Config Directory</h2>
<pre><code class="lang-bash">sudo mkdir -p /etc/nginx/conf.d
</code></pre>
<hr />
<h2 id="heading-step-3-create-reverse-proxy-config">📝 Step 3: Create Reverse Proxy Config</h2>
<pre><code class="lang-bash">sudo nano /etc/nginx/conf.d/myserver.conf
</code></pre>
<p>Add entries like the following for each service:</p>
<h3 id="heading-jellyfin">Jellyfin</h3>
<pre><code class="lang-nginx"><span class="hljs-section">server</span> {
  <span class="hljs-attribute">listen</span> <span class="hljs-number">80</span>;
  <span class="hljs-attribute">server_name</span> jellyfin.myserver.home;

  <span class="hljs-attribute">location</span> / {
    <span class="hljs-attribute">proxy_pass</span> http://&lt;your-server-ip&gt;:8096;
    <span class="hljs-attribute">proxy_set_header</span> Host <span class="hljs-variable">$host</span>;
    <span class="hljs-attribute">proxy_set_header</span> X-Real-IP <span class="hljs-variable">$remote_addr</span>;
    <span class="hljs-attribute">proxy_set_header</span> X-Forwarded-For <span class="hljs-variable">$proxy_add_x_forwarded_for</span>;
    <span class="hljs-attribute">proxy_set_header</span> X-Forwarded-Proto <span class="hljs-variable">$scheme</span>;
  }
}
</code></pre>
<p>This will map <a target="_blank" href="http://jellyfin.myserver.home"><code>http://jellyfin.myserver.home</code></a> to <code>http://&lt;your-server-ip&gt;:8096</code></p>
<p>Repeat similar blocks for other apps:</p>
<h3 id="heading-postgresql-pgadmin">PostgreSQL (pgAdmin)</h3>
<pre><code class="lang-nginx"><span class="hljs-section">server</span> {
  <span class="hljs-attribute">listen</span> <span class="hljs-number">80</span>;
  <span class="hljs-attribute">server_name</span> postgres.myserver.home;

  <span class="hljs-attribute">location</span> / {
    <span class="hljs-attribute">proxy_pass</span> http://&lt;your-server-ip&gt;:9876;
    <span class="hljs-attribute">proxy_set_header</span> Host <span class="hljs-variable">$host</span>;
    <span class="hljs-attribute">proxy_set_header</span> X-Real-IP <span class="hljs-variable">$remote_addr</span>;
    <span class="hljs-attribute">proxy_set_header</span> X-Forwarded-For <span class="hljs-variable">$proxy_add_x_forwarded_for</span>;
    <span class="hljs-attribute">proxy_set_header</span> X-Forwarded-Proto <span class="hljs-variable">$scheme</span>;
  }
}
</code></pre>
<h3 id="heading-node-red">Node-RED</h3>
<pre><code class="lang-nginx"><span class="hljs-section">server</span> {
  <span class="hljs-attribute">listen</span> <span class="hljs-number">80</span>;
  <span class="hljs-attribute">server_name</span> nodered.myserver.home;

  <span class="hljs-attribute">location</span> / {
    <span class="hljs-attribute">proxy_pass</span> http://&lt;your-server-ip&gt;:1880;
    <span class="hljs-attribute">proxy_set_header</span> Host <span class="hljs-variable">$host</span>;
    <span class="hljs-attribute">proxy_set_header</span> X-Real-IP <span class="hljs-variable">$remote_addr</span>;
    <span class="hljs-attribute">proxy_set_header</span> X-Forwarded-For <span class="hljs-variable">$proxy_add_x_forwarded_for</span>;
    <span class="hljs-attribute">proxy_set_header</span> X-Forwarded-Proto <span class="hljs-variable">$scheme</span>;
  }
}
</code></pre>
<h3 id="heading-homarr">Homarr</h3>
<pre><code class="lang-nginx"><span class="hljs-section">server</span> {
  <span class="hljs-attribute">listen</span> <span class="hljs-number">80</span>;
  <span class="hljs-attribute">server_name</span> dashboard.myserver.home;

  <span class="hljs-attribute">location</span> / {
    <span class="hljs-attribute">proxy_pass</span> http://&lt;your-server-ip&gt;:7575;
    <span class="hljs-attribute">proxy_set_header</span> Host <span class="hljs-variable">$host</span>;
    <span class="hljs-attribute">proxy_set_header</span> X-Real-IP <span class="hljs-variable">$remote_addr</span>;
    <span class="hljs-attribute">proxy_set_header</span> X-Forwarded-For <span class="hljs-variable">$proxy_add_x_forwarded_for</span>;
    <span class="hljs-attribute">proxy_set_header</span> X-Forwarded-Proto <span class="hljs-variable">$scheme</span>;
  }
}
</code></pre>
<hr />
<h2 id="heading-step-4-test-and-apply-nginx-config">🔍 Step 4: Test and Apply Nginx Config</h2>
<h3 id="heading-1-test-configuration">1. Test configuration:</h3>
<pre><code class="lang-bash">sudo nginx -t
</code></pre>
<h3 id="heading-2-restart-nginx">2. Restart Nginx:</h3>
<pre><code class="lang-bash">sudo systemctl restart nginx
</code></pre>
<hr />
<h2 id="heading-step-5-add-hostname-mapping-on-client-machines">🧭 Step 5: Add Hostname Mapping (on client machines)</h2>
<p>Edit <code>/etc/hosts</code> (on Linux/macOS) or <code>C:\Windows\System32\drivers\etc\hosts</code> (on Windows) and add:</p>
<pre><code class="lang-bash">192.168.1.100 jellyfin.myserver.home postgres.myserver.home nodered.myserver.home dashboard.myserver.home
</code></pre>
<blockquote>
<p>Replace <code>192.168.1.100</code> with your server’s actual IP.</p>
</blockquote>
<p>Now you can access:</p>
<ul>
<li><p><code>http://jellyfin.myserver.home</code></p>
</li>
<li><p><code>http://postgres.myserver.home</code></p>
</li>
<li><p><code>http://nodered.myserver.home</code></p>
</li>
<li><p><code>http://dashboard.myserver.home</code></p>
</li>
</ul>
<hr />
<h2 id="heading-final-notes">✅ Final Notes</h2>
<p>Your home lab is now:</p>
<ul>
<li><p>Secure and hardened</p>
</li>
<li><p>Running in containers</p>
</li>
<li><p>Easily accessible via custom URLs</p>
</li>
</ul>
<p>You can keep extending it with apps like Kavita, FreshRSS, Calibre-Web, or even GitLab. Just follow the same Podman + volume + Nginx proxy pattern.</p>
<p>Thanks for following along! 🧑‍💻</p>
<blockquote>
<p>Feel free to share your thoughts or improvements at <a target="_blank" href="https://artofcoding.dev">artofcoding.dev</a>!</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Part 5: Advanced Containers – pgAdmin, Node-RED, and Homarr]]></title><description><![CDATA[Welcome to Part 5 of the Ubuntu home lab series. This part expands on our Podman setup by deploying more advanced services inside containers. We’ll run PostgreSQL with pgAdmin in a shared Pod, Node-RED for workflows, and Homarr for a beautiful home l...]]></description><link>https://artofcoding.dev/part-5-advanced-containers-pgadmin-node-red-and-homarr</link><guid isPermaLink="true">https://artofcoding.dev/part-5-advanced-containers-pgadmin-node-red-and-homarr</guid><category><![CDATA[homarr]]></category><category><![CDATA[podman]]></category><category><![CDATA[pgAdmin]]></category><category><![CDATA[PostgreSQL]]></category><category><![CDATA[postgres]]></category><category><![CDATA[Node-Red]]></category><category><![CDATA[containers]]></category><dc:creator><![CDATA[Febin Joy]]></dc:creator><pubDate>Sun, 29 Jun 2025 14:00:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1748867150249/318407dc-3e07-4d89-9021-48829a374b67.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Welcome to Part 5 of the Ubuntu home lab series. This part expands on our Podman setup by deploying more advanced services inside containers. We’ll run PostgreSQL with pgAdmin in a shared Pod, Node-RED for workflows, and Homarr for a beautiful home lab dashboard.</p>
<hr />
<h2 id="heading-step-1-set-up-postgresql-pgadmin-in-a-pod">🐘 Step 1: Set Up PostgreSQL + pgAdmin in a Pod</h2>
<p>Podman supports pods, similar to Kubernetes. Containers in a pod share network and can easily talk to each other.</p>
<h3 id="heading-1-create-the-pod">1. Create the pod</h3>
<pre><code class="lang-bash">podman pod create --name postgre-sql -p 9876:80
</code></pre>
<p>This exposes port 80 of the pod to port 9876 on the host.</p>
<h3 id="heading-2-set-up-pgadmin">2. Set up pgAdmin</h3>
<pre><code class="lang-bash">mkdir -p ~/.config/containers/pgadmin
chmod -R 755 ~/.config/containers/pgadmin

podman volume create --opt device=<span class="hljs-variable">$HOME</span>/.config/containers/pgadmin \
  --opt <span class="hljs-built_in">type</span>=none --opt o=<span class="hljs-built_in">bind</span> pgadmin-volume

podman run --pod postgre-sql \
  -e <span class="hljs-string">'PGADMIN_DEFAULT_EMAIL=youradmin@yourdomain.com'</span> \
  -e <span class="hljs-string">'PGADMIN_DEFAULT_PASSWORD=passWoRd'</span> \
  -v pgadmin-volume:/var/lib/pgadmin \
  --name pgadmin \
  -d docker.io/dpage/pgadmin4:latest
</code></pre>
<p>This will pull the pgAdmin docker image and create a podman container in the pod we created earlier. You can use the cockpit to view the status.</p>
<h3 id="heading-3-set-up-postgresql">3. Set up PostgreSQL</h3>
<pre><code class="lang-bash">mkdir -p ~/.config/containers/postgres
chmod -R 755 ~/.config/containers/postgres

podman volume create --opt device=<span class="hljs-variable">$HOME</span>/.config/containers/postgres \
  --opt <span class="hljs-built_in">type</span>=none --opt o=<span class="hljs-built_in">bind</span> postgres-volume

podman run --name postgredb \
  --pod postgre-sql \
  -d -e POSTGRES_USER=admin \
  -e POSTGRES_PASSWORD=passWoRd \
  -v postgres-volume:/var/lib/postgresql/data:rw,z \
  docker.io/library/postgres:latest
</code></pre>
<p>This will pull the pgAdmin docker image and create a podman container in the pod we created earlier. You can use the cockpit to view the status.</p>
<h3 id="heading-4-allow-access">4. Allow access</h3>
<pre><code class="lang-bash">sudo iptables -A INPUT -p tcp --dport 9876 -j ACCEPT
sudo iptables-save | sudo tee /etc/iptables/rules.v4
</code></pre>
<h3 id="heading-5-access-and-configure">5. Access and configure</h3>
<ul>
<li><p>Access the pgAdmin web interface by navigating to : <code>http://&lt;your-server-ip&gt;:9876</code></p>
</li>
<li><p>In pgAdmin, add a new server:</p>
<ul>
<li><p><strong>Name</strong>: <code>mypgdb</code></p>
</li>
<li><p><strong>Host</strong>: <code>0.0.0.0</code></p>
</li>
<li><p><strong>Username/Password</strong>: match POSTGRES_USER and POSTGRES_PASSWORD</p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-6-enable-auto-start">6. Enable auto-start</h3>
<p>Edit your startup script:</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">"podman pod start postgre-sql"</span> &gt;&gt; ~/.config/containers/start.sh
</code></pre>
<hr />
<h2 id="heading-step-2-run-node-red">🔗 Step 2: Run Node-RED</h2>
<h3 id="heading-1-create-directory-and-volume">1. Create directory and volume</h3>
<pre><code class="lang-bash">mkdir -p ~/.config/containers/nodered
chmod -R 755 ~/.config/containers/nodered

podman volume create --opt device=<span class="hljs-variable">$HOME</span>/.config/containers/nodered \
  --opt <span class="hljs-built_in">type</span>=none --opt o=<span class="hljs-built_in">bind</span> nodered-data
</code></pre>
<h3 id="heading-2-run-the-container">2. Run the container</h3>
<pre><code class="lang-bash">podman run -d \
  -p 1880:1880 \
  --name nodered \
  -v nodered-data:/data \
  --restart always \
  docker.io/nodered/node-red:latest
</code></pre>
<h3 id="heading-3-allow-access">3. Allow access</h3>
<pre><code class="lang-bash">sudo iptables -A INPUT -p tcp --dport 1880 -j ACCEPT
sudo iptables-save | sudo tee /etc/iptables/rules.v4
</code></pre>
<h3 id="heading-4-enable-auto-start">4. Enable auto-start</h3>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">"podman start nodered"</span> &gt;&gt; ~/.config/containers/start.sh
</code></pre>
<p>Access: <code>http://&lt;your-server-ip&gt;:1880</code></p>
<hr />
<h2 id="heading-step-3-set-up-homarr-dashboard">🧭 Step 3: Set Up Homarr Dashboard</h2>
<p>Homarr is a wonderful dashboard that will make your home lab server more accessible and easy to use. It provides a beautiful UI to access all your self-hosted apps.</p>
<h3 id="heading-1-create-directories">1. Create directories</h3>
<pre><code class="lang-bash">mkdir -p ~/.config/containers/homarr/configs
mkdir -p ~/.config/containers/homarr/icons
mkdir -p ~/.config/containers/homarr/data
chmod -R 755 ~/.config/containers/homarr
</code></pre>
<h3 id="heading-2-create-volumes">2. Create volumes</h3>
<pre><code class="lang-bash">podman volume create --opt device=<span class="hljs-variable">$HOME</span>/.config/containers/homarr/configs --opt <span class="hljs-built_in">type</span>=none --opt o=<span class="hljs-built_in">bind</span> homarr-configs
podman volume create --opt device=<span class="hljs-variable">$HOME</span>/.config/containers/homarr/icons --opt <span class="hljs-built_in">type</span>=none --opt o=<span class="hljs-built_in">bind</span> homarr-icons
podman volume create --opt device=<span class="hljs-variable">$HOME</span>/.config/containers/homarr/data --opt <span class="hljs-built_in">type</span>=none --opt o=<span class="hljs-built_in">bind</span> homarr-data
</code></pre>
<h3 id="heading-3-run-the-container">3. Run the container</h3>
<pre><code class="lang-bash">podman run -d \
  -p 7575:7575 \
  --name homarr \
  -v homarr-configs:/app/data/configs \
  -v homarr-icons:/app/public/icons \
  -v homarr-data:/data \
  --restart unless-stopped \
  -e DEFAULT_COLOR_SCHEME=dark \
  ghcr.io/ajnart/homarr:latest
</code></pre>
<h3 id="heading-4-allow-access-1">4. Allow access</h3>
<pre><code class="lang-bash">sudo iptables -A INPUT -p tcp --dport 7575 -j ACCEPT
sudo iptables-save | sudo tee /etc/iptables/rules.v4
</code></pre>
<h3 id="heading-5-enable-auto-start">5. Enable auto-start</h3>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-string">"podman start homarr"</span> &gt;&gt; ~/.config/containers/start.sh
</code></pre>
<p>Access: <code>http://&lt;your-server-ip&gt;:7575</code></p>
<hr />
<p>Coming up next in Part 6: we’ll simplify access to all these services using Nginx as a reverse proxy so you can use friendly URLs like <a target="_blank" href="http://jellyfin.myserver.home"><code>http://jellyfin.myserver.home</code></a> instead of remembering port numbers.</p>
<p>Stay tuned for <strong>Part 6: Nginx Reverse Proxy for Clean URLs</strong>!</p>
]]></content:encoded></item><item><title><![CDATA[Part 4: Running Containers with Podman and Cockpit]]></title><description><![CDATA[Welcome to Part 4 of the Ubuntu home lab series. Now that our server is secure, it's time to start running services in containers. We'll use Podman (a daemonless alternative to Docker) and Cockpit (a web-based UI) to make management easy. My strategy...]]></description><link>https://artofcoding.dev/part-4-running-containers-with-podman-and-cockpit</link><guid isPermaLink="true">https://artofcoding.dev/part-4-running-containers-with-podman-and-cockpit</guid><category><![CDATA[containers]]></category><category><![CDATA[podman]]></category><category><![CDATA[cockpit]]></category><category><![CDATA[self hosting]]></category><category><![CDATA[linux-server]]></category><dc:creator><![CDATA[Febin Joy]]></dc:creator><pubDate>Sun, 22 Jun 2025 14:00:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1748867138770/5202bf36-a2cf-41bd-b2fe-258d72b9bfd1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Welcome to Part 4 of the Ubuntu home lab series. Now that our server is secure, it's time to start running services in containers. We'll use <strong>Podman</strong> (a daemonless alternative to Docker) and <strong>Cockpit</strong> (a web-based UI) to make management easy. My strategy is to use containers whenever possible(e.g. PostgreSQL DB). If containerising is not possible, use a VM.</p>
<p>In this part, we'll:</p>
<ul>
<li><p>Install and configure Podman</p>
</li>
<li><p>Set up Cockpit with container and VM support</p>
</li>
<li><p>Run our first container (Jellyfin)</p>
</li>
<li><p>Set up persistent volumes and startup scripts</p>
</li>
</ul>
<hr />
<h2 id="heading-step-1-install-podman">🧱 Step 1: Install Podman</h2>
<p>Podman is a daemonless container engine that allows you to run containers as non-root users, enhancing security and flexibility. It's designed to be compatible with Docker commands, making it easy to transition between the two. Additionally, Podman can pull and run Docker images, providing seamless integration with existing Docker workflows.</p>
<p>In a home lab setup, Podman offers the advantage of being managed easily through Cockpit, which we have already installed. This simplifies container management without needing additional tools like Portainer, which Docker requires for a web-based UI.</p>
<pre><code class="lang-bash">sudo apt update
sudo apt install -y podman podman-remote
</code></pre>
<p>You can confirm installation with:</p>
<pre><code class="lang-bash">podman --version
</code></pre>
<hr />
<h2 id="heading-step-2-install-cockpit-and-plugins">🌐 Step 2: Install Cockpit and Plugins</h2>
<p>Cockpit is a web-based interface for managing Linux servers, providing a graphical dashboard to monitor and control various aspects of system administration, such as storage, network settings, and system performance. Cockpit allows you to install various plugins to manage VMs, Podman containers, View logs, manage users etc from a remote computer on the same network with ease.</p>
<pre><code class="lang-bash">sudo apt install -y \
  qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils \
  cockpit cockpit-sosreport cockpit-machines \
  virt-manager cockpit-podman
</code></pre>
<p>Enable and start Cockpit:</p>
<pre><code class="lang-bash">sudo systemctl <span class="hljs-built_in">enable</span> --now cockpit.socket
</code></pre>
<p>Cockpit will now be accessible at:</p>
<pre><code class="lang-bash">https://&lt;your-server-ip&gt;:9090
</code></pre>
<p>Use your server’s username/password to log in.</p>
<blockquote>
<p>🔒 You can optionally configure SSL certificates for Cockpit.</p>
</blockquote>
<p>Add firewall rule:</p>
<pre><code class="lang-bash">sudo iptables -A INPUT -p tcp --dport 9090 -j ACCEPT
sudo iptables-save | sudo tee /etc/iptables/rules.v4
</code></pre>
<p>Cockpit is now available using <code>https://&lt;server-ip&gt;:9090</code> from any machine in your home lab server’s network. Login with your server username and password.</p>
<hr />
<h2 id="heading-step-3-run-your-first-container-jellyfin">🎬 Step 3: Run Your First Container (Jellyfin)</h2>
<h3 id="heading-1-pull-the-image">1. Pull the image</h3>
<p>I have chosen to install Jellyfin for the demonstration. Jellyfin is a free media system that allows you to manage and stream your media on your local network. You can follow the same method to spin up any container image.</p>
<pre><code class="lang-bash">podman pull docker.io/jellyfin/jellyfin:latest
</code></pre>
<p>Confirm that the image is pulled:</p>
<pre><code class="lang-bash">podman images
</code></pre>
<h3 id="heading-2-create-directories">2. Create directories</h3>
<pre><code class="lang-bash">mkdir -p ~/.config/containers/jellyfin/config
mkdir -p ~/.config/containers/jellyfin/cache
mkdir -p ~/data/media
chmod -R 755 ~/.config/containers/jellyfin ~/data/media
</code></pre>
<h3 id="heading-3-create-persistent-volumes">3. Create persistent volumes</h3>
<p>A Podman volume is a section of the host file system that is attached to a running container. It allows data to persist and be shared between containers.</p>
<pre><code class="lang-bash">podman volume create --opt device=<span class="hljs-variable">$HOME</span>/.config/containers/jellyfin/config --opt <span class="hljs-built_in">type</span>=none --opt o=<span class="hljs-built_in">bind</span> jellyfin-config
podman volume create --opt device=<span class="hljs-variable">$HOME</span>/.config/containers/jellyfin/cache --opt <span class="hljs-built_in">type</span>=none --opt o=<span class="hljs-built_in">bind</span> jellyfin-cache
podman volume create --opt device=<span class="hljs-variable">$HOME</span>/data/media --opt <span class="hljs-built_in">type</span>=none --opt o=<span class="hljs-built_in">bind</span> jellyfin-media
</code></pre>
<p>Creating the volume and passing it is always recommended as it helps to identify the volume when we list using <code>podman volume ls</code> and remove using <code>podman volume rm &lt;imagename&gt;</code>. If we don’t create explicitly, podman creates automatically and the names would not be easily identifiable.</p>
<p>Use <code>podman volume rm &lt;volume name&gt;</code> to delete a volume if required.</p>
<h3 id="heading-4-run-the-container">4. Run the container</h3>
<pre><code class="lang-bash">podman run -d \
  --name jellyfin \
  --restart=always \
  -p 8096:8096 \
  -p 8920:8920 \
  -v jellyfin-config:/config \
  -v jellyfin-cache:/cache \
  -v jellyfin-media:/media \
  jellyfin/jellyfin:latest
</code></pre>
<h3 id="heading-5-allow-traffic">5. Allow traffic</h3>
<pre><code class="lang-bash">sudo iptables -A INPUT -p tcp --dport 8096 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 8920 -j ACCEPT
sudo iptables-save | sudo tee /etc/iptables/rules.v4
</code></pre>
<p>This will create a Podman container with the name <code>jellyfin</code> which runs on your new server. You can upload all the media to <code>~/data/media</code> folder and organise them in Jellyfin.</p>
<p>Access Jellyfin:</p>
<pre><code class="lang-bash">http://&lt;your-server-ip&gt;:8096
</code></pre>
<p><em>If the Jellyfin wizard does not come up, try accessing</em> <code>http://&lt;server-ip&gt;:8096/web/index.html#!/wizardstart.html</code><em>.</em></p>
<hr />
<h2 id="heading-step-4-auto-start-containers-on-boot">🔁 Step 4: Auto-start Containers on Boot</h2>
<p>Podman is daemonless, so containers won’t auto-start after reboot by default. Let’s fix that with a simple systemd service.</p>
<h3 id="heading-1-create-a-startup-script">1. Create a startup script</h3>
<pre><code class="lang-bash">mkdir -p ~/.config/containers
nano ~/.config/containers/start.sh
</code></pre>
<p>Example content:</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>
podman start jellyfin
</code></pre>
<p>Make it executable:</p>
<pre><code class="lang-bash">chmod +x ~/.config/containers/start.sh
</code></pre>
<h3 id="heading-2-create-a-systemd-service">2. Create a systemd service</h3>
<pre><code class="lang-bash">sudo nano /etc/systemd/system/start-containers.service
</code></pre>
<p>Paste:</p>
<pre><code class="lang-ini"><span class="hljs-section">[Unit]</span>
<span class="hljs-attr">Description</span>=Start Podman Containers
<span class="hljs-attr">After</span>=network.target

<span class="hljs-section">[Service]</span>
<span class="hljs-attr">Environment</span>=<span class="hljs-string">"XDG_RUNTIME_DIR=/run/user/1000"</span>
<span class="hljs-attr">ExecStartPre</span>=/bin/sleep <span class="hljs-number">10</span>
<span class="hljs-attr">ExecStart</span>=/bin/bash /home/&lt;your-username&gt;/.config/containers/start.sh
<span class="hljs-attr">User</span>=&lt;your-username&gt;
<span class="hljs-attr">Restart</span>=always

<span class="hljs-section">[Install]</span>
<span class="hljs-attr">WantedBy</span>=default.target
</code></pre>
<blockquote>
<p>Replace <code>&lt;your-username&gt;</code> accordingly.</p>
</blockquote>
<p>Enable and start the service:</p>
<pre><code class="lang-bash">sudo systemctl <span class="hljs-built_in">enable</span> start-containers.service
sudo systemctl start start-containers.service
</code></pre>
<hr />
<p>In the next part, we’ll go further with multi-container pods using Podman. We’ll set up PostgreSQL + pgAdmin, Node-RED, and Homarr for managing your homelab.</p>
<p>Stay tuned for <strong>Part 5: Advanced Containers – pgAdmin, Node-RED, and Homarr</strong>!</p>
]]></content:encoded></item><item><title><![CDATA[Part 3: Securing and Hardening the Server]]></title><description><![CDATA[Welcome to Part 3 of the Ubuntu home lab series. Now that we have a solid base system with essential tools, it's time to focus on security. In this part, we'll:

Sync time with NTP

Enable automatic security updates

Harden SSH

Configure firewall ru...]]></description><link>https://artofcoding.dev/part-3-securing-and-hardening-the-server</link><guid isPermaLink="true">https://artofcoding.dev/part-3-securing-and-hardening-the-server</guid><category><![CDATA[Security]]></category><category><![CDATA[firewall]]></category><category><![CDATA[ssh]]></category><category><![CDATA[fail2ban]]></category><category><![CDATA[linux-security]]></category><dc:creator><![CDATA[Febin Joy]]></dc:creator><pubDate>Sun, 15 Jun 2025 14:00:24 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1748866975980/90d86071-7372-4dc1-8092-ef437f135685.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Welcome to Part 3 of the Ubuntu home lab series. Now that we have a solid base system with essential tools, it's time to focus on security. In this part, we'll:</p>
<ul>
<li><p>Sync time with NTP</p>
</li>
<li><p>Enable automatic security updates</p>
</li>
<li><p>Harden SSH</p>
</li>
<li><p>Configure firewall rules with iptables</p>
</li>
<li><p>Install Auditd, Fail2Ban, and Lynis</p>
</li>
</ul>
<blockquote>
<p>🛡️ Security is a process, not a one-time task. These steps form a solid baseline.</p>
</blockquote>
<hr />
<h2 id="heading-step-1-setup-time-synchronisation-ntp">🕒 Step 1: Setup Time Synchronisation (NTP)</h2>
<p>Ubuntu uses <code>systemd-timesyncd</code> for NTP.</p>
<ol>
<li><strong>Check if enabled:</strong></li>
</ol>
<pre><code class="lang-bash">systemctl status systemd-timesyncd
</code></pre>
<ol start="2">
<li><strong>Start and enable it:</strong></li>
</ol>
<pre><code class="lang-bash">sudo systemctl start systemd-timesyncd
sudo systemctl <span class="hljs-built_in">enable</span> systemd-timesyncd
</code></pre>
<ol start="3">
<li><strong>Check sync status:</strong></li>
</ol>
<pre><code class="lang-bash">timedatectl status
</code></pre>
<ol start="4">
<li><p><strong>Configure NTP servers:</strong></p>
<p> Having <code>systemd-timesyncd</code> will not sync time on the server. We need to configure it to update system time automatically by specifying which NTP server we need to use.</p>
<p> By default, <code>systemd-timesyncd</code> uses NTP servers configured in <code>/etc/systemd/timesyncd.conf</code>. We can modify or add custom NTP servers.</p>
</li>
</ol>
<pre><code class="lang-bash">sudo nano /etc/systemd/timesyncd.conf
</code></pre>
<p>Add or modify the NTP server settings under <code>[Time]</code>. Use the NTP server of your choice. For example:</p>
<pre><code class="lang-ini"><span class="hljs-section">[Time]</span>
<span class="hljs-attr">NTP</span>=<span class="hljs-number">0</span>.au.pool.ntp.org
<span class="hljs-attr">FallbackNTP</span>=ntp.ubuntu.com
</code></pre>
<ol start="5">
<li><strong>Restart the service:</strong></li>
</ol>
<pre><code class="lang-bash">sudo systemctl restart systemd-timesyncd
</code></pre>
<ol start="6">
<li><strong>Set the correct timezone:</strong></li>
</ol>
<pre><code class="lang-bash">timedatectl list-timezones
sudo timedatectl set-timezone Australia/Melbourne
</code></pre>
<ol start="7">
<li><strong>Verify the timezone and synchronisation status:</strong></li>
</ol>
<pre><code class="lang-bash">timedatectl status
</code></pre>
<p>With this, we would have the home lab server’s time synchronised automatically.</p>
<hr />
<h2 id="heading-step-2-enable-automatic-security-updates">🔄 Step 2: Enable Automatic Security Updates</h2>
<pre><code class="lang-bash">sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
</code></pre>
<p>This configures Ubuntu to install security updates automatically.</p>
<hr />
<h2 id="heading-step-3-harden-ssh">🔐 Step 3: Harden SSH</h2>
<ol>
<li><strong>Edit SSH configuration:</strong></li>
</ol>
<pre><code class="lang-bash">sudo nano /etc/ssh/sshd_config
</code></pre>
<p>Set the following options:</p>
<pre><code class="lang-ini">Port 7890               <span class="hljs-comment"># Use a non-default port</span>
PermitRootLogin no
MaxAuthTries 4
PasswordAuthentication no
PermitEmptyPasswords no
PubkeyAuthentication yes
AllowUsers your_username
</code></pre>
<ol start="2">
<li><strong>Optional</strong>: Restrict SSH to a group:</li>
</ol>
<pre><code class="lang-bash">sudo groupadd ssh_users
sudo usermod -aG ssh_users your_username
</code></pre>
<p>Then use <code>AllowGroups ssh_users</code> in the SSH config.</p>
<ol start="3">
<li><strong>Restart SSH:</strong></li>
</ol>
<pre><code class="lang-bash">sudo systemctl restart ssh
</code></pre>
<hr />
<h2 id="heading-step-4-configure-firewall-with-iptables">🔥 Step 4: Configure Firewall with iptables</h2>
<p>We have already installed Iptables in a step earlier. Now it is time to add some rules and configure it to harden our home lab server.</p>
<ol>
<li><strong>View current rules:</strong></li>
</ol>
<pre><code class="lang-bash">sudo iptables -L
</code></pre>
<ol start="2">
<li><strong>Set default policies:</strong></li>
</ol>
<p>The first thing to do is to drop all incoming traffic by default and allow output communication. We will open up some ports and communication in upcoming steps. This will make the server reject any unwanted requests.</p>
<pre><code class="lang-bash">sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT
</code></pre>
<ol start="3">
<li><strong>Allow necessary traffic:</strong></li>
</ol>
<pre><code class="lang-bash"><span class="hljs-comment"># SSH (replace 7890 with your SSH port)</span>
sudo iptables -A INPUT -p tcp --dport 7890 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 7890 -m conntrack --ctstate NEW -m recent --<span class="hljs-built_in">set</span>
sudo iptables -A INPUT -p tcp --dport 7890 -m conntrack --ctstate NEW -m recent --update --seconds 60 --hitcount 4 -j DROP

<span class="hljs-comment"># HTTP/HTTPS</span>
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT

<span class="hljs-comment"># Loopback and existing connections</span>
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A OUTPUT -o lo -j ACCEPT
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
</code></pre>
<p>We would be running some web applications in this server and default ports for HTTP and HTTPS communication should be left open.</p>
<p>Similarly, loop back traffic is generated between processes on the machine and is typically critical to the operation of the system. e.g. If we have a PostgreSQL DB and a web app, and they communicate on various ports. Since we are closing down a lot of traffic, it should not impact the running of these apps or the server.</p>
<ol start="4">
<li><strong>Save rules:</strong></li>
</ol>
<p>These rules which we applied would not persist when we reboot the server. For them to stay, we need to ensure the rules persist after a reboot, save them to a file:</p>
<pre><code class="lang-bash">sudo mkdir -p /etc/iptables
sudo chown root:root /etc/iptables
sudo chmod 755 /etc/iptables
sudo iptables-save | sudo tee /etc/iptables/rules.v4
</code></pre>
<ol start="5">
<li><strong>Create systemd service to restore on boot:</strong></li>
</ol>
<p>Now that the rules are saved, we need to reload it every time the computer boots up. Create a <code>systemd</code> service to load the rules automatically on boot.</p>
<pre><code class="lang-bash">sudo nano /etc/systemd/system/iptables.service
</code></pre>
<p>Paste:</p>
<pre><code class="lang-ini"><span class="hljs-section">[Unit]</span>
<span class="hljs-attr">Description</span>=Packet Filtering Framework
<span class="hljs-attr">DefaultDependencies</span>=<span class="hljs-literal">no</span>
<span class="hljs-attr">Before</span>=network-pre.target
<span class="hljs-attr">Wants</span>=network-pre.target

<span class="hljs-section">[Service]</span>
<span class="hljs-attr">Type</span>=<span class="hljs-literal">on</span>eshot
<span class="hljs-attr">ExecStart</span>=/sbin/iptables-restore /etc/iptables/rules.v4
<span class="hljs-attr">ExecReload</span>=/sbin/iptables-restore /etc/iptables/rules.v4
<span class="hljs-attr">ExecStop</span>=/sbin/iptables -F
<span class="hljs-attr">RemainAfterExit</span>=<span class="hljs-literal">yes</span>

<span class="hljs-section">[Install]</span>
<span class="hljs-attr">WantedBy</span>=multi-user.target
</code></pre>
<ol start="6">
<li><strong>Enable and start service:</strong></li>
</ol>
<pre><code class="lang-bash">sudo systemctl <span class="hljs-built_in">enable</span> iptables
sudo systemctl start iptables
</code></pre>
<p>If the service is already running, restart it.</p>
<pre><code class="lang-bash">sudo systemctl restart iptables
sudo systemctl restart ssh
</code></pre>
<hr />
<h2 id="heading-step-5-install-security-tools">📋 Step 5: Install Security Tools</h2>
<h3 id="heading-auditd-system-audit-logs">Auditd - System Audit Logs</h3>
<p>Auditd (Audit Daemon) is a powerful Linux auditing system that tracks and logs security-relevant events, such as file accesses and system calls, for detailed monitoring and analysis. Use <code>auditd</code> to monitor and log system events. Install it using the following:</p>
<pre><code class="lang-bash">sudo apt install -y auditd
sudo systemctl <span class="hljs-built_in">enable</span> auditd
sudo systemctl start auditd
</code></pre>
<h3 id="heading-fail2ban-ban-ips-on-failed-logins">Fail2Ban - Ban IPs on Failed Logins</h3>
<p>Fail2Ban is a security tool that helps protect your server against brute force attacks. It works by monitoring log files for failed login attempts and other suspicious activities, and then temporarily or permanently bans IP addresses that exhibit these behaviours by modifying firewall rules. Install Fail2ban using the steps below to protect against brute-force attacks:</p>
<pre><code class="lang-bash">sudo apt install -y fail2ban
sudo systemctl <span class="hljs-built_in">enable</span> fail2ban
sudo systemctl start fail2ban
</code></pre>
<h3 id="heading-lynis-security-auditing">Lynis - Security Auditing</h3>
<p>Run this after setting up all your services.</p>
<pre><code class="lang-bash">sudo apt install -y lynis
sudo lynis audit system
</code></pre>
<p>Optional packages (for passing more checks):</p>
<pre><code class="lang-bash">sudo apt install libpam-tmpdir apt-listchanges
</code></pre>
<h2 id="heading-step-6-configure-sftp-access-securely">📂 Step 6: Configure SFTP Access Securely</h2>
<p>SFTP allows secure file transfer over SSH. If you're running your SSH server on a custom port (e.g., 7890), SFTP will use the same.</p>
<p>1. <strong>Add iptables rule for SFTP (same as SSH port)</strong></p>
<pre><code class="lang-bash">sudo iptables -A INPUT -p tcp --dport 7890 -j ACCEPT
sudo iptables-save | sudo tee /etc/iptables/rules.v4
</code></pre>
<p>2. <strong>Restart iptables</strong></p>
<pre><code class="lang-bash">sudo systemctl restart iptables
</code></pre>
<ol start="3">
<li><strong>Verify SSH is listening on the correct port:</strong></li>
</ol>
<pre><code class="lang-bash">sudo netstat -tuln | grep 7890
<span class="hljs-comment"># Expected output: something like</span>
<span class="hljs-comment"># tcp   0  0 0.0.0.0:7890   0.0.0.0:*   LISTEN</span>
</code></pre>
<ol start="4">
<li>Test SFTP Client (e.g., FileZilla):</li>
</ol>
<p>In the SFTP client (e.g., FileZilla), use the following configuration:</p>
<ul>
<li><p>Protocol: SFTP - SSH File Transfer Protocol</p>
</li>
<li><p>Host: The home lab server's IP or hostname</p>
</li>
<li><p>Port: <code>7890</code></p>
</li>
<li><p>User: your SSH login user</p>
</li>
<li><p>Key file: Use your private key (e.g. <code>~/.ssh/id_ed25519</code>)</p>
</li>
</ul>
<blockquote>
<p>💡 If your key is in <code>.ppk</code> format (used by PuTTY), convert it to OpenSSH format before using with FileZilla.</p>
</blockquote>
<hr />
<p>With this, your server is now far more secure. In the next part, we’ll begin deploying containerised apps with Podman and Cockpit.</p>
<p>Stay tuned for <strong>Part 4: Running Containers with Podman and Cockpit</strong>!</p>
]]></content:encoded></item><item><title><![CDATA[Part 2: Essential Terminal Tools for Productivity]]></title><description><![CDATA[Welcome to Part 2 of the Ubuntu home lab setup series. In this section, we’ll focus on making the terminal experience powerful and developer-friendly. We’ll install popular utilities, configure a rich shell environment with Zsh, and set up Neovim and...]]></description><link>https://artofcoding.dev/part-2-essential-terminal-tools-for-productivity</link><guid isPermaLink="true">https://artofcoding.dev/part-2-essential-terminal-tools-for-productivity</guid><category><![CDATA[terminal]]></category><category><![CDATA[zsh]]></category><category><![CDATA[neovim]]></category><category><![CDATA[tmux]]></category><category><![CDATA[developer-setup]]></category><dc:creator><![CDATA[Febin Joy]]></dc:creator><pubDate>Sun, 08 Jun 2025 14:00:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1748866851140/ada8d28d-278b-4cea-856d-9cc8c12aedec.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Welcome to Part 2 of the Ubuntu home lab setup series. In this section, we’ll focus on making the terminal experience powerful and developer-friendly. We’ll install popular utilities, configure a rich shell environment with Zsh, and set up Neovim and TMUX.</p>
<hr />
<h2 id="heading-step-1-install-utilities">🛠️ Step 1: Install Utilities</h2>
<p>Install a collection of essential terminal tools:</p>
<pre><code class="lang-bash">sudo apt install -y \
  net-tools \
  zsh \
  bat \
  unzip \
  ripgrep \
  grep \
  xclip \
  htop \
  ranger \
  iptables \
  fzf
</code></pre>
<ul>
<li><p><code>net-tools</code>: A collection of networking tools, which includes some of the popular tools like <code>ifconfig</code> and <code>netstat</code>. They are very handy in managing network interfaces and connections.</p>
</li>
<li><p><code>zsh</code>: A powerful shell which complements bash functionality with a strong scripting capability and personalisation options.</p>
</li>
<li><p><code>bat</code>: Better <code>cat</code> with syntax highlighting.</p>
</li>
<li><p><code>unzip</code>: Utility for unpacking ZIP files.</p>
</li>
<li><p><code>ripgrep</code> and <code>fzf</code>: Search and fuzzy finding.</p>
</li>
<li><p><code>grep</code>: Another search tool for searching plain-text data on the command line for lines that match a regular expression</p>
</li>
<li><p><code>xclip</code>: A command line interface to the X11 clipboard, which can be used to copy and paste text or files. If you install NeoVim, this is a must-have to copy text to and from NeoVim out of the terminal.</p>
</li>
<li><p><code>htop</code>: Interactive process viewer.</p>
</li>
<li><p><code>ranger</code>: Console file manager.</p>
</li>
<li><p><code>iptables</code>: It is a Linux command line utility to manage the Linux kernel firewall. It is implemented within the <code>netfilter</code> framework. We can define rules to either accept a packet or reject it.</p>
</li>
</ul>
<hr />
<h2 id="heading-step-2-install-lazygit">🌀 Step 2: Install LazyGit</h2>
<p>LazyGit is a simple terminal UI for Git:</p>
<pre><code class="lang-bash">LAZYGIT_VERSION=$(curl -s <span class="hljs-string">"https://api.github.com/repos/jesseduffield/lazygit/releases/latest"</span> | grep -Po <span class="hljs-string">'"tag_name": *"v\K[^"]*'</span>)
curl -Lo lazygit.tar.gz \
  <span class="hljs-string">"https://github.com/jesseduffield/lazygit/releases/download/v<span class="hljs-variable">${LAZYGIT_VERSION}</span>/lazygit_<span class="hljs-variable">${LAZYGIT_VERSION}</span>_Linux_x86_64.tar.gz"</span>
tar xf lazygit.tar.gz lazygit
sudo install lazygit -D -t /usr/<span class="hljs-built_in">local</span>/bin/
</code></pre>
<hr />
<h2 id="heading-step-3-install-git-delta">🎨 Step 3: Install Git-Delta</h2>
<p>Git-delta is a syntax-highlighting pager for <code>git</code>, <code>diff</code>, <code>grep</code>, and <code>blame</code> output. It's designed to make developer’s life easier by making reviewing code changes easier and efficient. It improves the readability and layout of diffs:</p>
<ol>
<li><p>Download delta from the <a target="_blank" href="https://dandavison.github.io/delta/installation.html">official page</a>.</p>
</li>
<li><p>Optional: Install a theme configuration file like <code>themes.gitconfig</code> into <code>~/.config/delta</code>.</p>
</li>
<li><p>Add to <code>~/.gitconfig</code>:</p>
</li>
</ol>
<pre><code class="lang-ini"><span class="hljs-section">[core]</span>
  <span class="hljs-attr">pager</span> = delta
<span class="hljs-section">[interactive]</span>
  <span class="hljs-attr">diffFilter</span> = delta --color-<span class="hljs-literal">on</span>ly
<span class="hljs-section">[include]</span>
  <span class="hljs-attr">path</span> = ~/.config/delta/themes.gitconfig
<span class="hljs-section">[delta]</span>
  <span class="hljs-attr">features</span> = arctic-fox
  <span class="hljs-attr">navigate</span> = <span class="hljs-literal">true</span>
  <span class="hljs-attr">line-numbers</span> = <span class="hljs-literal">true</span>
  <span class="hljs-attr">side-by-side</span> = <span class="hljs-literal">true</span>
<span class="hljs-section">[merge]</span>
  <span class="hljs-attr">conflictstyle</span> = zdiff3
</code></pre>
<hr />
<h2 id="heading-step-4-install-neovim">📝 Step 4: Install Neovim</h2>
<p>NeoVim is my favourite text editor of choice. Even though I use <code>nano</code> for most steps in this document for convenience. Follow the steps below to install NeoVim.</p>
<p>To get the latest version of Neovim:</p>
<pre><code class="lang-bash">sudo add-apt-repository ppa:neovim-ppa/stable
sudo apt update
sudo apt install -y neovim
</code></pre>
<p>If you want to configure NeoVim to have support for LSP servers, Fuzzy Finding, Lazy and Mason Plugin support, Linting and automatic code suggestions, follow the instructions here : <a target="_blank" href="https://github.com/febinjoy/febins-neovim-config">GitHub - febinjoy/febins-neovim-config</a>. <a target="_blank" href="https://github.com/febinjoy/febins-neovim-config">It contains my Neo-Vim configuration.</a> It requires you to create a <code>.config/nvim</code> folder in your home directory. All the configurations I made are using Lua. It is simple, all you will need to do is to clone the repo and let NeoVim install the Lazy and Mason plugins.</p>
<p>Run this to use my config:</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/febinjoy/febins-neovim-config ~/.config/nvim
</code></pre>
<p>Launch <code>nvim</code> to auto-install plugins.</p>
<hr />
<h2 id="heading-step-5-configure-zsh">🐚 Step 5: Configure Zsh</h2>
<ol>
<li><p><strong>Install Zsh (already done in utilities)</strong></p>
</li>
<li><p><strong>Create history and config files</strong>:</p>
</li>
</ol>
<pre><code class="lang-bash">touch ~/.zsh_history
nano ~/.zshrc
</code></pre>
<ol start="3">
<li><strong>Add the following to</strong> <code>~/.zshrc</code>:</li>
</ol>
<pre><code class="lang-bash">ZINIT_HOME=<span class="hljs-string">"<span class="hljs-variable">${XDG_DATA_HOME:-<span class="hljs-variable">${HOME}</span>/.local/share}</span>/zinit/zinit.git"</span>
<span class="hljs-keyword">if</span> [ ! -d <span class="hljs-variable">$ZINIT_HOME</span> ]; <span class="hljs-keyword">then</span>
  mkdir -p <span class="hljs-string">"<span class="hljs-subst">$(dirname $ZINIT_HOME)</span>"</span>
  git <span class="hljs-built_in">clone</span> https://github.com/zdharma-continuum/zinit.git <span class="hljs-string">"<span class="hljs-variable">$ZINIT_HOME</span>"</span>
<span class="hljs-keyword">fi</span>
<span class="hljs-built_in">source</span> <span class="hljs-string">"<span class="hljs-variable">$ZINIT_HOME</span>/zinit.zsh"</span>

zinit ice depth=1; zinit light romkatv/powerlevel10k
zinit light zsh-users/zsh-autosuggestions
zinit light zsh-users/zsh-syntax-highlighting
zinit light Aloxaf/fzf-tab
zinit snippet OMZP::git
zinit snippet OMZP::sudo
zinit snippet OMZP::extract

<span class="hljs-built_in">export</span> HISTFILE=~/.zsh_history
<span class="hljs-built_in">export</span> HISTSIZE=10000
<span class="hljs-built_in">export</span> SAVEHIST=10000
<span class="hljs-built_in">bindkey</span> <span class="hljs-string">"^[[3~"</span> delete-char

<span class="hljs-comment"># Aliases</span>
<span class="hljs-built_in">alias</span> ls=<span class="hljs-string">'ls --color'</span>
<span class="hljs-built_in">alias</span> grep=<span class="hljs-string">'grep --color'</span>
</code></pre>
<ol start="4">
<li><strong>Change Default Shell to Zsh</strong>:<br /> Installing Zsh and having the config will not automatically switch your shell from bash to Zsh. We need to use the following command to change your shell:</li>
</ol>
<pre><code class="lang-bash">chsh -s $(<span class="hljs-built_in">which</span> zsh)
</code></pre>
<p>Then reboot or re-login.</p>
<blockquote>
<p>✨ If using Powerlevel10k, you may want a Nerd Font on your terminal.</p>
</blockquote>
<ol start="5">
<li><strong>My final version</strong>:<br /> I have added more options and aliases to my <code>.zshrc</code> according to my preference. Please find it below. Please don't hesitate to use it. You may need to remove some of it if you don’t have the associated tool installed. e.g. fzf:</li>
</ol>
<pre><code class="lang-bash"><span class="hljs-comment"># Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc.</span>
<span class="hljs-comment"># Initialization code that may require console input (password prompts, [y/n]</span>
<span class="hljs-comment"># confirmations, etc.) must go above this block; everything else may go below.</span>
<span class="hljs-keyword">if</span> [[ -r <span class="hljs-string">"<span class="hljs-variable">${XDG_CACHE_HOME:-<span class="hljs-variable">$HOME</span>/.cache}</span>/p10k-instant-prompt-<span class="hljs-variable">${(%):-%n}</span>.zsh"</span> ]]; <span class="hljs-keyword">then</span>
  <span class="hljs-built_in">source</span> <span class="hljs-string">"<span class="hljs-variable">${XDG_CACHE_HOME:-<span class="hljs-variable">$HOME</span>/.cache}</span>/p10k-instant-prompt-<span class="hljs-variable">${(%):-%n}</span>.zsh"</span>
<span class="hljs-keyword">fi</span>

ZINIT_HOME=<span class="hljs-string">"<span class="hljs-variable">${XDG_DATA_HOME:-<span class="hljs-variable">${HOME}</span>/.local/share}</span>/zinit/zinit.git"</span>
<span class="hljs-keyword">if</span> [ ! -d <span class="hljs-variable">$ZINIT_HOME</span> ]; <span class="hljs-keyword">then</span>
  mkdir -p <span class="hljs-string">"<span class="hljs-subst">$(dirname $ZINIT_HOME)</span>"</span>
  git <span class="hljs-built_in">clone</span> https://github.com/zdharma-continuum/zinit.git <span class="hljs-string">"<span class="hljs-variable">$ZINIT_HOME</span>"</span>
<span class="hljs-keyword">fi</span>
<span class="hljs-built_in">source</span> <span class="hljs-string">"<span class="hljs-variable">${ZINIT_HOME}</span>/zinit.zsh"</span>

zinit ice depth=1; zinit light romkatv/powerlevel10k

<span class="hljs-comment"># Add in zsh plugins</span>
zinit light zsh-users/zsh-autosuggestions
zinit light zsh-users/zsh-syntax-highlighting
zinit light Aloxaf/fzf-tab

<span class="hljs-comment"># Add in snippets</span>
zinit snippet OMZP::git
zinit snippet OMZP::sudo
zinit snippet OMZP::extract


<span class="hljs-comment"># Load zsh-completions</span>
<span class="hljs-built_in">autoload</span> -U compinit &amp;&amp; compinit

<span class="hljs-comment"># Key bindings</span>
<span class="hljs-built_in">bindkey</span> <span class="hljs-string">'^]'</span> autosuggest-accept
<span class="hljs-built_in">bindkey</span> <span class="hljs-string">'^p'</span> history-search-backward
<span class="hljs-built_in">bindkey</span> <span class="hljs-string">'^n'</span> history-search-forward
<span class="hljs-built_in">bindkey</span> <span class="hljs-string">"^[[3~"</span> delete-char

<span class="hljs-comment"># Setup zsh-history-file</span>
<span class="hljs-built_in">export</span> HISTFILE=~/.zsh_history
<span class="hljs-built_in">export</span> HISTSIZE=10000
<span class="hljs-built_in">export</span> SAVEHIST=<span class="hljs-variable">$HISTSIZE</span>
<span class="hljs-built_in">export</span> HISTDUP=erase

<span class="hljs-comment"># Options</span>
<span class="hljs-built_in">setopt</span> APPEND_HISTORY
<span class="hljs-built_in">setopt</span> SHARE_HISTORY
<span class="hljs-built_in">setopt</span> HIST_IGNORE_SPACE
<span class="hljs-built_in">setopt</span> HIST_SAVE_NO_DUPS
<span class="hljs-built_in">setopt</span> HIST_IGNORE_DUPS
<span class="hljs-built_in">setopt</span> HIST_FIND_NO_DUPS
<span class="hljs-built_in">setopt</span> EXTENDED_HISTORY
<span class="hljs-built_in">setopt</span> HIST_EXPIRE_DUPS_FIRST
<span class="hljs-built_in">setopt</span> HIST_IGNORE_ALL_DUPS
<span class="hljs-built_in">setopt</span> HIST_VERIFY

<span class="hljs-comment"># Aliases</span>
<span class="hljs-built_in">alias</span> ls=<span class="hljs-string">'ls --color'</span>
<span class="hljs-built_in">alias</span> grep=<span class="hljs-string">'grep --color'</span>
<span class="hljs-built_in">alias</span> fgrep=<span class="hljs-string">'fgrep --color'</span>
<span class="hljs-built_in">alias</span> egrep=<span class="hljs-string">'egrep --color'</span>

<span class="hljs-comment"># Completion styling</span>
<span class="hljs-built_in">zstyle</span> <span class="hljs-string">':completion:*'</span> matcher-list <span class="hljs-string">'m:{a-z}={A-Za-z}'</span>
<span class="hljs-built_in">zstyle</span> <span class="hljs-string">':completion:*'</span> list-colors <span class="hljs-string">"<span class="hljs-variable">${(s.:.)LS_COLORS}</span>"</span>
<span class="hljs-built_in">zstyle</span> <span class="hljs-string">':completion:*'</span> menu no
<span class="hljs-built_in">zstyle</span> <span class="hljs-string">':fzf-tab:complete:cd:*'</span> fzf-preview <span class="hljs-string">'ls --color=always $realpath'</span>
<span class="hljs-built_in">zstyle</span> <span class="hljs-string">':fzf-tab:complete:__zooxide_z:*'</span> fzf-preview <span class="hljs-string">'ls --color=always $realpath'</span>

<span class="hljs-comment"># To customize prompt, run `p10k configure` or edit ~/.p10k.zsh.</span>
[[ ! -f ~/.p10k.zsh ]] || <span class="hljs-built_in">source</span> ~/.p10k.zsh
</code></pre>
<hr />
<h2 id="heading-step-6-install-and-configure-tmux">📦 Step 6: Install and Configure TMUX</h2>
<p>TMUX aka Terminal Multiplexer is a powerful utility for terminal management, enabling the user to work with several terminal sessions in one window. It is a game changer in my opinion, which allows the user to easily create, manage, and switch between multiple terminal panes and windows, enhancing productivity and making multitasking easier. TMUX allows session detachment and re-attachment, which is very helpful in keeping persistent sessions on remote servers. It is also highly customisable and is an indispensable utility for any developer, system administrator, or anyone else who works with the command line on a frequent basis.</p>
<ol>
<li>Install TMUX:</li>
</ol>
<pre><code class="lang-bash">sudo apt install -y tmux
</code></pre>
<ol start="2">
<li>Create config file:</li>
</ol>
<pre><code class="lang-bash">nano ~/.tmux.conf
</code></pre>
<p>Paste <a target="_blank" href="https://github.com/febinjoy/terminal-config/blob/main/.tmux.conf">my config</a> or your own.</p>
<ol start="3">
<li>Install TPM (Plugin Manager):</li>
</ol>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm
</code></pre>
<ol start="4">
<li>Inside a TMUX session:</li>
</ol>
<ul>
<li><p>Press <code>Ctrl + A</code> then <code>I</code> to install plugins</p>
</li>
<li><p>Press <code>Ctrl + A</code> then <code>r</code> to reload</p>
</li>
<li><p>If you used my TMUX configuration, you will see a themed TMUX window at this point.</p>
</li>
</ul>
<hr />
<p>In Part 3, we'll focus on securing and hardening the server with firewall rules, SSH configuration, Fail2Ban, and more.</p>
<p>Stay tuned for <strong>Part 3: Securing and Hardening the Server</strong>!</p>
]]></content:encoded></item><item><title><![CDATA[Part 1: Installing and Configuring the Base Ubuntu Server]]></title><description><![CDATA[Welcome to Part 1 of my multi-part series on setting up a headless Ubuntu home lab server tailored for developers. This post covers the installation of Ubuntu Server, setting up your development environment, and installing essential tools to get star...]]></description><link>https://artofcoding.dev/part-1-installing-and-configuring-the-base-ubuntu-server</link><guid isPermaLink="true">https://artofcoding.dev/part-1-installing-and-configuring-the-base-ubuntu-server</guid><category><![CDATA[Ubuntu]]></category><category><![CDATA[Homelab]]></category><category><![CDATA[Linux]]></category><category><![CDATA[serversetup]]></category><category><![CDATA[Developer Tools]]></category><dc:creator><![CDATA[Febin Joy]]></dc:creator><pubDate>Mon, 02 Jun 2025 12:42:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1748867998478/5a902b23-ff9b-4f64-aac8-126673874ef9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Welcome to Part 1 of my multi-part series on setting up a headless Ubuntu home lab server tailored for developers. This post covers the installation of Ubuntu Server, setting up your development environment, and installing essential tools to get started.</p>
<blockquote>
<p><em>💡</em> This setup is intended for a personal home lab, not a production environment.</p>
</blockquote>
<hr />
<h2 id="heading-step-1-install-ubuntu-server">🖥️ Step 1: Install Ubuntu Server</h2>
<ol>
<li><p><strong>Download the ISO</strong>: Grab the latest <a target="_blank" href="https://ubuntu.com/download/server">Ubuntu Server ISO</a>.</p>
</li>
<li><p>Create a bootable USB with the ISO downloaded. How to do this step differs with different operating systems.</p>
</li>
<li><p><strong>Boot and Install</strong>:</p>
<ul>
<li><p>Insert the USB drive into your server and boot from it.</p>
</li>
<li><p>Follow the on-screen instructions.</p>
</li>
<li><p>During installation:</p>
<ul>
<li><p>Choose to install <strong>OpenSSH Server</strong>.</p>
</li>
<li><p>Select <strong>Use SSH via GitHub</strong> (adds your GitHub keys to enable SSH).</p>
</li>
</ul>
</li>
</ul>
</li>
</ol>
<blockquote>
<p>🔐 <em>Ensure your GitHub account has your SSH public keys added before installation.</em></p>
</blockquote>
<ol start="4">
<li><strong>Static IP Recommendation</strong>:<br /> Assign a static IP for your server in your router (outside the DHCP range).</li>
</ol>
<hr />
<h2 id="heading-step-2-update-the-system">🔄 Step 2: Update the System</h2>
<p>Run the following to make sure the system is up-to-date:</p>
<pre><code class="lang-bash">sudo apt update &amp;&amp; sudo apt upgrade -y
</code></pre>
<hr />
<h2 id="heading-step-3-install-programming-languages-amp-frameworks">🧰 Step 3: Install Programming Languages &amp; Frameworks</h2>
<p>Create a setup script to install all your preferred tools in one go.</p>
<h3 id="heading-1-create-setup-directory-and-script">1. Create Setup Directory and Script</h3>
<pre><code class="lang-bash">mkdir ~/setup
nano ~/setup/install_from_file.sh
</code></pre>
<p>Paste the following into the file:</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>

<span class="hljs-comment"># Java Runtime Environment</span>
sudo apt install -y default-jre

<span class="hljs-comment"># Python and Pip</span>
sudo apt install -y python3 python3-pip python3-venv python3-debugpy

<span class="hljs-comment"># NodeJS</span>
curl -fsSL https://deb.nodesource.com/setup_23.x | sudo -E bash -
sudo apt install -y nodejs

<span class="hljs-comment"># Golang</span>
sudo apt install -y golang

<span class="hljs-comment"># Lua</span>
sudo apt install -y lua5.4 luarocks

<span class="hljs-comment"># .NET SDK</span>
wget https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
sudo apt update
sudo apt install dotnet-sdk-8.0 -y

<span class="hljs-comment"># Sqlite3</span>
sudo apt install -y sqlite3
</code></pre>
<h3 id="heading-2-make-it-executable-and-run">2. Make It Executable and Run</h3>
<pre><code class="lang-bash">chmod +x ~/setup/install_from_file.sh
sudo ~/setup/install_from_file.sh
</code></pre>
<hr />
<h2 id="heading-step-4-verify-installations">🔍 Step 4: Verify Installations</h2>
<p>Check the versions to verify the tools are installed:</p>
<pre><code class="lang-bash">java --version
python3 --version
pip3 --version
node -v
npm -v
go version
dotnet --list-sdks
</code></pre>
<hr />
<h2 id="heading-step-5-install-and-configure-git-amp-github-ssh">🔄 Step 5: Install and Configure Git &amp; GitHub SSH</h2>
<h3 id="heading-1-verify-git-installation">1. Verify Git Installation</h3>
<pre><code class="lang-bash">sudo apt install -y git
git config --global user.name <span class="hljs-string">"Your Name"</span>
git config --global user.email <span class="hljs-string">"you@example.com"</span>
</code></pre>
<h3 id="heading-2-create-ssh-key-and-add-to-github">2. Create SSH Key and Add to GitHub</h3>
<pre><code class="lang-bash">ssh-keygen -t ed25519 -C <span class="hljs-string">"you@example.com"</span>
<span class="hljs-built_in">eval</span> <span class="hljs-string">"<span class="hljs-subst">$(ssh-agent -s)</span>"</span>
ssh-add ~/.ssh/id_ed25519
cat ~/.ssh/id_ed25519.pub
</code></pre>
<p>Copy the output and add it to GitHub:</p>
<ul>
<li><p>GitHub → Profile → Settings → SSH and GPG keys → New SSH Key</p>
</li>
<li><p>Title: <code>Homelab - &lt;your-server-hostname&gt;</code></p>
</li>
<li><p>Paste key and save</p>
</li>
</ul>
<p>Now you can <code>git clone</code> via SSH securely. The same steps could be repeated for Bitbucket or other source control tools if required.</p>
<hr />
<p>In the next part, we'll install essential terminal tools and boost productivity with a custom shell setup, Neovim, TMUX, and more.</p>
<p>Stay tuned for <strong>Part 2: Essential Terminal Tools for Productivity</strong>!</p>
<hr />
<p><em>Have questions or feedback? Drop a comment below or reach out via</em> <a target="_blank" href="https://github.com/febinjoy"><em>GitHub</em></a><em>.</em></p>
]]></content:encoded></item><item><title><![CDATA[Setting up a Linux terminal for productivity]]></title><description><![CDATA[Introduction
Recently, I have installed my computer with Arch Linux. The decision to move to vanilla Arch from EndeavourOS (another Arch-based distro) was quite an organic one. I just thought of starting with a clean slate without any preinstalled ap...]]></description><link>https://artofcoding.dev/setting-up-a-linux-terminal-for-productivity</link><guid isPermaLink="true">https://artofcoding.dev/setting-up-a-linux-terminal-for-productivity</guid><category><![CDATA[#LinuxTerminal]]></category><category><![CDATA[#WezTerm]]></category><category><![CDATA[#TechSetup]]></category><category><![CDATA[Productivity]]></category><category><![CDATA[ArchLinux]]></category><category><![CDATA[zsh]]></category><category><![CDATA[zshrc]]></category><category><![CDATA[ZSH Themes]]></category><category><![CDATA[tmux]]></category><category><![CDATA[neovim]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[programming]]></category><category><![CDATA[devtools]]></category><category><![CDATA[Lazygit]]></category><category><![CDATA[#ranger]]></category><dc:creator><![CDATA[Febin Joy]]></dc:creator><pubDate>Sun, 27 Oct 2024 10:36:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1730020054288/b65a5386-9e37-495f-9a28-54c846386a71.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Recently, I have installed my computer with Arch Linux. The decision to move to vanilla Arch from EndeavourOS (another Arch-based distro) was quite an organic one. I just thought of starting with a clean slate without any preinstalled apps.</p>
<p>During this process, there was a point when I had to set up my development environment from scratch. It involved setting up the terminal, installing all the required tools etc. While doing it, I thought of sharing the journey of how I configured a productive terminal environment for software development.</p>
<p>In this article, I'll take you through how to configure your terminal environment for maximum efficiency and productivity. We will go over the following:</p>
<ul>
<li><p><strong>WezTerm</strong>: A fully featured, modern terminal emulator.</p>
</li>
<li><p><strong>Zsh</strong>: An advanced interactive shell.</p>
</li>
<li><p><strong>TMUX</strong>: A terminal multiplexer for efficient handling of multiple terminal sessions.</p>
</li>
<li><p><strong>Neovim</strong>: How to configure this immensely capable and extendable text editor as an IDE.</p>
</li>
<li><p>Some of the coolest terminal applications which will take your productivity to the next level.</p>
</li>
</ul>
<p>Let's dive into creating a productivity-enhancing terminal setup and, at the same time, making it enjoyable to work in the terminal!</p>
<h2 id="heading-pre-requisites">Pre-requisites</h2>
<p>Before we proceed with configuring your terminal, please ensure you have the following installed. Since I am using Arch, I will be using <code>pacman</code> to install packages. You can install the same using the package manager in your distro.</p>
<h3 id="heading-install-and-configure-the-necessities">Install and configure the necessities</h3>
<h4 id="heading-1-install-python-only-required-for-configuring-neovim">1. Install Python (Only required for configuring Neovim)</h4>
<pre><code class="lang-bash">sudo pacman -S python
</code></pre>
<h4 id="heading-2-install-pip-only-required-for-configuring-neovim">2. Install Pip (Only required for configuring Neovim)</h4>
<pre><code class="lang-bash">sudo pacman -S python-pip
</code></pre>
<h4 id="heading-3-install-nodejshttpsnodejs-only-required-for-configuring-neovim">3. Install <a target="_blank" href="https://Node.js">Node.js</a> (Only required for configuring Neovim)</h4>
<pre><code class="lang-bash">sudo pacman -S nodejs
</code></pre>
<h4 id="heading-4-install-and-configure-git">4. Install and Configure Git</h4>
<pre><code class="lang-bash">sudo pacman -S git
</code></pre>
<p>Configure Git with your username and email:</p>
<pre><code class="lang-bash">git config --global user.name <span class="hljs-string">"Your Name"</span>
git config --global user.email <span class="hljs-string">"your.email@example.com"</span>
</code></pre>
<p>More details could be found here - <a target="_blank" href="https://docs.github.com/en/get-started/getting-started-with-git/set-up-git">https://docs.github.com/en/get-started/getting-started-with-git/set-up-git</a></p>
<h4 id="heading-5-installing-hack-nerd-font">5. Installing Hack Nerd Font</h4>
<p>Nerd Fonts provide a wide range of glyphs from popular iconic fonts. The help in enhancing the look of your terminal. My favourite nerd font is <code>Hack Nerd Font</code> You can install any of the nerd fonts from here - <a target="_blank" href="https://www.nerdfonts.com/font-downloads">https://www.nerdfonts.com/font-downloads</a> and use it.</p>
<pre><code class="lang-bash">sudo pacman -S ttf-hack-nerd
</code></pre>
<h4 id="heading-6-install-fuzzy-finder-for-terminal">6. Install Fuzzy Finder for terminal</h4>
<pre><code class="lang-bash">sudo pacman -S fzf
</code></pre>
<h2 id="heading-install-and-configure-wezterm">Install and configure WezTerm</h2>
<p>WezTerm is a wonderful open-source terminal emulator which is well known for its performance and customisation capabilities. The highlight of WezTerm is that we can configure it using Lua. I am quite sure WezTerm will take your terminal experience to the next level.</p>
<h3 id="heading-1-install-wezterm">1. Install WezTerm</h3>
<pre><code class="lang-bash">sudo pacman -S wezterm
</code></pre>
<h3 id="heading-2-configure-wezterm">2. Configure WezTerm</h3>
<p>Once WezTerm is installed, you can try launching it. I admit that the default look and feel of WezTerm is not so appealing. It is now time to configure it and make it beautiful.</p>
<p>Create a new folder <code>wezterm</code> inside your <code>.config</code> folder and navigate inside it with the following commands.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">cd</span> ~/.config
mkdir wezterm
<span class="hljs-built_in">cd</span> wezterm
</code></pre>
<p>Create a new file, <code>.wezterm.lua</code></p>
<pre><code class="lang-bash">touch .wezterm.lua
</code></pre>
<p>Open this file in an editor of your choice. I used Neovim. You are free to use any editor of your choice.</p>
<p>Neovim (If you have it installed):</p>
<pre><code class="lang-bash">nvim .wezterm.lua
</code></pre>
<p>Following is the config I used. Please follow inline comments for more explanation. Uncomment lines if required. Add the contents to the config file we just created.</p>
<pre><code class="lang-plaintext">local wezterm = require("wezterm")

-- This Lua table will hold the WezTerm configuration.
local config = wezterm.config_builder()

config.font = wezterm.font("Hack Nerd Font Mono") -- Change this if you have a different Nerd Font installed.
config.font_size = 12 -- Change this to suit your need. A different screen resolution might need a change here

config.window_padding = {
    left = 0,
    right = 0,
    top = 0,
    bottom = 0,
}

-- Set the initial Terminal Size here
config.initial_cols = 140 -- Width
config.initial_rows = 65 -- Height

-- Set the terminal's opacity.
-- 1 = Opaque. 0 = Transparent.
-- Choose a value as per your need.
config.window_background_opacity = 0.96

-- Enable the following if you want to use an image as the background
-- config.window_background_image = "background.jpg" -- Select background image of your choice
-- config.window_background_image_hsb = {
--      -- Darken the background image by reducing it to 1/3rd
--      brightness = 0.1,
--
--      -- You can adjust the hue by scaling its value.
--      -- a multiplier of 1.0 leaves the value unchanged.
--      hue = 1.0,
--
--      -- You can adjust the saturation also.
--      saturation = 1.0,
-- }
-- End of background image configuration

-- Select a good theme
-- More themes could be found here - https://wezfurlong.org/wezterm/colorschemes/index.html
config.color_scheme = "Flatland"
-- Here are some of the themes I personally like
-- config.color_scheme = "Catppuccin Mocha"
-- config.color_scheme = "Ciapre (Gogh)"
-- config.color_scheme = "Dawn (terminal.sexy)" -- Brown tint
-- config.color_scheme = "Sandcastle (base16)"
-- config.color_scheme = "Afterglow (Gogh)"
-- config.color_scheme = "Apprentice (Gogh)"
-- config.color_scheme = "Chameleon (Gogh)"
-- config.color_scheme = "Ciapre (Gogh)"
-- config.color_scheme = "Dawn (terminal.sexy)"
-- config.color_scheme = "FishTank"

config.enable_tab_bar = false -- This will remove the top tab bar of the terminal window. If you wish to have it, Please comment this line.
config.window_decorations = "RESIZE" -- This will remove the title bar and borders of the terminal and make it floating. Comment this line if you wish to keep the default style.

return config
</code></pre>
<p>I have made the same publicly available in GitHub - <a target="_blank" href="https://github.com/febinjoy/wezterm-config/blob/main/.wezterm.lua">https://github.com/febinjoy/wezterm-config/blob/main/.wezterm.lua</a>. Any changes to the above based on my future workflow could be found there.</p>
<p>Now, launch WezTerm to see your configuration in action. You would be having WezTerm up and running with your custom configuration.</p>
<h2 id="heading-install-and-configure-zsh">Install and configure Zsh</h2>
<p>Zsh is a powerful shell that is highly customisable which and provides you with a better command line experience. It has plenty of features compared to the traditional Bash shell; which makes it a favourite choice of developers. I, personally, prefer Zsh over bash. Now, I will walk you through the installation and configuration of Zsh which will make your terminal both functional and more stylish.</p>
<h3 id="heading-1-install-zsh">1. Install Zsh</h3>
<pre><code class="lang-bash">sudo pacman -S zsh
</code></pre>
<p>Even though we have installed Zsh, our current shell is still <code>bash</code>. Now, we will need to switch to using Zsh. Find the path where Zsh is installed (Usually, it will be <code>/usr/bin/zsh</code>).</p>
<p>Use the following command to change the shell.</p>
<pre><code class="lang-bash">sudo chsh &lt;your username&gt;
</code></pre>
<p>When prompted, provide the path to Zsh as the path to new shell. This will change it from <code>/usr/bin/bash</code> to <code>/usr/bin/zsh</code></p>
<p>Run the following to confirm it is set properly.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">echo</span> <span class="hljs-variable">$SHELL</span>
</code></pre>
<p>If you ever feel like switching back to bash, use the same method and provide path to bash.</p>
<h3 id="heading-2-configure-zsh">2. Configure Zsh</h3>
<p>Now it is time to configure your shell.</p>
<p>Create a file <code>.zshrc</code> and <code>.zsh_history</code> in the home directory using the following</p>
<pre><code class="lang-bash">touch ~/.zshrc
touch ~/.zsh_history
</code></pre>
<p>Open the <code>.zshrc</code> file and add the following lines.</p>
<pre><code class="lang-bash">ZINIT_HOME=<span class="hljs-string">"<span class="hljs-variable">${XDG_DATA_HOME:-<span class="hljs-variable">${HOME}</span>/.local/share}</span>/zinit/zinit.git"</span>
<span class="hljs-keyword">if</span> [ ! -d <span class="hljs-variable">$ZINIT_HOME</span> ]; <span class="hljs-keyword">then</span>
  mkdir -p <span class="hljs-string">"<span class="hljs-subst">$(dirname $ZINIT_HOME)</span>"</span>
  git <span class="hljs-built_in">clone</span> https://github.com/zdharma-continuum/zinit.git <span class="hljs-string">"<span class="hljs-variable">$ZINIT_HOME</span>"</span>
<span class="hljs-keyword">fi</span>
<span class="hljs-built_in">source</span> <span class="hljs-string">"<span class="hljs-variable">${ZINIT_HOME}</span>/zinit.zsh"</span>

zinit ice depth=1; zinit light romkatv/powerlevel10k

<span class="hljs-comment">#-----zsh-history-file-----</span>
<span class="hljs-built_in">export</span> HISTFILE=~/.zsh_history
<span class="hljs-built_in">export</span> HISTSIZE=10000
<span class="hljs-built_in">export</span> SAVEHIST=`<span class="hljs-variable">$HISTSIZE</span>`

<span class="hljs-comment"># In Arch, the delete key was not properly mapped. Comment this if not required.</span>
<span class="hljs-built_in">bindkey</span> <span class="hljs-string">"^[[3~"</span> delete-char
</code></pre>
<p>Save the file, exit WezTerm and launch again. Confirm everything is working correctly by running <code>zinit zstatus</code></p>
<p>In the above configuration, You might have noticed that I have installed a package called Powerlevel10K. Powerlevel10k is probably one of the most popular Zsh themes, developed with a goal of having a very customisable and good-looking prompt in your terminal. It is fast, feature-rich, and offers a bunch of options for making your prompt show information like git status, command execution time, and many more. Powerlevel10k works out of the box with Nerd Fonts, making your terminal look beautiful and informative at the same time. Once you relaunch Wezterm, you will be greeted with a screen to configure Powerlevel10k. Follow the prompts and choose the style of your choice. Once it is done, It will add the following lines to your <code>.zshrc</code> file. Don’t remove it manually.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># To customize prompt, run `p10k configure` or edit ~/.p10k.zsh. </span>
[[ ! -f ~/.p10k.zsh ]] || <span class="hljs-built_in">source</span> ~/.p10k.zsh
</code></pre>
<p>I went ahead and made extra refinements to my <code>.zshrc</code> file to suit my needs. Here is the final version for your reference.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Enable Powerlevel10k instant prompt. Should stay close to the top of ~/.zshrc.</span>
<span class="hljs-comment"># Initialization code that may require console input (password prompts, [y/n]</span>
<span class="hljs-comment"># confirmations, etc.) must go above this block; everything else may go below.</span>
<span class="hljs-keyword">if</span> [[ -r <span class="hljs-string">"<span class="hljs-variable">${XDG_CACHE_HOME:-<span class="hljs-variable">$HOME</span>/.cache}</span>/p10k-instant-prompt-<span class="hljs-variable">${(%):-%n}</span>.zsh"</span> ]]; <span class="hljs-keyword">then</span>
  <span class="hljs-built_in">source</span> <span class="hljs-string">"<span class="hljs-variable">${XDG_CACHE_HOME:-<span class="hljs-variable">$HOME</span>/.cache}</span>/p10k-instant-prompt-<span class="hljs-variable">${(%):-%n}</span>.zsh"</span>
<span class="hljs-keyword">fi</span>

ZINIT_HOME=<span class="hljs-string">"<span class="hljs-variable">${XDG_DATA_HOME:-<span class="hljs-variable">${HOME}</span>/.local/share}</span>/zinit/zinit.git"</span>
<span class="hljs-keyword">if</span> [ ! -d <span class="hljs-variable">$ZINIT_HOME</span> ]; <span class="hljs-keyword">then</span>
  mkdir -p <span class="hljs-string">"<span class="hljs-subst">$(dirname $ZINIT_HOME)</span>"</span>
  git <span class="hljs-built_in">clone</span> https://github.com/zdharma-continuum/zinit.git <span class="hljs-string">"<span class="hljs-variable">$ZINIT_HOME</span>"</span>
<span class="hljs-keyword">fi</span>
<span class="hljs-built_in">source</span> <span class="hljs-string">"<span class="hljs-variable">${ZINIT_HOME}</span>/zinit.zsh"</span>

zinit ice depth=1; zinit light romkatv/powerlevel10k

<span class="hljs-comment"># Add in zsh plugins</span>
zinit light zsh-users/zsh-autosuggestions
zinit light zsh-users/zsh-syntax-highlighting
zinit light zsh-users/zsh-completions
zinit light Aloxaf/fzf-tab

<span class="hljs-comment"># Add in snippets</span>
zinit snippet OMZP::git
zinit snippet OMZP::sudo
zinit snippet OMZP::archlinux
zinit snippet OMZP::extract


<span class="hljs-comment"># Load zsh-completions</span>
<span class="hljs-built_in">autoload</span> -U compinit &amp;&amp; compinit

<span class="hljs-comment"># Key bindings</span>
<span class="hljs-built_in">bindkey</span> <span class="hljs-string">'^]'</span> autosuggest-accept
<span class="hljs-built_in">bindkey</span> <span class="hljs-string">'^p'</span> history-search-backward
<span class="hljs-built_in">bindkey</span> <span class="hljs-string">'^n'</span> history-search-forward
<span class="hljs-built_in">bindkey</span> <span class="hljs-string">"^[[3~"</span> delete-char

<span class="hljs-comment"># Setup zsh-history-file</span>
<span class="hljs-built_in">export</span> HISTFILE=~/.zsh_history
<span class="hljs-built_in">export</span> HISTSIZE=10000
<span class="hljs-built_in">export</span> SAVEHIST=<span class="hljs-variable">$HISTSIZE</span>
<span class="hljs-built_in">export</span> HISTDUP=erase

<span class="hljs-comment"># Options</span>
<span class="hljs-built_in">setopt</span> APPEND_HISTORY
<span class="hljs-built_in">setopt</span> SHARE_HISTORY
<span class="hljs-built_in">setopt</span> HIST_IGNORE_SPACE
<span class="hljs-built_in">setopt</span> HIST_SAVE_NO_DUPS
<span class="hljs-built_in">setopt</span> HIST_IGNORE_DUPS
<span class="hljs-built_in">setopt</span> HIST_FIND_NO_DUPS
<span class="hljs-built_in">setopt</span> EXTENDED_HISTORY
<span class="hljs-built_in">setopt</span> HIST_EXPIRE_DUPS_FIRST
<span class="hljs-built_in">setopt</span> HIST_IGNORE_ALL_DUPS
<span class="hljs-built_in">setopt</span> HIST_VERIFY

<span class="hljs-comment"># Aliases</span>
<span class="hljs-built_in">alias</span> ls=<span class="hljs-string">'ls --color'</span>
<span class="hljs-built_in">alias</span> grep=<span class="hljs-string">'grep --color'</span>
<span class="hljs-built_in">alias</span> fgrep=<span class="hljs-string">'fgrep --color'</span>
<span class="hljs-built_in">alias</span> egrep=<span class="hljs-string">'egrep --color'</span>

<span class="hljs-comment"># Completion styling</span>
<span class="hljs-built_in">zstyle</span> <span class="hljs-string">':completion:*'</span> matcher-list <span class="hljs-string">'m:{a-z}={A-Za-z}'</span>
<span class="hljs-built_in">zstyle</span> <span class="hljs-string">':completion:*'</span> list-colors <span class="hljs-string">"<span class="hljs-variable">${(s.:.)LS_COLORS}</span>"</span>
<span class="hljs-built_in">zstyle</span> <span class="hljs-string">':completion:*'</span> menu no
<span class="hljs-built_in">zstyle</span> <span class="hljs-string">':fzf-tab:complete:cd:*'</span> fzf-preview <span class="hljs-string">'ls --color=always $realpath'</span>
<span class="hljs-built_in">zstyle</span> <span class="hljs-string">':fzf-tab:complete:__zooxide_z:*'</span> fzf-preview <span class="hljs-string">'ls --color=always $realpath'</span>

<span class="hljs-comment"># Shell integrations</span>
<span class="hljs-built_in">eval</span> <span class="hljs-string">"<span class="hljs-subst">$(fzf --zsh)</span>"</span>

<span class="hljs-comment"># To customize prompt, run `p10k configure` or edit ~/.p10k.zsh.</span>
[[ ! -f ~/.p10k.zsh ]] || <span class="hljs-built_in">source</span> ~/.p10k.zsh
</code></pre>
<p>I have installed plugins for auto suggestions, syntax highlighting, auto-completion etc. Few key bindings are also added. Please refer to inline comments for reference. You are welcome to change or add more.</p>
<h2 id="heading-install-and-configure-tmux">Install and configure TMUX</h2>
<p>TMUX or Terminal Multiplexer is one of the powerful utilities that enable you to manage multiple terminal sessions from within a single screen. It enhances productivity by enabling you to split your terminal into several panes, switching between them easily, and keep your sessions running even while you are disconnected.</p>
<h3 id="heading-1-install-tmux">1. Install TMUX</h3>
<p>Use the following command to install tmux:</p>
<pre><code class="lang-bash">sudo pacman -S tmux
</code></pre>
<h3 id="heading-configure-tmux">Configure TMUX</h3>
<p>Here is a wonderful article which helps you customise and configure TMUX - <a target="_blank" href="https://hamvocke.com/blog/a-guide-to-customizing-your-tmux-conf/">https://hamvocke.com/blog/a-guide-to-customizing-your-tmux-conf/</a></p>
<h2 id="heading-install-and-configure-neovim">Install and configure Neovim</h2>
<p>Neovim is a modern and enhanced version of the very famous code editor Vim. It provides an improved configuration system using Lua (like WezTerm) that is more user-friendly and aims at improving performance and extensibility. It is by far one of my favourite code editors of choice. I use it to write Python, Go, C# and JavaScript code and have extended it to have Syntax highlighting, LSP support, debugging support, Automatic code completion etc. Please refer to <a target="_blank" href="https://github.com/febinjoy/febins-neovim-config">https://github.com/febinjoy/febins-neovim-config</a> for more details. I am not elaborating further on this, as this article is more focused on making your terminal more beautiful and productive. If required, I can write an article on Neovim, and it's configuration later.</p>
<h2 id="heading-other-terminal-based-productivity-tools-that-i-use">Other terminal-based productivity tools that I use</h2>
<h3 id="heading-lazygit">Lazygit</h3>
<p>Lazygit is a simple terminal-based UI for Git. It makes performing Git commands in a more easy and productive way. It exposes an intuitive, easy-to-use interface to navigate through repositories, stage changes, create commits, and manage branches-all without the need to memorise more complicated git commands. Install Lazygit with the following command:</p>
<pre><code class="lang-bash">sudo pacman -S lazygit
</code></pre>
<h3 id="heading-ranger">Ranger</h3>
<p>Ranger is a powerful file manager for the terminal. It presents your file system in a nice-looking, navigable way and features previews of files, bookmarks for directories, and execution of shell commands. It does a lot more than classical ways of navigating through terminals. Install it using the following:</p>
<pre><code class="lang-bash">sudo pacman -S ranger
</code></pre>
<h3 id="heading-htop">htop</h3>
<p><strong>htop</strong> is a process viewer which provides a comprehensive overview of the running system processes. Install it with the following:</p>
<pre><code class="lang-bash">sudo pacman -S htop
</code></pre>
<h3 id="heading-ncdu">ncdu</h3>
<p>It is a disk usage analyser which helps you to understand your disk space usage.</p>
<pre><code class="lang-bash">sudo pacman -S ncdu
</code></pre>
<h3 id="heading-bat">bat</h3>
<p>Bat is a clone of the popular Linux tool <code>cat</code>. Bat provides syntax highlighting on top of <code>cat</code> which helps to view and understand code in terminal easier.</p>
<pre><code class="lang-bash">sudo pacman -S bat
</code></pre>
<h3 id="heading-ripgrep">ripgrep</h3>
<p>ripgrep is a fast search tool for large codebases. I use it in side my Neovim setup.</p>
<pre><code class="lang-bash">sudo pacman -S ripgrep
</code></pre>
<h2 id="heading-the-final-result">The final result</h2>
<p>And here is the final result. You can see TMUX in action with Neovim on the left side and Ranger and Lazygit stacked vertically on the right side.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730020602769/79d030d6-1ec6-4fe2-bd55-fa229f6f40ff.png" alt class="image--center mx-auto" /></p>
<h4 id="heading-shout-outs-and-courtesy-notes">Shout-outs and courtesy notes</h4>
<p>Big shout-out to all those wonderful developers who dedicated their efforts in creating and maintaining these wonderful applications and sharing it with the community.</p>
]]></content:encoded></item><item><title><![CDATA[EndeavourOS - Gemini]]></title><description><![CDATA[Introduction
Last week, my trusty computer running Ubuntu 23.10 decided to throw a tantrum while I was trying to upgrade it to Ubuntu 24.04, the latest LTS release. It resulted in a crash, leaving my system in an unpleasant state. Instead of diving d...]]></description><link>https://artofcoding.dev/endeavouros-gemini</link><guid isPermaLink="true">https://artofcoding.dev/endeavouros-gemini</guid><category><![CDATA[endeavouros-customisation]]></category><category><![CDATA[yay]]></category><category><![CDATA[linux-setup]]></category><category><![CDATA[arch-setup]]></category><category><![CDATA[endeavouros-setup]]></category><category><![CDATA[endeavouros-gemini]]></category><category><![CDATA[EndeavourOS]]></category><category><![CDATA[ArchLinux]]></category><category><![CDATA[linux for beginners]]></category><category><![CDATA[Linux installation]]></category><category><![CDATA[post-install]]></category><category><![CDATA[Pacman]]></category><category><![CDATA[Gnome]]></category><category><![CDATA[gnome-customise]]></category><category><![CDATA[gnome-customize]]></category><dc:creator><![CDATA[Febin Joy]]></dc:creator><pubDate>Sat, 01 Jun 2024 10:14:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1717236523150/d51136ab-ae41-41d5-8712-06b96d26ba9d.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>Last week, my trusty computer running Ubuntu 23.10 decided to throw a tantrum while I was trying to upgrade it to Ubuntu 24.04, the latest LTS release. It resulted in a crash, leaving my system in an unpleasant state. Instead of diving deeper into the troubleshooting steps to resolve the issue, I took it an opportunity to step outside my comfort zone and try something new.</p>
<p>My quest came to a halt on EndeavourOS, a distribution based on Arch Linux. Arch Linux, as everyone knows, is a highly customisable, minimalist Linux distribution. Here are some of the advantages of EndeavourOS that got me thinking in favour of it:</p>
<p><strong>Arch Accessibility:</strong> As someone who’s always been curious about Arch Linux but hesitant to take the leap, EndeavourOS seems like the perfect bridge. It’s designed to make Arch Linux more approachable for users like me.</p>
<p><strong>GUI Installer:</strong> Unlike the base distro - Arch, which demands manual configuration and a certain level of expertise, EndeavourOS provides a user-friendly GUI installer. It was easy to get the system set up. After installation, I found that, and I appreciate the EndeavourOS team for their wonderful effort in making the installation process a breeze.</p>
<p><strong>Rolling Release:</strong> EndeavourOS follows the same release model as Arch. This means I don't have to wait through a release cycle to get the latest software. No more FOMO (fear of missing out) on updates!</p>
<p><strong>Total control:</strong> Arch fans love the control it provides its users. EndeavourOS also inherits this from Arch. Being a software professional and a Linux enthusiast, I loved the OS to be the way I want it (Which I would be discussing with you in this article).</p>
<p><strong>No Bloatware:</strong> Like Arch, EndeavourOS also keeps things to a minimum and allows the users to develop from the basics.</p>
<p><strong>Software availability:</strong> There are 2 built-in package managers for EndeavourOS -<strong>Pacman</strong> and <strong>Yay</strong>. <strong>Pacman</strong> is the package manager for Arch, which EndeavourOS is based on. It is used to install, update, and remove packages from the official Arch (and EndeavourOS) repositories. (A repository is just a collection of packages, programs and libraries). Then there is Arch User Repository (AUR), which is a collection of packages not in the official repositories. These are maintained by users. It is highly recommended to install software from pacman if it is available there. If not, you can try checking yay.</p>
<h1 id="heading-installing-endeavouros">Installing EndeavourOS</h1>
<p>Follow the steps below to install EndeavourOS</p>
<h2 id="heading-download-the-os">Download the OS</h2>
<p>Visit the official EndeavourOS website and download the ISO image for your architecture (32-bit or 64-bit). You can find the download link here: <a target="_blank" href="https://endeavouros.com/#Download">https://endeavouros.com/#Download</a></p>
<p>You have the option to download from Torrent, Magnet or directly download from a mirror closer to your location.</p>
<p>I used EndeavourOS Gemini in this article.</p>
<h2 id="heading-create-a-bootable-disk-and-install-the-os">Create a Bootable Disk and Install the OS</h2>
<p>Once you have the ISO file, proceed to create a bootable USB drive using a tool similar to Rufus or Etcher.</p>
<p>Boot from that USB stick. If required, change your BIOS settings to boot from the USB. You will be greeted with the installer. It will provide you 2 options:</p>
<ul>
<li><p><strong>Online Install</strong>: Allows you to choose your desktop environment during installation.</p>
</li>
<li><p><strong>Offline Install</strong>: Defaults to XFCE.</p>
</li>
</ul>
<p>Select <strong>Online Install</strong> to choose your desktop environment.</p>
<p>Then the installer would ask you to choose the desktop environment. Please choose your favourite one. Being a fan of GNOME, my choice was obviously the same.</p>
<p>At this stage, you will need to connect to your Wi-Fi if your computer is not connected to the internet using a LAN cable.</p>
<p>Follow the on-screen instructions and perform tasks like partitioning the disk, choosing your timezone, creating your user account and password etc.</p>
<p>Once the installation is over, please remove the USB drive and restart your PC.</p>
<p>You will boot into the newly installed EndeavourOS!</p>
<h1 id="heading-make-it-yours">Make it yours!</h1>
<p>Most of the steps in this article would apply to other Arch-based distros like Garuda Linux as well.</p>
<h2 id="heading-installing-updates-and-enabling-essentials">Installing Updates and enabling essentials</h2>
<p>You will be greeted with a welcome screen on your first login to EndeavourOS. Use it to update all the mirrors, and perform system updates. Once you are done, please restart the PC.</p>
<h3 id="heading-enable-bluetooth">Enable Bluetooth</h3>
<p>By default, Bluetooth will be disabled in EndeavourOS. This makes it difficult for people using a USB keyboard, mouse or headphones. Use the following command to start it:</p>
<pre><code class="lang-bash">sudo systemctl start bluetooth
</code></pre>
<p>To enable it on every restart, run the following:</p>
<pre><code class="lang-bash">sudo systemctl <span class="hljs-built_in">enable</span> bluetooth
</code></pre>
<p>Reboot the PC and verify that you can enable Bluetooth. Once the Bluetooth is enabled, connect your peripherals.</p>
<h3 id="heading-install-drivers">Install Drivers</h3>
<p>I use a USB hub which makes use of DisplayLink to connect to multiple monitors. Like most other Linux distros, EndeavourOS also did not detect it. As a result, I was connecting a monitor using HDMI for my setup. I installed the DisplayLink driver using the following:</p>
<pre><code class="lang-bash">yay -S displaylink
</code></pre>
<p>Once the driver was installed, I restarted the PS and the monitors were detected. It was never this easy with my good - old Ubuntu.</p>
<p>You are welcome to search and install any other drivers that you might need.</p>
<h3 id="heading-configure-backups">Configure Backups</h3>
<p>Backups are inevitable for any system. I use a tool - <strong>Timeshift</strong> for my backup needs. It allows capturing the snapshot of the system at a point of time. After installing it, take a backup. If there are 2 disks, choose one disk entirely for backups. It is recommended to schedule a daily backup and retain daily backups for at least a week to be on the safer side. Use the following command to install Timeshift.</p>
<pre><code class="lang-bash">sudo pacman -S timeshift
</code></pre>
<h2 id="heading-installing-software">Installing Software</h2>
<h3 id="heading-preinstalled-software">Preinstalled Software</h3>
<p>EndeavourOS comes preinstalled with the following tools.</p>
<ul>
<li><p>Git</p>
</li>
<li><p>Mozilla Firefox</p>
</li>
<li><p>Meld (A tool used to find the differences between 2 files or folders. It is similar to WinMerge on Windows)</p>
</li>
<li><p>Python</p>
</li>
</ul>
<h3 id="heading-install-software-using-pacman">Install software using Pacman</h3>
<p>As mentioned earlier, pacman is the package manager for Arch, which EndeavourOS is based on. It is similar to <strong>apt</strong> in Debian and <strong>dnf</strong> in Fedora. To install a single package or list of packages, including dependencies, use the following command:</p>
<pre><code class="lang-bash">pacman -S package_name1 package_name2 ...
</code></pre>
<p>To remove a single package, leaving all of its dependencies installed, use the following:</p>
<pre><code class="lang-bash">pacman -R package_name
</code></pre>
<p>To remove a package and its dependencies which are not required by any other installed package, use the following:</p>
<pre><code class="lang-bash">pacman -Rs package_name
</code></pre>
<p>If you are not sure if a software is available in <code>pacman</code> or not, try the following:</p>
<pre><code class="lang-bash">pacman -Ss package_name
</code></pre>
<p>It will list out all the packages available. Please note the exact name of the package you need from the list provided, replace <code>package_name</code> with it and use <code>packman -S</code> to install it.</p>
<p>Prefix the commands with <code>sudo</code> as required.</p>
<h4 id="heading-using-shell-script-to-install">Using shell script to install</h4>
<p>I prefer to install software using a shell script so that it could be re-used the next time when it needs to be done. Please follow the following approach to do it:</p>
<ul>
<li><p>Search for all the packages you need to install and take a note of the exact package name you have to install.</p>
</li>
<li><p>Once you know the name of all the packages to be installed, create a new folder — <code>Setup</code> in the home directory.</p>
</li>
<li><p>Create a new file — <code>install_from_</code><a target="_blank" href="http://file.sh"><code>file.sh</code></a> in it.</p>
</li>
<li><p>Add the <code>pacman</code> install commands to it for all the packages you have to install.</p>
</li>
<li><p>A sample file with all common tools is provided below for your convenience. Please refer to the inline comments.</p>
</li>
<li><p>Add/Remove commands to this list as per your requirement.</p>
</li>
</ul>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>

<span class="hljs-comment"># Password Management</span>
pacman -S bitwarden

<span class="hljs-comment"># Programming</span>
pacman -S filezilla
pacman -S dbeaver
pacman -S pycharm-community-edition
pacman -S remmina
pacman -S wireshark-qt
pacman -S docker
pacman -S nodejs
pacman -S npm
pacman -S dotnet-sdk
<span class="hljs-comment">#It is recommended to run Postgres in Docker than locally</span>
pacman -S postgresql
<span class="hljs-comment"># If you want to run VMs</span>
pacman -S gnome-boxes 

<span class="hljs-comment"># Comms </span>
pacman -S discord

<span class="hljs-comment"># Media</span>
pacman -S vlc
pacman -S gimp
pacman -S reaper
pacman -S rawtherapee
pacman -S darktable
pacman -S shotwell
pacman -S rhythmbox
<span class="hljs-comment"># For editing videos</span>
pacman -S kdenlive 

<span class="hljs-comment"># Text Utilities</span>
pacman -S obsidian
pacman -S notepadqq

<span class="hljs-comment"># Utilities</span>
pacman -S bleachbit
pacman -S qbittorrent
<span class="hljs-comment"># For creating bootable USB sticks</span>
pacman -S isoimagewriter
<span class="hljs-comment"># By default, calendar app is not installed</span>
pacman -S gnome-calendar 

<span class="hljs-comment"># Finance</span>
pacman -S homebank

<span class="hljs-comment"># Drawing </span>
pacman -S krita

<span class="hljs-comment"># Extensions</span>
pacman -S gnome-shell-extensions
</code></pre>
<p>Once you have the script ready, It is time to provide it executable permissions. Use the following from the terminal in the same folder as the script file.</p>
<pre><code class="lang-bash">sudo chmod +x install_from_file.sh
</code></pre>
<p>Execute the script to install the packages.</p>
<pre><code class="lang-bash">sudo ./install_from_file.sh
</code></pre>
<p>This will install all the packages that you chose. Occasionally, you may be prompted to provide confirmation whether you are sure if you need to install the package. To avoid this, you can use a <code>-y</code> flag in the shell script next to each pacman command. Here is an example:</p>
<pre><code class="lang-bash">pacman -S krita -y
</code></pre>
<p>All the packages from pacman will now be installed on your PC. It is recommended to restart your PC at this point.</p>
<h4 id="heading-google-drive">Google Drive</h4>
<p>In EndeavourOS, you would be able to add your Google accounts like any other GNOME distro. But your Google Drive may not show up in the Files application. It is because, you are lacking a package - <code>gvfs-google</code>. It is a virtual file system implementation for Google Drive on Linux. Other distros will have it preinstalled. Here, you will need to install it manually using the following:</p>
<pre><code class="lang-bash">sudo pacman -S gvfs-google
</code></pre>
<p>Once installed, restart your computer. Google Drive will show up in your Files application.</p>
<h3 id="heading-install-software-using-yay">Install software using Yay</h3>
<p>Pacman installs packages only from the repos. There is a high chance of having some software that you need is not available. That is where Yay comes to your rescue. As mentioned earlier, there is a huge repository of software out there called AUR. Yay lets you install packages from both the repos and AUR.</p>
<p>You can follow the same format as pacman for searching, installing and removing packages with yay. The format is as follows:</p>
<pre><code class="lang-bash">yay -S package_name
</code></pre>
<p>However, I would not recommend using the shell script approach with yay.</p>
<blockquote>
<p>[!Warning] You should not be using sudo with <code>yay</code>.</p>
</blockquote>
<h4 id="heading-install-pamac">Install Pamac</h4>
<p>EndeavourOS does not come with a GUI-based package manager. I would recommend you to install Pamac which is a GUI-based package manager from Manjaro. Use the following to do it. If you are comfortable with a terminal package manager, this step is purely optional.</p>
<pre><code class="lang-bash">yay -Syu pamac-aur
</code></pre>
<h4 id="heading-install-libreoffice">Install LibreOffice</h4>
<p>Please install LibreOffice from <strong>Pamac GUI</strong>.</p>
<h4 id="heading-install-other-software">Install other software</h4>
<h5 id="heading-bluemail">Bluemail</h5>
<pre><code class="lang-bash">yay -S bluemail
</code></pre>
<h5 id="heading-pgadmin">pgadmin</h5>
<pre><code class="lang-bash">yay -S phppgadmin
</code></pre>
<h5 id="heading-xmind">XMind</h5>
<pre><code class="lang-bash">yay -S xmind
</code></pre>
<h5 id="heading-opera-browser">Opera Browser</h5>
<pre><code class="lang-bash">yay -S opera
</code></pre>
<h5 id="heading-artha-dictionary">Artha (Dictionary)</h5>
<p>Artha is a dictionary application. Something similar to <strong>Wordweb</strong> on Windows.</p>
<pre><code class="lang-bash">yay -S artha
</code></pre>
<h5 id="heading-visual-studio-code">Visual Studio Code</h5>
<p>To install the official VS Code, install the following. This is not the open-source version and supports settings to sync with your GitHub account.</p>
<pre><code class="lang-bash">yay -S visual-studio-code-bin
</code></pre>
<h5 id="heading-git-client-gitqlient">Git Client (gitqlient)</h5>
<pre><code class="lang-bash">yay -S gitqlient
</code></pre>
<h5 id="heading-docker-desktop">Docker Desktop</h5>
<pre><code class="lang-bash">yay -S docker-desktop
</code></pre>
<h3 id="heading-shell-extensions">Shell extensions</h3>
<h4 id="heading-blur-my-shell-extension">Blur-my-Shell Extension</h4>
<p>Blur my shell is a popular extension that adds a blur look to different parts of the GNOME Shell.</p>
<pre><code class="lang-bash">yay -S gnome-shell-extension-blur-my-shell
</code></pre>
<h4 id="heading-caffeine">Caffeine</h4>
<p>This is a shell extension used to disable the screensaver and auto-suspend. It helps to keep your computer awake.</p>
<pre><code class="lang-bash">yay -S gnome-shell-extension-caffeine
</code></pre>
<h4 id="heading-custom-accent-colours">Custom Accent Colours</h4>
<p>This is a GNOME Shell Extension that provides 7 Custom Accent Colours. The selected Accent Colour can be applied to GTK4/GTK3 apps and the Gnome Shell.</p>
<pre><code class="lang-bash">yay -S gnome-shell-extension-custom-accent-colors-git
</code></pre>
<h3 id="heading-other-customisation">Other customisation</h3>
<h4 id="heading-icons">Icons</h4>
<p>If the default icon pack in EndeavourOS is not exciting enough for you, find some icon pack by searching in pacman.</p>
<pre><code class="lang-bash">pacman -Ss icon
</code></pre>
<p>Install the icon pack:</p>
<pre><code class="lang-bash">sudo pacman -S obsidian-icon-theme
</code></pre>
<h4 id="heading-keyboard-shortcuts">Keyboard shortcuts</h4>
<p>Following are some of the keyboard shortcuts I added.</p>
<h5 id="heading-launchers">Launchers</h5>
<ul>
<li><p>Win (Super) + E : Open Home folder</p>
</li>
<li><p>Win (Super) + F : Launch web browser</p>
<ul>
<li>My browser is Firefox</li>
</ul>
</li>
<li><p>Ctrl + Shift + F : Search</p>
</li>
</ul>
<h5 id="heading-navigation">Navigation</h5>
<ul>
<li>Win (Super) + D : Hide all normal windows</li>
</ul>
<h5 id="heading-custom-shortcuts">Custom Shortcuts</h5>
<ul>
<li><p>Win (Super) + T : Terminal</p>
<ul>
<li>Use command : <code>gnome-terminal --geometry 132x43</code></li>
</ul>
</li>
<li><p>Win (Super) + O : Obsidian</p>
<ul>
<li>Use command : <code>obsidian</code></li>
</ul>
</li>
</ul>
<p>Here is a preconfigured keyboard shortcut that might be helpful for you:</p>
<ul>
<li>Win (Super) + A : Opens app drawer</li>
</ul>
<h1 id="heading-conclusion">Conclusion</h1>
<p>So far, EndeavourOS seems to be one of the best Linux distros that suits my needs perfectly, and I am more than tempted to install it on my laptop as well. Kudos to the developers and contributors for their wonderful effort in making EndeavourOS what it is now.</p>
<p>Please share your experience with EndeavourOS with me, and don't hesitate to get in touch if you need better clarity on something I mentioned in this article.</p>
<p>Add a custom wallpaper of your choice, and enjoy using EndeavourOS.</p>
<blockquote>
<p>[!Ouote]: The Linux philosophy is - 'Laugh in the face of danger'. Oops. Wrong One. 'Do ot yourself'. Yes, that's it.</p>
<p>~ Linus Torvalds</p>
</blockquote>
]]></content:encoded></item><item><title><![CDATA[Introducing Brain Bank Obsidian vault!]]></title><description><![CDATA[Introduction
Over the years, I’ve experimented with a variety of note-taking and idea-organising tools, including Evernote, OneNote, Notion, and Confluence, to name a few. Each of these tools has its strengths and weaknesses. However, a common issue ...]]></description><link>https://artofcoding.dev/introducing-brain-bank-obsidian-vault</link><guid isPermaLink="true">https://artofcoding.dev/introducing-brain-bank-obsidian-vault</guid><category><![CDATA[#BrainBank]]></category><category><![CDATA[#ObsidianVault]]></category><category><![CDATA[#Obsidian-Vault]]></category><category><![CDATA[obsidian]]></category><category><![CDATA[obsidianmd]]></category><category><![CDATA[note-taking]]></category><category><![CDATA[note-taking-app]]></category><category><![CDATA[Notetaking]]></category><category><![CDATA[Notetaking Apps]]></category><category><![CDATA[digital notes]]></category><category><![CDATA[productivity tools]]></category><category><![CDATA[Productivity]]></category><category><![CDATA[KnowledgeManagement]]></category><category><![CDATA[knowledgebase]]></category><category><![CDATA[markdown]]></category><dc:creator><![CDATA[Febin Joy]]></dc:creator><pubDate>Mon, 27 May 2024 09:02:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1716785996696/b4f5e03c-4707-4574-b2f4-0d265625be46.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>Over the years, I’ve experimented with a variety of note-taking and idea-organising tools, including Evernote, OneNote, Notion, and Confluence, to name a few. Each of these tools has its strengths and weaknesses. However, a common issue I encountered was that I often had to adjust my workflow to fit the tool, rather than the tool adapting to my needs. This is typically the case when features are tightly integrated, which isn’t necessarily a bad thing, but it wasn’t what I was looking for. I was more interested in a tool that could work in harmony with me, a tool where I could freely express my ideas and retrieve them later without having to spend a significant amount of time organising them into a folder structure.</p>
<p>Many people find different tools valuable for various reasons. It’s all about discovering the tool that best aligns with your personal workflow. I discovered that Obsidian met all my needs. At first, I used it just like any other note-taking tool, organising notes into folders and using it as a Markdown editor. However, after watching some insightful videos about its powerful features, I realised how much customisation could enhance its utility. This experience transformed my perspective on the tool and its potential.</p>
<h2 id="heading-birth-of-brain-bank">Birth of Brain Bank</h2>
<p>As a writer of short stories, I began using Obsidian as my primary writing tool. This experience led me to explore the numerous built-in and community plugins that Obsidian offers. As a software professional, I quickly recognised the potential impact this tool could have on my productivity. It became an invaluable resource for organising my research, managing the content for my blog, tracking various topics I wanted to learn or explore, keeping a record of the books I’ve read, and even maintaining a list of movies I plan to watch. In essence, Obsidian has become a second brain for me, a place where all this information can coexist and be easily accessed.</p>
<p>I came across several intriguing videos on YouTube that demonstrated how to maximise the use of Obsidian. Listing all the articles and videos I found would certainly make this article quite lengthy, so I won’t delve into that for now. However, I gathered a wealth of information from these resources and began constructing a folder structure, templates, tag notes, and more to create a foundational vault. This vault can be taken by anyone and further customised to their liking. When I started building it, my initial challenge was deciding on a name for it, as I needed to create a GitHub repository to share it with the community. Ultimately, I chose the name “Brain Bank”, which I felt perfectly encapsulated my concept of a second brain where ideas and notes collate.</p>
<h1 id="heading-how-is-brain-bank-different-from-a-default-obsidian-vault">How is Brain Bank different from a default Obsidian vault?</h1>
<p>An Obsidian vault is essentially a self-contained folder where all the plugins and customisation are local to that vault. If you create a new vault, you’ll need to install the plugins and customise it according to your preferences. With Brain Bank, I’ve developed a vault that includes a wealth of templates, tags, tag notes, Maps of Content (MoCs), and more. This means that anyone who wants to use Obsidian with a similar workflow won’t have to start from scratch. More detailed information about it can be found <a target="_blank" href="https://github.com/robertmartin8/MolecularNotes">here</a>.</p>
<p>If a default Obsidian vault is similar to a blank canvas, then using Brain Bank is like having a pre-drawn sketch. Here are some of the enhancements Brain Bank offers compared to a default Obsidian vault:</p>
<ul>
<li><p><strong>Pre-created, Colour-coded Folder Structure</strong>: Brain Bank provides a ready-to-use, colour-coded folder structure, making it easier to manage your notes from the get-go. In contrast, a default Obsidian vault starts as a blank slate, allowing users to create their own folder structure. You are free to modify the preconfigured folder structure to your liking.</p>
</li>
<li><p><strong>Enhanced Note Creation</strong>: Brain Bank introduces tags, tag notes, Maps of Content (MoCs), and templates to enhance note creation. Tags allow efficient categorisation and grouping of related notes. Tag notes are predefined notes used in templates to group together all notes of a specific type. Templates, preloaded with tag notes, provide a consistent format for specific types of content (e.g., meeting notes, action items).</p>
</li>
<li><p><strong>Customised User Experience with Plugins</strong>: Brain Bank utilises both built-in and community plugins to enhance the user experience. These plugins allow users to customise their environment, add features, and optimise their workflow. Users are free to add more plugins to their liking or disable the ones as deemed.</p>
</li>
<li><p><strong>Keyboard Shortcuts</strong>: Brain Bank includes additional keyboard shortcuts for common actions, facilitating faster navigation and note creation.</p>
</li>
<li><p><strong>Predefined Locations for Saving Notes Automatically</strong>: Brain Bank provides predefined default folders for specific types of notes. When you create a note of a certain category, it automatically gets saved in the appropriate folder.</p>
</li>
<li><p><strong>Colour-coded Graph View for Easy Identification</strong>: Brain Bank introduces a colour-coded graph view that enhances visual navigation. Notes of different types (based on parent folders) are represented using distinct colours, making it easier to identify related content.</p>
</li>
<li><p><strong>Custom Dashboard for Easy Access and Overview</strong>: Brain Bank offers a custom dashboard that provides users with a centralised hub for accessing their vault. This dashboard typically includes quick links to frequently accessed notes or folders and an overview of recent activity, such as recently modified notes.</p>
</li>
<li><p><strong>Integrated Kanban Board</strong>: Brain Bank integrates a Kanban board directly within the note-taking environment. Notes can be moved between columns, providing a visual representation of progress.</p>
</li>
</ul>
<p>In essence, Brain Bank offers a more structured and feature-rich starting point for users, reducing the need for extensive customisation and setup. It’s like having a second brain where your ideas and notes collate.</p>
<h1 id="heading-how-does-it-look-like">How does it look like?</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716789209609/02c350ed-f5b0-49e7-b368-7d646c920324.png" alt class="image--center mx-auto" /></p>
<p>Here’s a snapshot of the default Obsidian interface with a Brain Bank vault open. It provides a glimpse into the organised and feature-rich environment that Brain Bank offers.</p>
<h1 id="heading-how-do-someone-getuse-it">How do someone get/use it?</h1>
<p>For those interested in using Brain Bank, it can be downloaded from the GitHub repository at this link - <a target="_blank" href="https://github.com/febinjoy/brainbank/releases">https://github.com/febinjoy/brainbank/releases</a>.</p>
<p>For detailed instructions on how to use the customisation in Brain Bank, please refer to this Wiki pages -</p>
<ul>
<li><p><a target="_blank" href="https://github.com/febinjoy/brainbank/wiki">https://github.com/febinjoy/brainbank/wiki</a>,</p>
</li>
<li><p><a target="_blank" href="https://github.com/febinjoy/brainbank/wiki/Getting-Started">https://github.com/febinjoy/brainbank/wiki/Getting-Started</a> and</p>
</li>
<li><p><a target="_blank" href="https://github.com/febinjoy/brainbank/wiki/How-to-use-BrainBank">https://github.com/febinjoy/brainbank/wiki/How-to-use-BrainBank</a></p>
</li>
</ul>
<p>They provide a comprehensive guide to help you make the most of Brain Bank’s features.</p>
<h1 id="heading-what-if-there-are-questions">What if there are questions?</h1>
<p>Feel free to reach out to me using the GitHub repo's discussions here - <a target="_blank" href="https://github.com/febinjoy/brainbank/discussions">https://github.com/febinjoy/brainbank/discussions</a>. I am more than happy to help you out. Please do not limit it to questions. You can let me know about feature suggestions, ideas and feedback as well.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1716789906985/71479045-e0f8-4c73-be8d-22cf98fe039b.png" alt /></p>
<h1 id="heading-shout-outs">Shout-outs</h1>
<p>Brain Bank, owes its seamless experience to the brilliant minds behind various community plugins and the Obsidian team. These plugins enhance functionality, boost productivity, and elevate your note-taking game. Let’s give a huge round of applause to these talented authors and contributors!</p>
<p>I would personally like to thank each and every user of Brain Bank for the support. Remember, Brain Bank is now your digital sanctuary for thoughts, ideas, and knowledge. Feel free to adapt, expand and customise your vault as your knowledge grows. The vault is only as powerful as the ideas it holds.</p>
<p>Happy Note-taking!!!</p>
]]></content:encoded></item><item><title><![CDATA[Things to do after installing Fedora 40]]></title><description><![CDATA[April 2024 saw the release of 2 very popular Linux distros — Fedora 40 and Ubuntu 24.04 LTS. As everyone knows, Fedora is a rolling release and Ubuntu 24.04 is a long-term support version. Both use the latest version of GNOME — GNOME 46. Be your own ...]]></description><link>https://artofcoding.dev/things-to-do-after-installing-fedora-40</link><guid isPermaLink="true">https://artofcoding.dev/things-to-do-after-installing-fedora-40</guid><category><![CDATA[fedora40]]></category><category><![CDATA[flathub]]></category><category><![CDATA[gnome-tweaks]]></category><category><![CDATA[fedora-customise]]></category><category><![CDATA[fedora-customize]]></category><category><![CDATA[gnome-customise]]></category><category><![CDATA[gnome-customize]]></category><category><![CDATA[Fedora]]></category><category><![CDATA[Fedoralinux]]></category><category><![CDATA[dnf]]></category><category><![CDATA[flatpak]]></category><category><![CDATA[Gnome]]></category><category><![CDATA[linux for beginners]]></category><category><![CDATA[Linux installation]]></category><category><![CDATA[post-install]]></category><dc:creator><![CDATA[Febin Joy]]></dc:creator><pubDate>Sat, 04 May 2024 14:50:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1714833181687/35bad1d3-4a43-4b92-99f5-4e0df9df1eb3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>April 2024 saw the release of 2 very popular Linux distros — Fedora 40 and Ubuntu 24.04 LTS. As everyone knows, Fedora is a rolling release and Ubuntu 24.04 is a long-term support version. Both use the latest version of GNOME — GNOME 46. Be your own judge, and you are welcome to choose the distro that suits your purpose. You won't go wrong with either of them.</p>
<p>I completed reinstalling my laptop with Fedora 40 and just thought of sharing my workflow of setting up Fedora with you. Most of these work for Ubuntu as well.</p>
<h1 id="heading-step-1-install-the-os">Step 1: Install the OS</h1>
<p>Download the OS from the links below and create an installation disk. Follow the on-screen instructions and install the OS using the installation disk.</p>
<ul>
<li><p>Fedora Workstation — <a target="_blank" href="https://fedoraproject.org/workstation/download">https://fedoraproject.org/workstation/download</a></p>
</li>
<li><p>Ubuntu 24.04 — <a target="_blank" href="https://ubuntu.com/download/desktop">https://ubuntu.com/download/desktop</a></p>
</li>
</ul>
<h1 id="heading-step-2-improvements">Step 2: Improvements</h1>
<p>If any software update window pops up, please install the updates and restart the computer.</p>
<h2 id="heading-set-hostname">Set Hostname</h2>
<p>The default hostname of the system after installing the OS would be <code>fedora</code>. You can change it with the following. Replace <code>&lt;hostname&gt;</code> with the hostname of your choice. It is recommended to restart the PC after this step.</p>
<pre><code class="lang-bash">sudo hostnamectl set-hostname &lt;hostname&gt;
</code></pre>
<h2 id="heading-configure-dnf">Configure DNF</h2>
<p>Fedora 40 uses <strong>DNF</strong> as its package manager. It provides secure package management and lets you query and fetch packages, install and uninstall them using automatic dependency resolution. Ubuntu users might be familiar with its alternative — <strong>APT</strong>.</p>
<p>DNF searches for packages and downloads them from various mirrors. It may not be using the fastest mirror and may take way more time to download packages. Its performance could be improved as follows:</p>
<p>Open the following file using the <code>nano⁣</code> command:</p>
<pre><code class="lang-bash">sudo nano /etc/dnf/dnf.conf
</code></pre>
<p>Add the following to the end of the file:</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Added for speed:</span>
fastestmirror=True
max_parallel_downloads=10
defaultyes=True
keepcache=True
</code></pre>
<p>These are DNF configuration changes which will help you speed up installing software. The full reference of the DNF configuration is available here — <a target="_blank" href="https://dnf.readthedocs.io/en/latest/conf_ref.html">https://dnf.readthedocs.io/en/latest/conf_ref.html</a>. If required, include other config changes as well.</p>
<h2 id="heading-add-flathub">Add Flathub</h2>
<p>Like DNF, Flatpak is another package manager supported by both Fedora and Ubuntu. It is a utility for software deployment that offers a sandbox environment. This allows the users to install and run applications, keeping them isolated from the rest of the system. This makes it more secure and takes away the worries about dependencies/libraries required to run the software. Flatpak uses many online repositories, and FlatHub is one such repository that distributes the applications to Flatpak users.</p>
<p>Add the FlatHub repo to Flatpak using the following:</p>
<pre><code class="lang-bash"> sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
</code></pre>
<h2 id="heading-update-your-system">Update your system</h2>
<p>The first thing to do after installing the OS and setting up the repositories is to update your system. Use the following command to update the system. When prompted, enter your password. Use <code>apt</code> instead of <code>dnf</code> on Ubuntu.</p>
<pre><code class="lang-bash"> sudo dnf update
</code></pre>
<h1 id="heading-step-3-essential-configuration-and-software">Step 3: Essential configuration and software</h1>
<p>The first software I would install on any Linux PC would be Timeshift. It is a backup tool that allows capturing the snapshot of the system. You can install it using the software application or use the following command to do it.</p>
<pre><code class="lang-bash">sudo dnf install timeshift -y
</code></pre>
<p>Once the tool is installed, take a backup before installing any other software. Make sure you choose all files when configuring backups.</p>
<h2 id="heading-install-both-free-and-non-free-rpm-fusion"><strong>Install both Free and Non-Free RPM Fusion</strong></h2>
<p>RPM Fusion provides software that the Fedora Project or Red Hat doesn't want to ship. Download and install both the free and non-free versions of RPM fusion from here — <a target="_blank" href="https://rpmfusion.org/Configuration">https://rpmfusion.org/Configuration</a>.</p>
<h2 id="heading-install-media-codecs"><strong>Install media codecs</strong></h2>
<p>Fedora does not come with all the required media codecs pre-installed. Install the media codecs using the following:</p>
<pre><code class="lang-bash">sudo dnf groupupdate multimedia --setop=<span class="hljs-string">"install_weak_deps=False"</span> --exclude=PackageKit-gstreamer-plugin
sudo dnf groupupdate sound-and-video
</code></pre>
<h2 id="heading-install-dnfdragora"><strong>Install DnfDragora</strong></h2>
<p>dnfdragora is a DNF frontend, based on rpmdragora from Mageia. Install it using the following:</p>
<pre><code class="lang-bash">sudo dnf install dnfdragora
</code></pre>
<h2 id="heading-install-git"><strong>Install git</strong></h2>
<p>Usually <code>git</code> comes pre-installed in Fedora. Run the following to ensure it is installed.</p>
<pre><code class="lang-bash">sudo dnf install git
</code></pre>
<h2 id="heading-install-bitwarden">Install Bitwarden</h2>
<p>I, personally, use Bitwarden as my password manager and that would be one of the first software that I would install as it helps me with all the passwords to log in to other apps and services easily.</p>
<h1 id="heading-step-4-install-required-software">Step 4: Install required software</h1>
<h2 id="heading-install-from-flatpak">Install from Flatpak</h2>
<p>As much as possible, I install all the software I need as Flatpak. In the home directory, create a new folder — <code>setup</code> and create a new file — <code>install_from_</code><a target="_blank" href="http://file.sh"><code>file.sh</code></a>. Open the <code>setup</code> folder in terminal and open the file using <code>nano</code>.</p>
<pre><code class="lang-bash">sudo nano install_from_file.sh
</code></pre>
<p>You can add all the Flatpak that you need to install in this shell script.</p>
<p>e.g. If you need to install <code>gimp</code> and <code>vlc</code>, the shell script will be as follows:</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>
flatpak install gimp -y
flatpak install vlc -y
</code></pre>
<p>The <code>-y</code> flag will automatically respond <code>yes</code> whenever the installer raises a user prompt. If you want more control, remove the flag and manually approve each prompt. You can search flatpak for packages using:</p>
<pre><code class="lang-bash">flatpak search &lt;package name&gt;
</code></pre>
<p>Once you have all the packages listed in the file, we must run the script to install them.</p>
<p>Make the script executable using the following:</p>
<pre><code class="lang-bash">sudo chmod +x install_from_file.sh
</code></pre>
<p>Execute the file:</p>
<pre><code class="lang-bash">sudo ./install_from_file.sh
</code></pre>
<p>This will install all the packages one by one. If flatpak identifies more than one package with the name we mentioned, it will prompt you to choose which one to install. Select the one you require when prompted.</p>
<p>Installing using this script saves a lot of time searching for the packages and installing them as I already have a backup of the <code>install_from_file.sh</code> readily available. Keep the contents of this file in your Google Drive or email it to yourself for later use. Whenever I reinstall the OS, I use the backup of the script to install all my tools.</p>
<h3 id="heading-software-worth-mentioning">Software worth mentioning</h3>
<p>Some notable software I, personally, use from flatpak are listed below:</p>
<ul>
<li><p><strong>PyCharm</strong> as my Python editor</p>
</li>
<li><p>Meld for comparing files and folders</p>
</li>
<li><p>Tick Tick as a Todoist alternative</p>
</li>
<li><p>Discord</p>
</li>
<li><p>Bluemail as my email client</p>
</li>
<li><p>VLC</p>
</li>
<li><p>Gimp for editing images</p>
</li>
<li><p>Reaper for audio editing</p>
</li>
<li><p>Rawtherapee for editing RAW images</p>
</li>
<li><p>MarkText as my Markdown editor</p>
</li>
<li><p>Obsidian for organising my notes</p>
</li>
<li><p>Joplin and Simplenote for all the text that I need to sync across other devices</p>
</li>
<li><p>Artha as a dictionary tool</p>
</li>
<li><p>XMind for mind mapping</p>
</li>
<li><p>Bleachbit for system cleanup</p>
</li>
<li><p>Missioncenter as a system resource monitoring tool.</p>
</li>
<li><p>Krita for drawing</p>
</li>
</ul>
<h2 id="heading-other-software">Other Software</h2>
<h3 id="heading-install-vs-code">Install VS Code</h3>
<p>Download RPM from <a target="_blank" href="https://code.visualstudio.com/download">https://code.visualstudio.com/download</a> and install VS Code. If you are already using VS Code on any other machine, sync the extensions by logging in using GitHub or Microsoft account.</p>
<h3 id="heading-install-jre">Install JRE</h3>
<p>Run the following to install JRE</p>
<pre><code class="lang-bash">sudo dnf install java-openjdk
</code></pre>
<h3 id="heading-install-nodejs">Install Node.js</h3>
<p>Install Node.js and NPM using the following commands:</p>
<pre><code class="lang-bash">sudo dnf install nodejs
sudo dnf install npm
</code></pre>
<p>Verify the installation using the following commands:</p>
<pre><code class="lang-bash">node -v
npm -v
</code></pre>
<h3 id="heading-install-net-sdk">Install .Net SDK</h3>
<p>Use the following to install .Net SDK</p>
<pre><code class="lang-bash">sudo dnf install dotnet-sdk-8.0 -y
</code></pre>
<h3 id="heading-install-microsoft-edge">Install Microsoft Edge</h3>
<p>Personally, I use Edge and Firefox for most of my browsing needs. Firefox comes pre-installed with Fedora. If you wish, you can download and install edge by following the steps below:</p>
<ul>
<li><p>Download RPM from Microsoft and install — <a target="_blank" href="https://www.microsoft.com/en-us/edge/business/download?form=MA13FJ">https://www.microsoft.com/en-us/edge/business/download?form=MA13FJ</a></p>
</li>
<li><p>Login to browser profiles so that all the bookmarks and extensions are synchronised</p>
</li>
<li><p>Login to each extension that requires a login.</p>
</li>
</ul>
<h2 id="heading-extensions">Extensions</h2>
<p>Install <strong>Gnome Tweaks</strong> from the software centre and enable the minimise and maximise buttons.</p>
<p>Install <strong>Extensions Manager</strong> from Flatpak. It is also available here — <a target="_blank" href="https://flathub.org/apps/com.mattjakeman.ExtensionManager">https://flathub.org/apps/com.mattjakeman.ExtensionManager</a></p>
<p>Some notable extensions are listed below:</p>
<ul>
<li><p>Dash to Dock</p>
</li>
<li><p>Blur my Shell</p>
</li>
<li><p>Clipboard Indicator</p>
</li>
<li><p>Coverflow Alt-Tab</p>
</li>
<li><p>Caffeine</p>
</li>
<li><p>Custom accent colors</p>
</li>
<li><p>User Themes</p>
<ul>
<li>Set theme to custom accent colors</li>
</ul>
</li>
</ul>
<h1 id="heading-other-miscellaneous-tweaks">Other miscellaneous tweaks</h1>
<h2 id="heading-connect-your-online-accounts">Connect your online accounts</h2>
<p>If you want to access your Google Drive like a mounted disk on your system, add it from the settings. It also syncs your calendar with the built-in Calendar app.</p>
<p>If the browser window did not pop up to login to google account, it is because the control centre is broken. Run the following:</p>
<pre><code class="lang-bash">WEBKIT_DISABLE_COMPOSITING_MODE=1 gnome-control-center
</code></pre>
<h2 id="heading-setup-clocks">Setup Clocks</h2>
<p>If you want to keep track of the time at a different location, add it to the built-in clock app.</p>
<h2 id="heading-install-themes-and-icons">Install themes and Icons</h2>
<p>Use DnfDragora to install themes and Icon packs, and use the tweaks app to choose them.</p>
<h1 id="heading-conclusion">Conclusion</h1>
<p>Hardening a Linux system is already covered here — <a target="_blank" href="https://hashnode.com/post/clqf5dl9g000108ib52dhfayi">https://hashnode.com/post/clqf5dl9g000108ib52dhfayi</a></p>
<p>Add a custom wallpaper of your choice and enjoy using Fedora 40.</p>
<h4 id="heading-shout-outs-and-courtesy-notes">Shout-outs and courtesy notes</h4>
<p>Photo by <a target="_blank" href="https://unsplash.com/@jan_huber?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Jan Huber</a> on <a target="_blank" href="https://unsplash.com/photos/blue-and-white-bokeh-lights-3Btf2cTAGKs?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash">Unsplash</a> for the cover picture background.</p>
]]></content:encoded></item><item><title><![CDATA[Linux hardening for beginners]]></title><description><![CDATA[Introduction

Many developers have utilised Linux for various tasks and projects during their careers, with many opting for it as their primary operating system. One of the key factors driving this choice is security. Linux is frequently regarded as ...]]></description><link>https://artofcoding.dev/linux-hardening-for-beginners</link><guid isPermaLink="true">https://artofcoding.dev/linux-hardening-for-beginners</guid><category><![CDATA[linux-security]]></category><category><![CDATA[securing-linux]]></category><category><![CDATA[linux-hardening]]></category><category><![CDATA[linux for beginners]]></category><category><![CDATA[Linux]]></category><category><![CDATA[linux-basics]]></category><dc:creator><![CDATA[Febin Joy]]></dc:creator><pubDate>Thu, 21 Dec 2023 11:56:51 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1703069797746/149b94c3-a868-46e9-a1b3-5ca6fcd20c1c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703077634896/6a911bd4-cb4d-45a0-bb78-75fefe9d654b.png" alt class="image--center mx-auto" /></p>
<p>Many developers have utilised Linux for various tasks and projects during their careers, with many opting for it as their primary operating system. One of the key factors driving this choice is security. Linux is frequently regarded as more secure than Windows for several reasons:</p>
<p><strong>Open-Source:</strong> Linux's security is boosted by its open-source nature, allowing a large community to identify and fix vulnerabilities quickly.</p>
<p><strong>Diversity:</strong> Linux's numerous distributions, like Ubuntu, Debian, and Fedora, let users customise security and features for their needs.</p>
<p><strong>Privilege separation:</strong> Linux's strict privilege model limits user and process permissions, preventing unauthorised access and reducing attack risks.</p>
<p><strong>Centralised package management</strong>: Linux distributions offer secure package management systems for installing, updating, and verifying software from trusted sources, reducing malware risks.</p>
<p><strong>Strong user and permission management</strong>: Linux provides a robust system for managing users and permissions, enabling administrators to set accurate access controls and limit privileges, enhancing security against unauthorised access and breaches.</p>
<p>System security relies on many things, like proper configuration, timely updates, user awareness, and adherence to security best practices, as no operating system is entirely immune to security risks. Different Linux distributions come with preinstalled applications and configurations, but their default settings might not be sufficiently hardened to minimise the potential attack surface.</p>
<p>In this article, we'll explore various configuration improvements to strengthen your Linux machine or server's security, safeguarding confidentiality, preserving integrity, and ensuring availability against potential attacks. Since this topic is too vast and deep, this article is designed only to act as a signboard which will lead you in the right direction towards security.</p>
<h2 id="heading-what-and-how">What and How?</h2>
<p>Let us categorise this as per MoSCoW prioritisation(<a target="_blank" href="https://en.wikipedia.org/wiki/MoSCoW_method">MoSCoW method - Wikipedia</a>) method into the following:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703076829792/33db2c87-a12b-406b-b98a-4ce339ab088e.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-must-have">Must have</h3>
<h4 id="heading-choose-the-right-distro">Choose the right distro</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703079757465/ac6c8857-ce0d-4b36-9cbc-04b5b5aa4398.png" alt class="image--center mx-auto" /></p>
<p>Here are several examples of the many Linux distributions available for you to choose.</p>
<ul>
<li><p>Ubuntu</p>
</li>
<li><p>OpenSUSE</p>
</li>
<li><p>Debian</p>
</li>
<li><p>Fedora</p>
</li>
<li><p>Linux Mint</p>
</li>
<li><p>CentOS</p>
</li>
<li><p>Arch Linux</p>
</li>
</ul>
<p>Each distribution has its own strengths, target audience, and purpose. It is crucial to investigate and select the one that best meets your needs in terms of usability, software availability, community support, and specific requirements.</p>
<p><strong>Factors to consider:</strong></p>
<ul>
<li><p>Usage. It should be the right version and flavour for your job. You are the best person to judge.</p>
</li>
<li><p>Hardware requirements.</p>
</li>
<li><p>Long-term support. (Find a right balance between the latest version and LTS)</p>
</li>
<li><p>Ease of use.</p>
</li>
<li><p>Stability and security.</p>
</li>
<li><p>Community support.</p>
</li>
<li><p>Previous experience (If you are familiar with a distro, pick the same unless if you want to try a new one).</p>
</li>
</ul>
<h4 id="heading-update-the-os-and-package-manager">Update the OS and Package Manager</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703153560177/1d543059-1167-44fe-aaae-28244b0af1bd.png" alt class="image--center mx-auto" /></p>
<p>The first thing you need to do after installing a Linux distro of your choice is to update it. There may be patches available which fix bugs and vulnerabilities. How you do this greatly depends on your choice of distro. Different distros use different package managers. For this article, I would be focusing more on the package manager: <code>apt</code> used by Debian-based Linux distros like Debian, Ubuntu, Linux Mint, and elementary OS. You can use the alternates for the distro of your choice.</p>
<p>Run the following after spinning up the machine. (The <code>-y</code> flag will say yes to all prompts for confirmation. If you want to review and proceed, please remove it.)</p>
<pre><code class="lang-bash">sudo apt update
sudo apt -y upgrade
</code></pre>
<blockquote>
<p>Quick Tip:</p>
<p><strong>Use</strong> <code>apt</code> <strong>instead of</strong> <code>apt-get</code></p>
<p>As mentioned earlier, <code>apt</code> which is an abbreviation of "Advanced Package Tool" and <code>apt-get</code> are package manager tools used in Debian-based Linux distros. The distinction between <code>apt</code> and <code>apt-get</code> goes beyond <code>apt</code> being a newer version of <code>apt-get</code>. The <code>apt</code> command was developed to provide a more user-friendly alternative to <code>apt-get</code>, consolidating the features of various package management tools for the ease of users.</p>
<p><strong>Use</strong> <code>dnf</code> <strong>instead of</strong> <code>yum</code></p>
<p>YUM, or "YellowDog Updater Modified", is a package manager designed for installing, updating, or removing software packages on Red Hat Enterprise Linux systems. On the other hand, DNF, which stands for Dandified YUM, is an enhanced version of the YUM package manager. The problems associated with YUM, such as sluggish performance, high memory consumption, and slow dependency resolution, have been addressed in DNF. This improved package manager offers increased efficiency and a more user-friendly experience for managing software packages on RedHat-based Linux systems.</p>
</blockquote>
<h4 id="heading-proper-user-management">Proper user management</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703153886185/5bddd1c1-feb4-4ca4-8c89-0c4fccfad60d.png" alt class="image--center mx-auto" /></p>
<p>User management is vital for system security, and mastering efficient account management techniques helps safeguard your server or machine from vulnerabilities.</p>
<h5 id="heading-root-user">Root User</h5>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703154737133/7ca4a4c1-a9f0-4a16-b71d-10ce28fbc554.png" alt class="image--center mx-auto" /></p>
<p>On Linux, the <code>root user</code>, also known as the <code>root account</code> or <code>superuser account</code>, is the administrator with the highest level of system privileges who possesses unlimited access to all files, directories, and system resources on the operating system. You can perform critical system administration tasks, such as installing software, modifying configurations, managing users and permissions, and accessing sensitive files that regular users cannot modify or access as a root user.</p>
<p>Exercise caution when using the root user account, and use regular user accounts for daily activities. Keeping the root login enabled can pose a security threat, as hackers can potentially use these credentials to gain access to the server. To strengthen your Linux system and harden it, you should disable root login.</p>
<p>Most of the distros come with the root user disabled by default. Do not enable it unless you know what you are doing. Some older versions of the popular distros come with root user enabled. It is always recommended to use the latest version of the OS.</p>
<h5 id="heading-sudo">Sudo</h5>
<p>The <code>sudo</code> command stands for either <code>substitute user do</code> or <code>super user do</code> and is typically used to execute commands as the root user, temporarily elevating a regular user's privileges for specific administrative tasks. This helps in enhancing security by limiting root account usage to only when required. You might have already seen me using <code>sudo</code> above when we tried to install updates.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703133210565/aa8fe9c1-ed44-4973-9ca9-a5b612196393.png" alt class="image--center mx-auto" /></p>
<h5 id="heading-sudoers">Sudoers</h5>
<p>If every user in the system can elevate themselves to have root privileges by using <code>sudo</code>, how does it make the system secure? Well, not all users can elevate themselves to have root privileges using <code>sudo</code>. They need to be part of <code>sudoers</code> group to do so.</p>
<p>Now what is <code>sudoers</code> group? The Linux <code>sudoers</code> group is a distinct group that provides selected users with the ability to execute commands with administrative privileges through the <code>sudo</code> command. This enables them to perform tasks that require higher permissions.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703134531364/74ab1e31-2806-4f40-9c5f-056e92feb4b9.webp" alt class="image--center mx-auto" /></p>
<h5 id="heading-how-to-review-sudoers-and-providerevoke-access">How to review Sudoers and provide/revoke access</h5>
<p>Using the following command would list all the <code>sudo</code> users in Ubuntu and Debian.</p>
<pre><code class="lang-bash">sudo grep -Po <span class="hljs-string">'^sudo.+:\K.*$'</span> /etc/group
</code></pre>
<p>If you want to add a particular user account to the sudoers list, use the following:</p>
<pre><code class="lang-bash">sudo adduser &lt;username&gt; sudo
</code></pre>
<p>To remove a user from the sudoers list, use the following:</p>
<pre><code class="lang-bash">sudo deluser &lt;username&gt; sudo
</code></pre>
<h5 id="heading-default-user-accounts">Default user accounts</h5>
<p>Some old versions of certain distros comes with pre-created user accounts. For example, older versions of Raspbian OS came with a user <code>pi</code> with password <code>raspberry</code>. This was dropped in OS version Bullseye. Please refer: <a target="_blank" href="https://www.raspberrypi.com/news/raspberry-pi-bullseye-update-april-2022/">https://www.raspberrypi.com/news/raspberry-pi-bullseye-update-april-2022/</a></p>
<p>Make sure your system does not have a pre-created user account.</p>
<p><strong>List all user accounts (Only usernames):</strong></p>
<pre><code class="lang-bash">sudo awk -F: <span class="hljs-string">'{ print $1}'</span> /etc/passwd
</code></pre>
<p><strong>Power users can try this (Usernames and permissions):</strong></p>
<pre><code class="lang-bash">sudo less /etc/passwd
</code></pre>
<p>To remove a user, use the <code>userdel</code> command. Using <code>-h</code> option after the command will list out all options available for the command.</p>
<pre><code class="lang-bash">sudo userdel &lt;username&gt;
</code></pre>
<p>Reviewing user permissions is also very critical on Linux machines. Going deep into it will blow up the proportions of this article. Please refer to this wonderful article: <a target="_blank" href="https://www.freecodecamp.org/news/how-to-manage-users-in-linux/">https://www.freecodecamp.org/news/how-to-manage-users-in-linux/</a> by <a target="_blank" href="https://www.freecodecamp.org/news/author/caesarsage/">Destiny Erhabor</a> for an elaborative article on Linux User Management.</p>
<h4 id="heading-passwords-and-login">Passwords and login</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703155460591/44f8da81-21f1-4781-af32-8068a0b95fba.png" alt class="image--center mx-auto" /></p>
<p>Having strong user and sudo passwords is essential for maintaining the security and integrity of any system. It protects the machine from unauthorised access and safeguards sensitive data. Weak passwords are vulnerable to various password-based attacks, such as brute-force attacks or dictionary attacks.</p>
<p>Remember to choose a strong password that is unique, complex, and not easily guessable. It is advised to use a combination of uppercase and lowercase letters, numbers, and special characters in your password. Regularly updating passwords and refraining from password reuse can further enhance the security of your Linux system.</p>
<p>Make sure you do not write down or save your passwords anywhere. Notepads, OneNote, Notion and other similar tools are not places destined to save passwords. If passwords are complex and difficult to remember, use a reputed password manager like Bitwarden or LastPass, which will store your passwords encrypted.</p>
<h4 id="heading-ssh">SSH</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703155646767/43c209b0-cdca-4c8d-a632-adce85023563.png" alt class="image--center mx-auto" /></p>
<p>SSH, or Secure Shell, is a network protocol enabling secure remote access and communication between two computers over an unsecured network, allowing users to safely access and control a remote computer or server from their device, regardless of distance. This is specifically useful in the case of servers.</p>
<p>It uses public-key cryptography to authenticate and establish a secure connection between the client (local computer) and the server (remote computer), exchanging cryptographic keys to verify each other's identity before connecting. Once the SSH connection is established, users can remotely execute commands, manage files, transfer data, and perform various administrative tasks on the remote system.</p>
<p>Using SSH for connecting to remote Linux machines is highly encouraged. The following are a few pointers that could be helpful in configuring SSH.</p>
<ul>
<li><p>Ensure you are using V2 of the SSH protocol</p>
</li>
<li><p>Ensure to have the following config set for SSH</p>
<ul>
<li><p>PermitEmptyPasswords no</p>
</li>
<li><p>PermitRootLogin no</p>
</li>
<li><p>MaxAuthTries 4</p>
</li>
<li><p>Allow only specific users (choose who can SSH)</p>
</li>
</ul>
</li>
<li><p>Change the default port: 22 to something else and deny all traffic to port 22.</p>
</li>
<li><p>Make sure that root cannot log in remotely through SSH</p>
</li>
<li><p>Configure IPTables(A Linux firewall) to restrict SSH access from known IPs only.</p>
</li>
<li><p>Key-based authentication should be used instead of password-based authentication.</p>
</li>
<li><p>Client keys should be encrypted to prevent their use in case they are stolen.</p>
</li>
<li><p>Use SSH tunnels if required.</p>
<ul>
<li>SSH tunnelling, also known as SSH port forwarding, is a technique that enables a user to open a secure tunnel between a local host and a remote host. More on that later.</li>
</ul>
</li>
</ul>
<h3 id="heading-should-have">Should have</h3>
<h4 id="heading-remove-unwanted-software-and-disable-unused-functionalities-and-services">Remove unwanted software and disable unused functionalities and services.</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703155805726/94ab2f1c-1b68-4075-9c21-b1086a700a15.png" alt class="image--center mx-auto" /></p>
<p>Operating systems often come preloaded with software and services that run constantly in the background without notice. To enhance the security of the machine, list all packages and software installed using your package managers (e.g. apt, dnf).</p>
<pre><code class="lang-bash">sudo apt list –-installed
</code></pre>
<p>Make sure to remove unwanted packages</p>
<pre><code class="lang-bash">sudo apt remove &lt;package name&gt;
</code></pre>
<p><strong>Ensure to check and close open ports</strong></p>
<p>Open ports can expose information about your network architecture, making it susceptible to attacks. Malicious actors can exploit these vulnerabilities to gain access to your server/machine. To mitigate this risk, regularly scan for open ports and close any that are not in use. Tools like netstat can help you identify open ports and promptly secure your server by closing them.</p>
<p><strong>Disable unused services</strong><br />Disable any unwanted services that you are not using. Make sure that the service is not in use or required before disabling.</p>
<pre><code class="lang-bash">sudo systemctl stop &lt;service name&gt;
sudo systemctl <span class="hljs-built_in">disable</span> &lt;service name&gt;
</code></pre>
<p>Furthermore, make sure that you are not installing any unwanted software.</p>
<h4 id="heading-firewall">Firewall</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703155125013/fe986411-1d98-458f-886d-03428c54e26b.png" alt class="image--center mx-auto" /></p>
<p>Firewalls are essential for enhancing the security of Linux systems and networks. They control access, block harmful traffic, and defend against unauthorised access attempts and play a vital role in maintaining system integrity. Make sure to install a firewall and configure it properly.</p>
<p>Here is a list of popular Linux firewalls:</p>
<ul>
<li><p>iptables</p>
</li>
<li><p>nftables</p>
</li>
<li><p>UFW (Uncomplicated Firewall)</p>
</li>
<li><p>Firewalld</p>
</li>
<li><p>Shorewall</p>
</li>
</ul>
<p>These are some examples of Linux firewalls. Each one has its own strengths, features, and ways to set it up. It's important to pick a firewall that fits your needs and works well with your network environment.</p>
<h4 id="heading-backups">Backups</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703156144912/3fc04bce-e847-4286-aba0-1ab870d4887e.png" alt class="image--center mx-auto" /></p>
<p>Backups are essential to the security of any system. It comes handy in the event of a security incident or disaster recovery. There are plenty of options available for backing up your Linux systems like:</p>
<ul>
<li><p>rsync: A command-line utility for file synchronisation and backup.</p>
</li>
<li><p>Bacula: An open-source network backup solution that offers a client-server architecture. It provides features like data compression, encryption, and backup scheduling. Bacula supports various backup methods, including full, differential, and incremental backups.</p>
</li>
<li><p>Amanda (Advanced Maryland Automatic Network Disk Archiver): A backup software that allows for centralised management of backups across multiple systems. It offers features like deduplication, encryption, and backup scheduling.</p>
</li>
<li><p>Duplicity: A command-line backup tool that focuses on secure and encrypted backups. It uses standard tools like GnuPG for encryption and supports various storage backends, including local file systems, FTP, SSH, and cloud storage providers. If you want to back up to cloud solutions like Amazon S3 or Microsoft Azure, Duplicity could be an option for you.</p>
</li>
<li><p>Clonezilla: Clonezilla is a disk imaging and cloning tool that creates exact copies (images) of entire disks or partitions, allowing for easy restoration in case of system failures or data loss</p>
</li>
<li><p>Timeshift: Timeshift is a system restore utility that creates snapshots of the operating system at different points in time.</p>
</li>
</ul>
<p>These are just a few examples. Each one has its pros and cons. You can opt to choose one or a combination of more that aligns with your backup requirements and preferences.</p>
<h4 id="heading-automate-patches-and-updates">Automate patches and updates</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703156471711/b31f635c-aad8-4bcb-b72d-cb8bd02fb239.png" alt class="image--center mx-auto" /></p>
<p>The Unattended Upgrades feature of Ubuntu (and other Debian-based distros) ensures that important security patches for installed packages are automatically downloaded and installed without needing any manual intervention from an end-user</p>
<pre><code class="lang-bash">sudo apt install unattended-upgrades &amp;&amp; systemctl <span class="hljs-built_in">enable</span> --now unattended-upgrades
</code></pre>
<h4 id="heading-disable-unused-peripherals">Disable unused peripherals</h4>
<p>Reduce the attack surface area by disabling the peripherals that are not in use.</p>
<p>e.g. A web server connected to a network using a LAN cable should not have Wi-Fi enabled.</p>
<h4 id="heading-disk-encryption">Disk Encryption</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703156656314/b33e0032-f975-463f-9ee0-63ec3d4e6c8c.png" alt class="image--center mx-auto" /></p>
<p>The decision to encrypt the hard disk greatly depends on how sensitive is the data the machine handles. If the Linux server/machine handles sensitive data, disk encryption is highly recommended.</p>
<p>Please refer <a target="_blank" href="https://ubuntu.com/core/docs/uc20/full-disk-encryption">https://ubuntu.com/core/docs/uc20/full-disk-encryption</a> for Ubuntu's disc encryption.</p>
<h4 id="heading-transport-layers-and-protocols">Transport layers and protocols</h4>
<p>Please try to stick to the following as much as possible.</p>
<ul>
<li><p>Use TLS 1.3 and HTTPS as much as possible.</p>
</li>
<li><p>Avoid Using FTP, Telnet, and Rlogin/Rsh Services</p>
<ul>
<li><p>Under most network configurations, usernames, passwords, FTP / telnet / RSH commands and transferred files can be captured by anyone on the same network using a packet sniffer.</p>
</li>
<li><p>The common solution to this problem is to use either OpenSSH , SFTP, or FTPS (FTP over SSL), which adds SSL or TLS encryption to FTP.</p>
</li>
</ul>
</li>
<li><p>If your network applications are not using the IPv6 protocol, disable it to decrease the attack surface area.</p>
</li>
</ul>
<h3 id="heading-could-have">Could have</h3>
<h4 id="heading-logging-and-auditing">Logging and Auditing</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703158878294/6e2a5b3c-48a5-4aa8-9f89-933a649ffb97.png" alt class="image--center mx-auto" /></p>
<p>We need to configure logging and auditing to collect all hacking and cracking attempts. By default, syslog stores data in <code>/var/log/` </code> directory. This is useful to find out software misconfiguration, which may open your system to various attacks.</p>
<h4 id="heading-mandatory-access-control">Mandatory Access Control</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703158661306/f9e6d1f6-165f-4d90-bd8a-8f7e4f8a6208.png" alt class="image--center mx-auto" /></p>
<p>Mandatory access control (MAC) systems give fine-grained control over what programs and applications can access. This means that your browser won't have access to your entire home directory or similarly.</p>
<p>There are two prominent options among the various others worth mentioning.</p>
<p><strong>SELinux:</strong> SELinux aka Security-Enhanced Linux, is a fantastic security system for Linux. It provides different security policies for the Linux kernel. This overlay allows you to control processes access to files in the file system. Only a program with the appropriate role can access a specific resource, and even superuser privileges are not relevant. SELinux significantly enhances the security of the Linux system, as even the root user is considered a regular user here.</p>
<p><strong>AppArmor:</strong> The AppArmor system is used on Ubuntu and operates similarly to SELinux. Profiles are created for each application, specifying which files the application can access, while denying access to everything else.</p>
<h4 id="heading-sandboxing">Sandboxing</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703158443848/b2d078ef-0644-428d-aefc-a77f7d229d1f.png" alt class="image--center mx-auto" /></p>
<p>A sandbox allows you to run a program in an isolated environment that has either limited access or none to the rest of your system. You can use these to secure applications or run untrusted programs.</p>
<p>Containerisation platforms like Docker and Bubblewrap are worth mentioning here.</p>
<h3 id="heading-wont-have">Won't have</h3>
<p>We don't have much to mention here in this section, except for the following:</p>
<ul>
<li><p>Weaker policies and practices.</p>
</li>
<li><p>Reluctance to update yourself and the server/machine.</p>
</li>
</ul>
<h3 id="heading-conclusion">Conclusion</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703159349623/11ce6629-d1aa-4bde-8378-02afdc9f9709.png" alt class="image--center mx-auto" /></p>
<h4 id="heading-security-is-a-journey-not-a-destination">Security is a Journey, Not a destination</h4>
<p>The Linux system hardening steps and configurations mentioned above will help boost the security of your Linux servers and machines. However, always remember that security is an ongoing process that requires regular checks, software updates, and data backups.</p>
<p>Once you have hardened the system as much as you can, please follow good privacy and security practices:</p>
<ul>
<li><p>Disable or remove things you don't need to minimise attack surface.</p>
</li>
<li><p>Stay updated. Configure a cron job or init script to update the system daily.</p>
</li>
<li><p>Don't leak any information about the system, no matter how minor it may seem.</p>
</li>
<li><p>Follow general security and privacy advice.</p>
</li>
</ul>
<h4 id="heading-shout-outs-and-courtesy-notes">Shout-outs and courtesy notes</h4>
<ul>
<li><p>Image by <a target="_blank" href="https://pixabay.com/users/openclipart-vectors-30363/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=149971">OpenClipart-Vectors</a> from <a target="_blank" href="https://pixabay.com//?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=149971">Pixabay</a></p>
</li>
<li><p>Image by <a target="_blank" href="https://pixabay.com/users/stocksnap-894430/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=926837">StockSnap</a> from <a target="_blank" href="https://pixabay.com//?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=926837">Pixabay</a></p>
</li>
<li><p>Image by <a target="_blank" href="https://pixabay.com/users/stux-12364/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=1072366">Stefan Schweihofer</a> from <a target="_blank" href="https://pixabay.com//?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=1072366">Pixabay</a></p>
</li>
<li><p>Image by <a target="_blank" href="https://pixabay.com/users/geralt-9301/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=2679755">Gerd Altmann</a> from <a target="_blank" href="https://pixabay.com//?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=2679755">Pixabay</a></p>
</li>
<li><p>Image by Rahul from <a target="_blank" href="https://pixahive.com/photo/drops-on-groot-character/">Pixahive</a></p>
</li>
<li><p>Image by <a target="_blank" href="https://pixabay.com/users/juergen_s-6938697/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=5420277">Jürgen Schmidtlein</a> from <a target="_blank" href="https://pixabay.com//?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=5420277">Pixabay</a></p>
</li>
<li><p>Image by <a target="_blank" href="https://pixabay.com/users/alexas_fotos-686414/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=1111448">Alexa</a> from <a target="_blank" href="https://pixabay.com//?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=1111448">Pixabay</a></p>
</li>
<li><p>Image by <a target="_blank" href="https://pixabay.com/users/ulleo-1834854/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=2328289">Leopictures</a> from <a target="_blank" href="https://pixabay.com//?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=2328289">Pixabay</a></p>
</li>
<li><p>Image by <a target="_blank" href="https://pixabay.com/users/422737-422737/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=445153">422737</a> from <a target="_blank" href="https://pixabay.com//?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=445153">Pixabay</a></p>
</li>
<li><p>Image by <a target="_blank" href="https://pixabay.com/users/marjonhorn-3698690/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=4393509">Marjon Besteman</a> from <a target="_blank" href="https://pixabay.com//?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=4393509">Pixabay</a></p>
</li>
<li><p>Image by <a target="_blank" href="https://pixabay.com/users/pexels-2286921/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=1846059">Pexels</a> from <a target="_blank" href="https://pixabay.com//?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=1846059">Pixabay</a></p>
</li>
<li><p>Image by <a target="_blank" href="https://pixabay.com/users/joshuaworoniecki-12734309/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=5089188">Joshua Woroniecki</a> from <a target="_blank" href="https://pixabay.com//?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=image&amp;utm_content=5089188">Pixabay</a></p>
</li>
<li><p><a target="_blank" href="https://xkcd.com/149/">https://xkcd.com/149/</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Design Patterns : Factory and Factory method]]></title><description><![CDATA[Let us dive into individual design patterns, starting with Factory design pattern and then Factory method design pattern. Both these are two most common design patterns used in real-time applications. As mentioned in the previous article – Design Pat...]]></description><link>https://artofcoding.dev/design-patterns-factory-and-factory-method</link><guid isPermaLink="true">https://artofcoding.dev/design-patterns-factory-and-factory-method</guid><category><![CDATA[design patterns]]></category><category><![CDATA[Factory Design Pattern]]></category><category><![CDATA[software architecture]]></category><category><![CDATA[patterns]]></category><category><![CDATA[factory]]></category><dc:creator><![CDATA[Febin Joy]]></dc:creator><pubDate>Sat, 14 Jan 2023 05:46:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1673674965169/85495c2c-67d2-4bee-acfc-3eb4f78e9e23.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Let us dive into individual design patterns, starting with Factory design pattern and then Factory method design pattern. Both these are two most common design patterns used in real-time applications. As mentioned in the previous article – Design <a target="_blank" href="https://artofcoding.dev/design-patterns-basics">Patterns – Basics (</a><a target="_blank" href="http://artofcoding.dev">artofcoding.dev</a><a target="_blank" href="https://artofcoding.dev/design-patterns-basics">)</a>, they fall under the category - Creational design patterns.</p>
<p>Even experienced engineers have a misconception that both these patterns are the same, and usually use both the names interchangeably. Let us explore further and find what they are, how they differ, when, where and how to use them.</p>
<h1 id="heading-factory-design-pattern">Factory design pattern</h1>
<p>What does a factory do? Creates something as per the requirements. That is precisely what a Factory design pattern also does. It tries to solve the fundamental problems in object instantiation by providing abstraction. Gang of Four (GoF) defines factory design pattern as -</p>
<blockquote>
<p>A factory is an object which is used for creating other objects.</p>
</blockquote>
<p>The implementation will have a factory class with a method which will return different types of objects based on it's input parameters. Here, the object creation logic is hidden from the client class which calls this method.</p>
<h2 id="heading-real-life-example">Real life example</h2>
<p>Let us assume that we are asked to develop an application to process data from Excel, Word, and PDF files after reading it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673620040358/53f07cbb-1f3a-45f2-96bb-9ce5900f73be.png" alt class="image--center mx-auto" /></p>
<p>Here, since all 3 are documents we process, we can have a document class and 3 different subclasses to represent each type of document, i.e. Word, Excel, and PDF.</p>
<p>The user will be providing the file path, and we need to identify the document type and process it accordingly.</p>
<h3 id="heading-without-any-pattern">Without any pattern</h3>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">FactoryPattern.Interfaces</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">interface</span> <span class="hljs-title">IDocument</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">OpenFile</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> filePath</span>)</span>;
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ProcessData</span>(<span class="hljs-params"></span>)</span>;
    }
}
</code></pre>
<p>We need to define an interface or an abstract class so that we can define all the properties and methods a document should have. I created an interface – ⁣<code>IDocument</code> with 2 methods – ⁣<code>OpenFile</code> and <code>ProcessData</code> declared.</p>
<p>Now we have to create 3 different classes for each document type.</p>
<p><strong>ExcelDocument.cs:</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> FactoryPattern.Interfaces;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">FactoryPattern.Classes</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ExcelDocument</span> : <span class="hljs-title">IDocument</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">OpenFile</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> filePath</span>)</span>
        {
            <span class="hljs-comment">// File read logic specific to Excel</span>
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ProcessData</span>(<span class="hljs-params"></span>)</span>
        {
            <span class="hljs-comment">// Data processing logic specific to Excel</span>
        }
    }
}
</code></pre>
<p><strong>WordDocument.cs:</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> FactoryPattern.Interfaces;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">FactoryPattern.Classes</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">WordDocument</span> : <span class="hljs-title">IDocument</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">OpenFile</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> filePath</span>)</span>
        {
            <span class="hljs-comment">// File read logic specific to Word</span>
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ProcessData</span>(<span class="hljs-params"></span>)</span>
        {
            <span class="hljs-comment">// Data processing logic specific to Word</span>
        }
    }
}
</code></pre>
<p><strong>PdfDocument.cs:</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> FactoryPattern.Interfaces;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">FactoryPattern.Classes</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">PdfDocument</span> : <span class="hljs-title">IDocument</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">OpenFile</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> filePath</span>)</span>
        {
            <span class="hljs-comment">// File read logic specific to Pdf</span>
        }

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ProcessData</span>(<span class="hljs-params"></span>)</span>
        {
            <span class="hljs-comment">// Data processing logic specific to Pdf</span>
        }
    }
}
</code></pre>
<p>You can see all 3 classes implements the interface – ⁣<code>IDocument</code> and have their specific implementation of methods – ⁣<code>OpenFile</code> and <code>ProcessData</code>.</p>
<p>Now let us create a class that tries to open these documents.</p>
<p><strong>Program.cs:</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">FactoryPattern</span>
{
    <span class="hljs-keyword">class</span> <span class="hljs-title">Program</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>)</span>
        {
            <span class="hljs-comment">// This should ideally come from the UI.</span>
            <span class="hljs-comment">// Hard coded to simulate</span>
            <span class="hljs-keyword">string</span> filePath = <span class="hljs-string">"c:/document_to_open.pdf"</span>;

            IDocument document = <span class="hljs-literal">null</span>;

            <span class="hljs-comment">// Create instance based on file extension</span>
            <span class="hljs-keyword">switch</span> (Path.GetExtension(filePath).ToLower())
            {
                <span class="hljs-keyword">case</span> <span class="hljs-string">".pdf"</span>:
                    document = <span class="hljs-keyword">new</span> PdfDocument();
                    <span class="hljs-keyword">break</span>;

                <span class="hljs-keyword">case</span> <span class="hljs-string">".doc"</span>:
                <span class="hljs-keyword">case</span> <span class="hljs-string">".docx"</span>:
                    document = <span class="hljs-keyword">new</span> WordDocument();
                    <span class="hljs-keyword">break</span>;

                <span class="hljs-keyword">case</span> <span class="hljs-string">".xls"</span>:
                <span class="hljs-keyword">case</span> <span class="hljs-string">".xlsx"</span>:
                    document = <span class="hljs-keyword">new</span> ExcelDocument();
                    <span class="hljs-keyword">break</span>;

                <span class="hljs-keyword">default</span>:
                    document = <span class="hljs-keyword">new</span> WordDocument();
                    <span class="hljs-keyword">break</span>;
            }

            document.OpenFile(filePath);
            document.ProcessData();
        }
    }
}
</code></pre>
<p>This works fine and achieves the requirements. By default, a Word document is created. We can throw an error if needed to specify – unknown file type.</p>
<p>When executed, it will open and process the file based on the file extension.</p>
<p>But this code posses certain drawbacks. Let us see what they are:</p>
<ul>
<li><p>The class <code>Program</code> is tightly coupled with <code>PdfDocument</code>, <code>ExcelDocument</code>, and <code>WordDocument</code>.</p>
</li>
<li><p>The code is difficult to test.</p>
</li>
<li><p>It is not scalable. If we need to add a new document type, we will have to modify the client code.</p>
</li>
</ul>
<p>Let us see how we can overcome these issues with Factory design pattern.</p>
<h3 id="heading-implementation-using-factory-design-pattern">Implementation using Factory design pattern</h3>
<p>With Factory design pattern, we will be shifting the responsibility of creating the document class objects from the <code>Program</code> class to a <code>Factory</code> class. This will hide the object creation logic from all the clients.</p>
<p><strong>DocumentFactory.cs:</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">using</span> FactoryPattern.Interfaces;

<span class="hljs-keyword">namespace</span> <span class="hljs-title">FactoryPattern.Classes</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">DocumentFactory</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">public</span> IDocument <span class="hljs-title">ReadDocument</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> filePath</span>)</span>
        {
            IDocument document = <span class="hljs-literal">null</span>;

            <span class="hljs-keyword">if</span> (<span class="hljs-keyword">string</span>.IsNullOrWhiteSpace(filePath))
                <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ArgumentNullException(<span class="hljs-keyword">nameof</span>(filePath));

            <span class="hljs-comment">// Other validations to check if the path exists.</span>

            <span class="hljs-keyword">switch</span> (Path.GetExtension(filePath).ToLower())
            {
                <span class="hljs-keyword">case</span> <span class="hljs-string">".pdf"</span>:
                    document = <span class="hljs-keyword">new</span> PdfDocument();
                    <span class="hljs-keyword">break</span>;

                <span class="hljs-keyword">case</span> <span class="hljs-string">".doc"</span>:
                <span class="hljs-keyword">case</span> <span class="hljs-string">".docx"</span>:
                    document = <span class="hljs-keyword">new</span> WordDocument();
                    <span class="hljs-keyword">break</span>;

                <span class="hljs-keyword">case</span> <span class="hljs-string">".xls"</span>:
                <span class="hljs-keyword">case</span> <span class="hljs-string">".xlsx"</span>:
                    document = <span class="hljs-keyword">new</span> ExcelDocument();
                    <span class="hljs-keyword">break</span>;

                <span class="hljs-keyword">default</span>:
                    document = <span class="hljs-keyword">new</span> WordDocument();
                    <span class="hljs-keyword">break</span>;
            }

            document.OpenFile(filePath);
            <span class="hljs-keyword">return</span> document;
        }
    }
}
</code></pre>
<p>We created a class <code>DocumentFactory</code> and added a method – ⁣<code>ReadDocument</code> to it, which takes the file path as a parameter.</p>
<p>Then, we can rewrite <code>Program.cs</code> as follows:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">FactoryPattern</span>
{
    <span class="hljs-keyword">class</span> <span class="hljs-title">Program</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>)</span>
        {
            <span class="hljs-comment">// This should ideally come from the UI.</span>
            <span class="hljs-comment">// Hard coded to simulate</span>
            <span class="hljs-keyword">string</span> filePath = <span class="hljs-string">"c:/document_to_open.pdf"</span>;

            <span class="hljs-keyword">var</span> documentFactory = <span class="hljs-keyword">new</span> DocumentFactory();

            IDocument document = documentFactory.ReadDocument(filePath);
            document.ProcessData();
        }
    }
}
</code></pre>
<p><code>DocumentFactory</code> takes the responsibility of creating the document, making the design more scalable in future.</p>
<p>This is now testable. We can create a Unit test project and use the following to test.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">namespace</span> <span class="hljs-title">FactoryPatternTests</span>
{
    [<span class="hljs-meta">TestFixture</span>]
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">DocumentFactoryTests</span>
    {
        [<span class="hljs-meta">TestCase(<span class="hljs-meta-string">""</span>)</span>]
        [<span class="hljs-meta">TestCase(<span class="hljs-meta-string">" "</span>)</span>]
        [<span class="hljs-meta">TestCase(null)</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ReadDocument_EmptyPath_ThrowsArgumentNullException</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> path</span>)</span>
        {
            <span class="hljs-comment">// Arrange</span>
            <span class="hljs-keyword">var</span> documentFactory = <span class="hljs-keyword">new</span> DocumentFactory();

            <span class="hljs-comment">// Act + Assert</span>
            Assert.Throws&lt;ArgumentNullException&gt;(() =&gt; documentFactory.ReadDocument(path));
        }

        [<span class="hljs-meta">TestCase(<span class="hljs-meta-string">"c:/document.pdf"</span>, typeof(PdfDocument))</span>]
        [<span class="hljs-meta">TestCase(<span class="hljs-meta-string">"c:/document.doc"</span>, typeof(WordDocument))</span>]
        [<span class="hljs-meta">TestCase(<span class="hljs-meta-string">"c:/document.docx"</span>, typeof(WordDocument))</span>]
        [<span class="hljs-meta">TestCase(<span class="hljs-meta-string">"c:/document.xls"</span>, typeof(ExcelDocument))</span>]
        [<span class="hljs-meta">TestCase(<span class="hljs-meta-string">"c:/document.xlsx"</span>, typeof(ExcelDocument))</span>]
        [<span class="hljs-meta">TestCase(<span class="hljs-meta-string">"c:/document.default"</span>, typeof(WordDocument))</span>]
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">ReadDocument_ValidPath_ReturnsExpectedDocument</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> path, Type expectedDocumentType</span>)</span>
        {
            <span class="hljs-comment">// Arrange</span>
            <span class="hljs-keyword">var</span> documentFactory = <span class="hljs-keyword">new</span> DocumentFactory();

            <span class="hljs-comment">// Act</span>
            <span class="hljs-keyword">var</span> document = documentFactory.ReadDocument(path);

            <span class="hljs-comment">// Assert</span>
            Assert.IsNotNull(document);
            Assert.IsInstanceOf(expectedDocumentType, document);
        }
    }
}
</code></pre>
<p>Method <code>ReadDocument_ValidPath_ReturnsExpectedDocument</code> ensures that we get the right <code>IDocument</code> object.</p>
<h2 id="heading-class-design">Class design</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673668739003/272f3c4b-0e4b-42c5-a0d8-c7f289239616.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-when-to-use-factory-design-pattern">When to use Factory design pattern</h2>
<p>Factory design pattern could usually be used when</p>
<ul>
<li><p>Objects have common functionality and can be extended to subclasses</p>
</li>
<li><p>Client need not be concerned with the exact subclass to be created.</p>
</li>
<li><p>Implementation classes are subject to change or if it requires allowing new implementations in future.</p>
</li>
</ul>
<h1 id="heading-factory-method-design-pattern">Factory method design pattern</h1>
<p>The key difference this pattern has with Factory design pattern is that it allows the subclass to decide which class is to be instantiated. To achieve this, an abstract class acts as the Factory class and return the instance of the document.</p>
<p>Let us see how this applies to our above example and solves the problem.</p>
<p>We have the interface – ⁣<code>IDocument</code> and 3 classes that implements the interface.</p>
<p>Then we will need to create the <code>DocumentFactory</code>. In Factory design pattern, this was a concrete class. Instead, we will create an abstract class in Factory method.</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> <span class="hljs-title">DocumentFactory</span>
    {
        <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">abstract</span> IDocument <span class="hljs-title">ReadDocument</span>(<span class="hljs-params"></span>)</span>;

        <span class="hljs-function"><span class="hljs-keyword">public</span> IDocument <span class="hljs-title">LoadDocument</span>(<span class="hljs-params"></span>)</span>
        {
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.ReadDocument();
        }
    }
</code></pre>
<p>The Factory contains an abstract method – ⁣<code>ReadDocument</code> and a concrete method – ⁣<code>LoadDocument</code>, which internally calls the <code>ReadDocument</code> method of the subclass. This subclass creates the document object and returns it. The responsibility of creating the document now lies on the implementations of <code>DocumentFactory</code>.</p>
<p>We will need to create 3 more classes here.</p>
<p><strong>ExcelDocumentFactory.cs:</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ExcelDocumentFactory</span> : <span class="hljs-title">DocumentFactory</span>
{
    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> IDocument <span class="hljs-title">ReadDocument</span>(<span class="hljs-params"></span>)</span>
    {
        IDocument document = <span class="hljs-keyword">new</span> ExcelDocument();
        <span class="hljs-keyword">return</span> document;
    }
}
</code></pre>
<p><strong>PdfDocumentFactory.cs:</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">PdfDocumentFactory</span> : <span class="hljs-title">DocumentFactory</span>
{
    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> IDocument <span class="hljs-title">ReadDocument</span>(<span class="hljs-params"></span>)</span>
    {
        IDocument document = <span class="hljs-keyword">new</span> PdfDocument();
        <span class="hljs-keyword">return</span> document;
    }
}
</code></pre>
<p><strong>WordDocumentFactory.cs:</strong></p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">WordDocumentFactory</span> : <span class="hljs-title">DocumentFactory</span>
{
    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">override</span> IDocument <span class="hljs-title">ReadDocument</span>(<span class="hljs-params"></span>)</span>
    {
        IDocument document = <span class="hljs-keyword">new</span> PdfDocument();
        <span class="hljs-keyword">return</span> document;
    }
}
</code></pre>
<p>We now have an abstract document factory class and 3 implementations for it, which returns the document object.</p>
<p>Now, the client code can create a document as follows:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Program</span>
{
    <span class="hljs-function"><span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Main</span>(<span class="hljs-params"><span class="hljs-keyword">string</span>[] args</span>)</span>
    {
        <span class="hljs-comment">// This should ideally come from the UI.</span>
        <span class="hljs-comment">// Hard coded to simulate</span>
        <span class="hljs-keyword">string</span> filePath = <span class="hljs-string">"c:/document_to_open.pdf"</span>;

        <span class="hljs-keyword">var</span> documentFactory = <span class="hljs-keyword">new</span> ExcelDocumentFactory();

        IDocument document = documentFactory.LoadDocument();
        document.OpenFile(filePath);
        document.ProcessData();
    }
}
</code></pre>
<p>At this point, you must be wondering – How we will decide which document factory to use. If we are not sure of which, It is recommended to use Factory Design pattern.</p>
<h2 id="heading-class-design-1">Class design</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673668770688/73e16d79-3dda-4216-b6c5-710568632d10.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-when-to-use-factory-method-design-pattern">When to use Factory method design pattern</h2>
<p>Factory method design pattern could usually be used for</p>
<ul>
<li><p>Objects have common functionality and can be extended to subclasses</p>
</li>
<li><p><strong>The client knows which subclass to create, but do not want to get hands dirty by actually creating the subclass object.</strong></p>
</li>
<li><p>Implementation classes are subject to change or if it requires allowing new implementations in future.</p>
</li>
</ul>
<p>Another real life situation where you need to use factory method pattern would be as follows:</p>
<p>The requirement is to create 3 forms to gather information from employees. The first one is to gather their personal data, second one to gather their experience details and the third one to enter their bank details.</p>
<p>We need to have a common base class – ⁣<code>IForm</code>, and 3 implementations – ⁣<code>PersonalForm</code>, <code>ExperienceForm</code>, and <code>FinanceForm</code>. Also create an abstract class - <code>FormFactory</code> and its implementations – ⁣<code>PersonalFormFactory</code>, <code>ExperienceFormFactory</code>, and <code>FinanceFormFactory</code>.</p>
<p>In the application, whenever we have to gather finance information, we can use the <code>FinanceFormFactory</code>.</p>
<p>I hope this article helps you in some way to understand Factory pattern and Factory method pattern. Your support and love in the form of comments and feedback are highly appreciated. Please don't hesitate to ask questions if any. Thanks.</p>
<h1 id="heading-appendix"><strong>Appendix</strong></h1>
<p>The source code used in this article could be found here - <a target="_blank" href="https://github.com/artofcoding-dev/design-patterns/tree/master/Creational/FactoryPattern">Design-patterns/Creational/FactoryPattern : github</a></p>
<h3 id="heading-shout-outs-and-courtesy-notes"><strong>Shout-outs and courtesy notes</strong></h3>
<p><a target="_blank" href="https://www.freepik.com/free-vector/people-working-factory-landing-pages_6163215.htm#query=factory&amp;position=38&amp;from_view=search&amp;track=sph">Image by pch.vector</a> on Freepik</p>
]]></content:encoded></item><item><title><![CDATA[Design Patterns – Basics]]></title><description><![CDATA[What to expect from this series?

Whether you are a newbie or an experienced programmer, you might have come across the term – “Software Design Patterns” many times in your career and would be actively using them knowingly or unknowingly in your code...]]></description><link>https://artofcoding.dev/design-patterns-basics</link><guid isPermaLink="true">https://artofcoding.dev/design-patterns-basics</guid><category><![CDATA[design patterns]]></category><category><![CDATA[software architecture]]></category><category><![CDATA[design and architecture]]></category><category><![CDATA[software development]]></category><category><![CDATA[patterns]]></category><dc:creator><![CDATA[Febin Joy]]></dc:creator><pubDate>Sat, 07 Jan 2023 13:06:43 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1673072243716/68edea86-e1ba-4a7a-bbb9-4b1a275ea825.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-what-to-expect-from-this-series">What to expect from this series?</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673056275983/56694746-7a28-4279-9d0d-0b6d9dfac378.png" alt class="image--center mx-auto" /></p>
<p>Whether you are a newbie or an experienced programmer, you might have come across the term – “Software Design Patterns” many times in your career and would be actively using them knowingly or unknowingly in your code.</p>
<p>What are design patterns? How does it help a developer? How do we implement them? Well, this series here – <a target="_blank" href="https://artofcoding.dev/series/design-patterns">Design patterns simplified</a> aims at answering these questions along with explaining various design patterns with code samples and practical scenarios on when to use which pattern.</p>
<p>I will keep this series as simple as possible for the beginners and concise enough for the ace programmers out there. I am not venturing to explain the basic object-oriented concepts further. However, knowing them would help you understand this series much better.</p>
<p>All the code samples throughout this series will be added (As each new part is added to the series) here -<a target="_blank" href="https://github.com/artofcoding-dev/design-patterns">https://github.com/artofcoding-dev/design-patterns</a>. They are written in C#, but I hope programmers in any other language would be able to understand them and use the concepts.</p>
<h1 id="heading-what-are-software-design-patterns">What are Software Design Patterns?</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673057142726/4a642e3d-7d7c-45d3-972b-1b161f213148.png" alt class="image--center mx-auto" /></p>
<p>Ever got stuck thinking about how to solve a problem effectively while writing code? If your answer is “Yes”, then please realise that you are not the first person who faced the same kind of problem. Those who have faced them earlier, have already solved it for you. All you need to do is reuse them instead of trying to reinvent the wheel.</p>
<p>Design patterns could be considered as a general purpose abstraction of a problem. In simple words, they are general, reusable, tested solutions for specific recurring problems a developer faces in their day to day programming. When I mention solution, it is not a code snippet which is ready for reuse or copy-paste. Instead, it provides a framework or template for achieving your requirements in the best possible way. Similar to how a recipe helps you cook a dish, it helps you with the measures, approaches, and ingredients to come up with a better software.</p>
<h1 id="heading-how-does-it-help-a-developer">How does it help a developer?</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673088234028/49bb72f6-1290-4e12-bbea-af64afcb1a8a.png" alt class="image--center mx-auto" /></p>
<p>Here are some of the advantages developers could have by using design patterns.</p>
<h2 id="heading-improves-code-quality">Improves code quality</h2>
<p>Understanding design patterns will provide you with the required insights that would help you design a robust, flexible, scalable, loosely coupled, modular and reusable software.</p>
<p>Along with the obvious advantage of having a proven solution, it is also helpful in maintaining your code relatively clean, and resourceful in improving the quality of your documentation.</p>
<p>But also keep in mind that a good design is not the only ingredient of a good software. However good the design is, the quality of a software greatly depends on how the design is implemented as well. Having a good design will equip you in solving countless issues that may come up during the course of development, and a poor implementation can spoil the soup.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673091518137/03851783-0ef8-407c-b6e7-90a8c3c2e546.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-reduces-risk">Reduces Risk</h2>
<p>Since the patterns are tried, tested and improved by developers over time, it reduces the element of risk and effort required in testing.</p>
<h2 id="heading-ease-of-communication-and-documentation">Ease of communication and documentation</h2>
<p>Design patterns are language neutral and could be applied to any object-oriented programming language. This makes things easy for developers to communicate efficiently, ensuring everyone is on the same page and helps them to visualise the design in their mind.</p>
<h2 id="heading-impact-on-productivity">Impact on productivity</h2>
<p>Using design patterns reduces the time spent on maintaining the code and provides better consistency. Even though they have a positive impact on the development timeline, don't expect a drastic reduction on your initial development timelines. Figuring out the optimum design usually consumes time as it is required to account for the time needed to analyse the requirements, finalising the right tools and training the team if needed. But it will be beneficial in the long run, when you need to introduce changes to it or add to it later.</p>
<h1 id="heading-how-to-find-the-right-design-patterns">How to find the right design patterns?</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673057848064/91ea2383-d081-4043-947e-d4dd12e5ddea.png" alt class="image--center mx-auto" /></p>
<p>There are plenty of design patterns available, and choosing the appropriate one would be a tough call to make initially. Remember, the key here is your requirements. You are trying to solve your problems with design patterns, and not the other way around. It should specifically address your requirements and, at the same time, maintain a general openness to account for future problems. It is quite natural for us to stick to the methods familiar to us for solving problems. Every so often, it may not be the optimal solution. What experienced programmers and designers do is not to prematurely solve the problems without giving it enough thought. Furthermore, it takes a lot of patience and practice, mastering the art of designing good software.</p>
<p>Example: If the problem is to cross a river. The following could be considered the solutions:</p>
<ul>
<li><p>Swimming across the river</p>
</li>
<li><p>Using a boat</p>
</li>
<li><p>Constructing a bridge across a river</p>
</li>
</ul>
<p>All these solve the same problem. Swimming would solve it for one person, a boat would solve it for a few people at the same time, and a bridge would solve the issue for everyone. Considering the risks involved and other factors, a bridge would seem to be the ideal solution. But it would take longer to build and would cost more to implement. This would restrict people from travelling until the construction is completed. So here, the optimum solution would not be just to build the bridge. Instead, it will be a hybrid solution that involves constructing a bridge and using a boat until the bridge is constructed.</p>
<p>Blindly following a pattern would not be the best thing under certain situations. As developers, our primary focus should always be on the “<strong><em>WHAT</em></strong>” part instead of the <strong><em>“HOW”</em></strong> part of the problem. It enables us to solve the issues efficiently. In the example above, the focus should be on facilitating the travel rather than building the bridge (i.e. Implementing the pattern) which will lead us to the hybrid approach.</p>
<p>Another word of caution for the developers would be to avoid the overuse of design patterns. It is always good to remember YAGNI principle(<a target="_blank" href="https://artofcoding.dev/14-principles-every-developer-should-know#heading-7-you-arent-gonna-need-it-yagni">https://artofcoding.dev/14-principles-every-developer-should-know#heading-7-you-arent-gonna-need-it-yagni</a>) and find the right balance.</p>
<h1 id="heading-typescategories-of-design-patterns">Types/Categories of Design Patterns</h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673058310212/ef92320c-c23c-4ce0-b057-3ac40a808761.png" alt class="image--center mx-auto" /></p>
<p>Design patterns could be broadly classified under 3 categories based on their purpose:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673092594521/c0d541f7-4725-4071-b884-16f9d5077dac.jpeg" alt class="image--center mx-auto" /></p>
<h2 id="heading-behavioral-patterns">Behavioral patterns</h2>
<p>These patterns focus more on the effective communication and interaction between various components and objects and the assignment of responsibilities.</p>
<p>Example: Consider a restaurant where there is a chef, a waiter, and clients. The responsibility of the chef is to cook, the waiter takes and executes the orders and clients places orders and makes payment. The client and the chef need not see or communicate directly. But there in an indirect, effective communication happening through the waiter.</p>
<p>Few of the prominent behavioral patterns are:</p>
<ul>
<li><p>Iterator pattern</p>
</li>
<li><p>Observer pattern</p>
</li>
<li><p>Chain of responsibility pattern</p>
</li>
<li><p>Command pattern</p>
</li>
<li><p>Visitor pattern</p>
</li>
<li><p>Strategy pattern</p>
</li>
<li><p>Interpreter pattern</p>
</li>
<li><p>Mediator pattern</p>
</li>
</ul>
<h2 id="heading-structural-patterns">Structural patterns</h2>
<p>Structural design patterns focus more on the template for defining the structure and components of a class. It helps the programmers to organise the classes and objects and helps in ensuring efficiency and flexibility of the component/software.</p>
<p>Some popular structural patterns are:</p>
<ul>
<li><p>Adapter pattern</p>
</li>
<li><p>Facade</p>
</li>
<li><p>Decorator</p>
</li>
<li><p>Proxy</p>
</li>
</ul>
<h2 id="heading-creational-patterns">Creational patterns</h2>
<p>Creational design patterns focus more on object creation and initialisation. It empowers the developer in deciding which object is to be created in a specified scenario.</p>
<p>Example: A developer wants to log errors in the application, and decides to use a single logger instance.</p>
<p>Well known creational design patterns are:</p>
<ul>
<li><p>Abstract Factory Patterns</p>
</li>
<li><p>Builder Pattern</p>
</li>
<li><p>Factory Method Pattern</p>
</li>
<li><p>Prototype Pattern</p>
</li>
<li><p>Singleton Pattern</p>
</li>
</ul>
<p>There are more design patterns in these categories. We can dig more of them in the upcoming articles. Your support and love in the form of comments and feedback are highly appreciated. Thanks.</p>
<h1 id="heading-appendix"><strong>Appendix</strong></h1>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1673081312914/8b82c233-7173-48a3-aafe-66fe956a59f7.png" alt class="image--center mx-auto" /></p>
<p>It would be a crime if I don't mention a book – “<strong>Design Patterns: Elements of Reusable Object-Oriented Software</strong>” written by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides in 1994, which could be considered “The Bible” of Design Patterns. If I am asked to pick only one book on software architecture and design, it would be this book. The authors of this book are often referred to as Gang of Four(GoF). If you are into C++ or love to go deeper, I highly recommend this book; not just as a one-time read, but as a reference material as well.</p>
<h3 id="heading-shout-outs-and-courtesy-notes"><strong>Shout-outs and courtesy notes</strong></h3>
<p>A big shout-out to the following photographers for their pictures which I could use from Unsplash and for <a target="_blank" href="https://miro.com/">https://miro.com/</a> for helping me draw the diagrams.</p>
<p>Photo by <a target="_blank" href="https://unsplash.com/@dronepilot?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Anita Denunzio</a> on <a target="_blank" href="https://unsplash.com/photos/AMIiKN-4oVE?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a><br />Photo by <a target="_blank" href="https://unsplash.com/@rhyskentish?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Rhys Kentish</a> on <a target="_blank" href="https://unsplash.com/photos/TFgLjR9TAEM?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a><br />Photo by <a target="_blank" href="https://unsplash.com/@a_kehmeier?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Austin Kehmeier</a> on <a target="_blank" href="https://unsplash.com/photos/lyiKExA4zQA?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a><br />Photo by <a target="_blank" href="https://unsplash.com/@mattwridley?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Matt Ridley</a> on <a target="_blank" href="https://unsplash.com/photos/Lyl8RL7imrw?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a><br />Photo by <a target="_blank" href="https://unsplash.com/@nate_dumlao?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Nathan Dumlao</a> on <a target="_blank" href="https://unsplash.com/photos/pMW4jzELQCw?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a><br />Photo by <a target="_blank" href="https://unsplash.com/@sharonmccutcheon?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Alexander Grey</a> on <a target="_blank" href="https://unsplash.com/photos/tn57JI3CewI?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a><br />Photo by <a target="_blank" href="https://unsplash.com/@enisyavuz?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Enis Yavuz</a> on <a target="_blank" href="https://unsplash.com/photos/tuuh4DrgMpU?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a><br />Photo by <a target="_blank" href="https://unsplash.com/@tarikul_islam?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Shardar Tarikul Islam</a> on <a target="_blank" href="https://unsplash.com/photos/G1lNoSED98A?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a><a target="_blank" href="https://unsplash.com/@mattwridley">  
</a></p>
<p><a target="_blank" href="https://unsplash.com/@rhyskentish">  
</a></p>
]]></content:encoded></item><item><title><![CDATA[14 Principles every developer should know]]></title><description><![CDATA[Introduction
As a developer, our primary objective is to develop software solutions that address a set of specific requirements (Fit for purpose). We achieve this by defining the architecture and finally implementing it by writing code. I believe the...]]></description><link>https://artofcoding.dev/14-principles-every-developer-should-know</link><guid isPermaLink="true">https://artofcoding.dev/14-principles-every-developer-should-know</guid><category><![CDATA[software-principles]]></category><category><![CDATA[Software Engineering]]></category><category><![CDATA[Programming Tips]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[principles]]></category><dc:creator><![CDATA[Febin Joy]]></dc:creator><pubDate>Wed, 28 Dec 2022 15:52:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1672238589031/9b186efa-d2d7-417c-aa65-22f1cbe987c9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h1 id="heading-introduction">Introduction</h1>
<p>As a developer, our primary objective is to develop software solutions that address a set of specific requirements (Fit for purpose). We achieve this by defining the architecture and finally implementing it by writing code. I believe there is more to it than just writing code. The way the code is written is equally important as what is written. Any source code should possess the following qualities for it to be considered a good code.</p>
<ul>
<li><p>Readable</p>
</li>
<li><p>Efficient</p>
</li>
<li><p>Concise</p>
</li>
<li><p>Reusable</p>
</li>
<li><p>Scalable</p>
</li>
<li><p>Well-designed</p>
</li>
<li><p>Well-commented and documented and</p>
</li>
<li><p>Tested</p>
</li>
</ul>
<h1 id="heading-principles">Principles</h1>
<p>Following 14 principles would help to achieve the above qualities easily.</p>
<h2 id="heading-1-draw-before-you-code">1. Draw Before You Code</h2>
<p>It is always good to have the design ready before you start writing code. Irrespective of whether you are developing a small component of a huge project, it helps in:</p>
<ul>
<li><p>Identifying the gaps/issues in the requirements</p>
</li>
<li><p>Helps to avoid issues during implementation.</p>
</li>
<li><p>Making the application's components scalable, which in turn allows accommodating requirement changes that may come up later in the project life cycle.</p>
</li>
<li><p>Dividing the requirements into smaller chunks and prioritising them.</p>
</li>
</ul>
<p>UML diagrams like a <code>Component diagram</code>, <code>Object diagram</code>, <code>Class diagram</code>, <code>Sequence diagrams,</code> etc. could be used for these as required.</p>
<p>There are a few approaches for this based on various factors.</p>
<h3 id="heading-big-design-up-front-bduf">Big Design Up Front (BDUF)</h3>
<p>If you know the requirements upfront and if you are not expecting massive deviations from them, the <strong>BDUF</strong> approach would be a perfect fit for you. The software design is completed in advance, considering current requirements and the room for scaling in the future.</p>
<p>Example: You are asked to develop a login module for a web application. Right now, the requirement is to use the ASP.NET membership provider. A well-designed solution could accommodate Single Sign On easily at a later stage if the customer decides to switch.</p>
<p>There are certain caveats for BDUF.</p>
<ul>
<li><p>If you are not sure of the requirements, and its scope, the design is more likely to be flawed. Don't go too deep with the design in that case.</p>
</li>
<li><p>Design revisions will be harder and more expensive once the code is written.</p>
</li>
</ul>
<h3 id="heading-agile-and-emergent-design">Agile and Emergent Design</h3>
<p>If you follow methodologies like Agile, requirements are bound to change frequently. Sometimes, you may not be having clear visibility of the road map as they evolve. Having an emergent design is preferred over having a concrete design. It emphasises having the design emerge as we get more clear of the requirements.</p>
<p>Still, it is good to draw your classes, the relations between them, how they are interconnected, etc. It helps you to think better on paper.</p>
<h3 id="heading-just-enough-design-up-front-jeduf">Just Enough Design Up Front (JEDUF)</h3>
<p>This approach tries to hit the balance of both <strong>BDUF</strong> and <strong>Emergent</strong> design by defining the foundation design upfront based on which, you could build later on. The upfront design will only take into consideration the fundamental aspects of the requirements. This helps to identify core risks at the start itself, leaving enough flexibility to account for unknowns later.</p>
<p>Another notable approach that could be mentioned here is <strong>Adaptable Design Up Front (ADUF)</strong>. It becomes relevant when there is an ambiguity on how much is “Just Enough”.</p>
<blockquote>
<p>Various architects and developers may have differences of opinion about the approaches listed above. It is not a one-size fits all solution and is highly debated. Whatever approach you take, it is always good to have your design upfront before you write the code. It helps to make your code - efficient, concise, reusable, scalable, and well-designed.</p>
</blockquote>
<h2 id="heading-2-measure-twice-and-cut-once">2. Measure Twice and Cut Once</h2>
<p>This principle is an extension of the first principle – <strong>Draw Before You Code</strong>. Ensure all the project requirements are considered in framing the design to avoid surprises later. It helps in having predictable outcomes. It also helps in a more accurate estimation of timelines.</p>
<h2 id="heading-3-result-oriented-approach">3. Result-Oriented approach</h2>
<p>Defining what you are trying to achieve and all the edge cases in advance help to ensure that the code you wrote does what it says on the tin. This could be achieved by defining all the test cases in advance and, planning unit tests. This will prepare you to handle all the scenarios that need to be taken care of during development. If you don't have the outcomes prepared in advance, it is easy to miss some edge cases, resulting in a bug.</p>
<p>Example: If you are asked to develop a method that takes 2 date time objects and returns the time difference between them; While writing the code, it is easy to miss an edge case – the first date time is greater than the second one, or one of them is null.</p>
<h2 id="heading-4-occams-razor">4. Occam's Razor</h2>
<p>Occam's razor or the principle of parsimony is a problem-solving principle put forward by William Occam in the 14th century. It states that – <em>“Entities should not be multiplied beyond necessity”.</em> When presented with multiple competing hypotheses, one should select the solution with the fewest assumptions. It favours simplicity over complexity. This aligns with what Albert Einstein said – “<em>Everything should be made as simple as possible, but not simpler</em>.”</p>
<p>When applied to software development, this advocates lean software development, encouraging developers to start with the most straightforward possible code. It reduces the chances of having bugs and allows developers to easily design, develop, test, and fix bugs at each step.</p>
<p>This principle is more relevant in selecting an appropriate model for machine learning problems.</p>
<p>Reference: <a target="_blank" href="https://en.wikipedia.org/wiki/Occam%27s_razor">Occam's razor - Wikipedia</a></p>
<h2 id="heading-5-dont-reinvent-the-wheel">5. Don't reinvent the wheel</h2>
<p>For some reason, many of us developers tend to write code to solve problems that someone else might have already fixed. This might be because:</p>
<ul>
<li><p>We are not aware of its existence.</p>
</li>
<li><p>We are not ready to get out of our comfort zone and try something new.</p>
</li>
<li><p>Furthermore, we assume it to be way more complex than it is.</p>
</li>
</ul>
<p>Try to find if there are libraries or NuGet packages that could solve your problem. Even if you spend a couple of hours researching, it would still be better than writing it from the scratch, as the amount of time and effort required to perfect it could be utilised fruitfully.</p>
<p>Making use of design patterns (More about this in future posts) and existing application frameworks also helps to avoid trying to solve the problems already solved by others.</p>
<p>Example: If you want to work with JSON objects in a .Net project, use NewtonSoft JSON library or JSON.Net instead of trying to write your implementation of parsing JSON.</p>
<h2 id="heading-6-keep-it-simple-stupid-kiss">6. Keep it Simple, Stupid (KISS)</h2>
<p>This principle is as simple as its name suggests. Make your code as easy and simple to understand as possible. It not only makes it easy for other developers to follow but also helps to break down complex problems into smaller chunks.<br />Few inputs:</p>
<ul>
<li><p>Ensure to use meaningful variable names describing what they are used for.</p>
</li>
<li><p>Ensure that your method names reflect the purpose of that method</p>
</li>
<li><p>Provide adequate comments</p>
</li>
<li><p>Ensure your methods do not exceed 50-100 lines of code.</p>
<ul>
<li>If it does, you can simplify it by splitting it.</li>
</ul>
</li>
<li><p>Ensure each method solves only one problem or does only one job.</p>
</li>
<li><p>If your method is flooded with conditions, consider refactoring.</p>
</li>
<li><p>Do not keep redundant code. Delete it.</p>
</li>
</ul>
<h2 id="heading-7-you-arent-gonna-need-it-yagni">7. You Aren't Gonna Need It (YAGNI)</h2>
<p>This principle states that a developer should not add functionality until deemed necessary. It is quite common for developers to think about future possibilities and add some code or logic to address them; which is not required at the moment. The software can become larger and more complex if developers add code for future use. This could end up as bloated code, making the software difficult to maintain. Avoid this mistake and keep your code clean of clutter.</p>
<h2 id="heading-8-dont-repeat-yourself-dry">8. Don't Repeat Yourself (DRY)</h2>
<p>Andy Hunt and Dave Thomas in their book <strong>The Pragmatic Programmer</strong> defined DRY as :</p>
<blockquote>
<p><em>Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.</em></p>
</blockquote>
<p>This principle is self-explanatory from its name and aims at preventing duplication of code, logic, or data. A piece of code should only be implemented once, instead of written several times wherever it is required. It helps to save time, reduce complexity, and reduces the chance of bugs.</p>
<p>Example: Creating helper classes, common services, or libraries for sharing between multiple classes or projects.</p>
<h2 id="heading-9-separation-of-concerns-soc">9. Separation of Concerns (SoC)</h2>
<p>This principle aims to separate software into distinct sections, where each section addresses a concern. Each section should be independent of the other, which makes it easy to maintain.</p>
<p>Ideally, a component, a layer, a package, a class, or a method should have only one concern and implement it.</p>
<p>Example: A typical example of SoC is how we organise microservices in a Microservices architecture. Each microservice addresses one concern.</p>
<p>Another example of SoC is the MVC pattern where the Model (the data), View (the UI), and Controller (the logic) are divided into 3 separate sections.</p>
<h2 id="heading-10-avoid-premature-optimisation">10. Avoid Premature Optimisation</h2>
<p>As developers, we are often tempted to optimise our code to make it simple and effective, which speeds up development. However, if done too early, it could produce adverse results. Optimising before knowing the complexities and bottlenecks of the program would result in wasted effort and eventually rewriting that code. Try to avoid this mistake.</p>
<h2 id="heading-11-principle-of-least-astonishment-pola">11. Principle of Least Astonishment (POLA)</h2>
<p>This principle says that it is recommended to design a feature that doesn't have a high astonishment factor. End users prefer to have obvious, predictable, and consistent outcomes when using the software. Otherwise, they will drift away from using the features that surprise/confuse them every time.</p>
<p>This principle also aims to leverage users' existing knowledge to reduce their learning curve.</p>
<p>Example: <code>Ctrl + X</code> is a commonly used shortcut for performing a Cut operation. A developer maps that shortcut to some other operation by default.</p>
<h2 id="heading-12-law-of-demeter-lod">12. Law of Demeter (LoD)</h2>
<p>This principle is also known as the principle of least knowledge. It aims at achieving loose coupling between components.</p>
<p>As per the guideline proposed by Ian Holland, it can be summarised as follows:</p>
<ul>
<li><p>Each unit should have only limited knowledge about other units: only units "closely" related to the current unit.</p>
</li>
<li><p>Each unit should only talk to its friends; don't talk to strangers.</p>
</li>
<li><p>Only talk to your immediate friends.</p>
</li>
</ul>
<p>It makes writing, refactoring and testing code much easier.</p>
<h2 id="heading-13-never-go-at-it-alone">13. Never Go At It Alone</h2>
<p>If you are working on a module or software project all by yourself, it is quite possible to make mistakes and miss things in the flow. Getting a fresh set of eyes to review your design and code always helps in maintaining a healthy code base. Moreover, it could be challenging for a single person to adhere to the best practices and write effective code.</p>
<p>Using pair programming, collaborating with other developers, and effective code reviews exponentially improve the quality of the code.</p>
<h2 id="heading-14-solid">14. SOLID</h2>
<p>SOLID is an acronym that represents 5 core principles of software development.</p>
<ul>
<li><p>Single Responsibility</p>
</li>
<li><p>Open-closed</p>
</li>
<li><p>Liskov substitution</p>
</li>
<li><p>Interface Segregation</p>
</li>
<li><p>Dependency inversion</p>
</li>
</ul>
<p>This itself is worth an individual article and I am not venturing further to explain it here. Those who are interested can refer to the following:</p>
<ul>
<li><p><a target="_blank" href="https://www.pentalog.com/blog/it-development-technology/solid-principles-object-oriented-programming/">SOLID Principles in Object Oriented Programming (</a><a target="_blank" href="http://pentalog.com">pentalog.com</a><a target="_blank" href="https://www.pentalog.com/blog/it-development-technology/solid-principles-object-oriented-programming/">)</a></p>
</li>
<li><p><a target="_blank" href="https://www.digitalocean.com/community/conceptual-articles/s-o-l-i-d-the-first-five-principles-of-object-oriented-design">SOLID: The First 5 Principles of Object-Oriented Design | DigitalOcean</a></p>
</li>
<li><p><a target="_blank" href="https://www.freecodecamp.org/news/solid-principles-for-programming-and-software-design/">SOLID Principles for Programming and Software Design (</a><a target="_blank" href="http://freecodecamp.org">freecodecamp.org</a><a target="_blank" href="https://www.freecodecamp.org/news/solid-principles-for-programming-and-software-design/">)</a></p>
</li>
</ul>
<h1 id="heading-conclusion">Conclusion</h1>
<p>A special thanks to all those who read this article thus far. I am quite sure I comfortably ignored some of the above principles while writing this article (Especially KISS; making it complex and a larger read). But at least I have the excuse of not writing code. ;)</p>
<p>I hope this article was beneficial to you in some way. This being a vast topic, have its limitations in including all the required information. If you felt you need more clarity somewhere, please point it out. I will try to include as much as possible. There may include areas where some programmers/architects disagree with certain points/aspects mentioned above. Feel free to express your views and feedback. Thanks again!</p>
<p>Cover photo by <a target="_blank" href="https://unsplash.com/es/@jessysmith?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Jessy Smith</a> on <a target="_blank" href="https://unsplash.com/photos/zFOm6KzA-7g?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></p>
]]></content:encoded></item></channel></rss>